npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@nice-code/devtools

v0.67.0

Published

One-call devtools for nice-code — actions, state, realms, wire traffic and a live topology, from the browser, your server, and your Durable Objects.

Downloads

2,324

Readme

@nice-code/devtools

For standalone windows and deployed-session lifecycle management, use @nice-code/devtools-cli. The Vite plugin remains the zero-config path while developing an app locally.

Docs: nicecode.io — guides, integrations, and the full API surface. Working with an AI assistant? Point it at nicecode.io/llms-devtools.txt (the devtools suite) or nicecode.io/llms.txt (the whole stack) — the complete, current docs flattened into plain text.

Devtools for nice-code — actions, state, realms, wire traffic, and a live topology of your frontends and backends — in a standalone window, from one function call per runtime:

| Entry point | For | Call | | --- | --- | --- | | @nice-code/devtools | your web app | createNiceDevtools() | | @nice-code/devtools/server | a long-lived server (Bun, Node, …) | createNiceServerDevtools() | | @nice-code/devtools/server | a Cloudflare Durable Object | createNiceDurableObjectDevtools() | | @nice-code/devtools/window | the window page (the Vite plugin serves it for you) | mountDevtoolsWindow() | | @nice-code/devtools/remote | a deployed staging frontend joining a relay session — the import is the production strip | enableRemoteDevtoolsSession() |

All three producers derive their devtools identity — label, clientId, coordEnvId — from the RuntimeCoordinate you already hand them. There is nothing to restate.

Full guide: nicecode.io/devtools/window · nicecode.io/devtools/backends

Install

bun add @nice-code/devtools
bun add -d @nice-code/devtools-vite

@nice-code/action, @nice-code/realm and @nice-code/state are peer dependencies — the window renders a panel for each. React is an optional peer: the ./server entry is React-free and runs unchanged in Node, Bun and workerd.

Setup

Add the Vite plugin. It serves the devtools window page and runs the relay:

import { niceDevtools } from "@nice-code/devtools-vite";

export default defineConfig({ plugins: [react(), niceDevtools()] });

Wire the app in one place:

import { createNiceDevtools } from "@nice-code/devtools";

export const devtools = createNiceDevtools({
  topologyId: "my-app",   // names the devtools topology this app belongs to
  runtime: getRuntime,    // an ActionRuntime, or a getter for one
  domains: [act_root],    // the ROOT action domains to observe
  stores: { UserStore },  // the stores the State panel lists
});

Hand its three seams to the code that produces the data:

connectChannel(runtime, channel, { wireTap: devtools.wireTap });  // per connection
connectRealm(gameRealm, { devtools: devtools.realm("game") });     // per realm
<devtools.LauncherButton />                                         // once, anywhere

That is all of it. There is no devtools.html to commit, no window entry module, no second rollupOptions.input.

What it costs

In production, nothing. enabled is false, no core is constructed, wireTap and realm() return undefined, and the launcher renders null. Handing connectRealm and connectChannel an absent tap is what makes them skip the observation work rather than measure frames into a sink. (A staging flavor build opts back in explicitly — enabled: true behind a build flag; see "Deployed staging" below.)

In development, nothing until a window attaches. The bridge subscribes to no scope while nobody is listening. That matters more than it sounds: a realm's projected view is a structured clone per patch tick, and paying for it with no reader is exactly the cost this design refuses.

Beyond the one call

  • devtools.internals — the live cores and bridge host, for pausing a core or contributing a scope.
  • useDevtoolsWindowAttached() / useDevtoolsClientIdentity() — React hooks for reflecting the window's presence in your own UI.
  • @nice-code/devtools/windowmountDevtoolsWindow(), if you host the window page yourself (a non-Vite dev server). Point the app at it with windowUrl.
  • startAppDevtoolsBridge() — the seam createNiceDevtools is built on.

Observing backends

A long-lived server

It dials the relay itself. One call, the mirror of the frontend's:

import { createNiceServerDevtools } from "@nice-code/devtools/server";

export const devtools = createNiceServerDevtools({
  topologyId: DEVTOOLS_TOPOLOGY,   // the same id your frontend passes; share the constant
  runtime,                         // label, clientId and coordEnvId all derived from it
  realms: { match: engine },
  domains: [act_root],
});

serveChannel(runtime, channel, { storage, carriers, wireTap: devtools.wireTap });

Pass topologyId: ["web-app", "admin-app"] when one backend serves several apps: it joins both relay rooms and appears in both devtools windows, while the two apps' frontends stay invisible to each other.

A Cloudflare Durable Object

A DO cannot dial out — an outbound socket pins it awake — so the window dials in: a plain wire connection to the DO's ordinary WebSocket endpoint (the same one its clients use), where devtools rides the wire mux as its own token-gated protocol. No separate dev route.

import { createNiceDurableObjectDevtools } from "@nice-code/devtools/server";

const devtools = createNiceDurableObjectDevtools(ctx, {
  runtime,
  stage: env.DEVTOOLS_ENV ?? "development", // required; "production" disables everything
  token: env.DEVTOOLS_TOKEN,        // unset ⇒ inert. No token, no protocol, no bridge, no cost.
  realms: { match: () => this.engine },
  persistCounters: true,
});

this.server = serveDurableObject(ctx, channel, { runtime, devtools });

Point the window at the DO's endpoint from the dev server, which is the only place that can hold the token without publishing it — never as a VITE_ var:

niceDevtools({
  backends: [{ url: "ws://localhost:8787/match/ws", token: env.DEVTOOLS_DO_TOKEN }],
});

See nicecode.io/devtools/backends.

Deployed staging (never production)

The same window reaches staging/dev deployments, triple-gated and fail-closed:

  • Dial into a deployed backend — the window's ⧉ backend control takes a wss:// URL + the token from your deploy config (a wrangler secret; no token ⇒ the DO serves no devtools at all). Guide: nicecode.io/devtools/remote-backends.
  • Stream a deployed frontend — producers dial out to a short-lived, token-authenticated relay session (@nice-code/devtools-relay/cloudflare is the deployable relay). The dial code lives behind @nice-code/devtools/remote, so a production bundle that never imports it contains none of it; a staging build opts its bridge in with enabled: true and streams shape, not values (streamContents: false). Guide: nicecode.io/devtools/remote-sessions.

Production cannot participate by construction: the remote entry is absent from a production bundle, production configs carry no credentials, and both the relay and every host refuse env: "production" at runtime.