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

@kubb/studio

v5.16.1

Published

Kubb Studio client runtime. Connects a Kubb project to Kubb Studio over one WebSocket and publishes CI snapshots, shared by the `kubb studio` CLI command and the Docker agent.

Readme

npm version npm downloads Stars License Node

@kubb/studio

Kubb Studio client runtime.

Connects a Kubb project to Kubb Studio through typed Cap'n Web RPC over one authenticated WebSocket, and publishes snapshots from CI in one HTTP request. It backs the kubb studio CLI command and the kubblabs/kubb-agent Docker image.

Most people never install this directly. Reach for kubb studio instead, which pairs your machine and runs this for you.

Installation

npm install @kubb/studio

Usage

import { Hookable, type KubbHooks } from '@kubb/core'
import { connectAgent, InvalidAgentTokenError, pairAgent } from '@kubb/studio'

const hooks = new Hookable<KubbHooks>()
hooks.hook('studio:connected', ({ agentSlug }) => console.log(`Connected as ${agentSlug}`))
hooks.hook('studio:warn', ({ message }) => console.warn(message))

let token = await readStoredToken()

for (;;) {
  token ??= (await pairAgent({ type: 'cli', name: 'my-project', hostname, machineId, onCode })).token
  try {
    // Resolves on shutdown, rejects when Studio refuses the token.
    await connectAgent({ token, configPath: 'kubb.config.ts', loadConfig, version: '1.0.0', hooks, signal })
    break
  } catch (error) {
    if (!(error instanceof InvalidAgentTokenError)) throw error
    token = undefined
  }
}

The runtime discovers nothing on its own. The host passes the token, the config loader, its own version, and a hook emitter, and keeps its own credentials. That is what lets one runtime serve a CLI running in a developer's project and a container running a fixed plugin set.

Source layout

| File | What it owns | | ---------------- | -------------------------------------------------------------------------------- | | protocol.ts | The wire contract Studio compiles against, published as @kubb/studio/protocol. | | connect.ts | connectAgent: the socket loop and the Agent that serves Studio's calls. | | pair.ts | pairAgent: RFC 8628 device pairing. | | snapshot.ts | createSnapshot for CI, and packing a generation into an npm tarball. | | generations.ts | Running a generation and keeping its files and AST for readFiles/readInput. | | diff.ts | The paged line diff readDiff serves between two kept sets. |

Connection

connectAgent opens wss://<studio>/api/agent/socket with the agent's bearer token and an x-kubb-instance-id header. Studio calls connect(info) as the first RPC call. info says whether the agent is a sandbox and carries its slug and Studio's version. From then on the agent pings every 30 seconds, and Studio schedules one job at a time on the socket.

With allowRead, the connect payload includes the current output.path file list. Studio reads file contents from disk through readFiles when a user opens a file. Sandbox agents have no disk output, and output paths outside the project root are excluded.

Studio ends a socket on purpose with one of these close codes:

| Code | Meaning | connectAgent | | ------ | --------------------------------------------- | ------------------------------------- | | 4001 | The token is invalid, expired, or revoked | Rejects with InvalidAgentTokenError | | 4002 | Another process of the same agent took over | Resolves | | 4003 | The agent is older than Studio accepts | Rejects with IncompatibleAgentError | | other | An ordinary drop, 1011 for a Studio failure | Reconnects with jittered backoff |

Everything the runtime has to say goes through the hooks emitter: studio:connected, studio:disconnected, studio:reconnecting, studio:command, studio:warn, and studio:error, next to the kubb:* hooks of each generation. When a request is refused for a missing permission, studio:warn names it as permission, so the host can add its own remedy.

Permissions

Every permission is off by default, and each covers one trust boundary:

| Option | What it grants | | ----------------- | ---------------------------------------------------------------------------------------------- | | allowWrite | Generated files are written to disk. Off means they exist only in memory and stream to Studio. | | allowExec | The formatter, the linter, and output.postGenerate run as child processes. | | allowConfigEdit | Studio may change plugin options in kubb.config.ts. | | allowRead | Studio may read existing output files and the files a generation produced. | | allowReadAst | Studio may read back the parsed spec (the Kubb AST). |

A sandbox never writes or edits config, and always allows reads.

Pairing

No host starts with a token, so each one pairs over RFC 8628 device authorization. pairAgent asks Studio for a code, hands it to onCode to show, and polls until someone approves it in the browser.

machineId is a secret the host keeps for the machine. Studio stores its hash, so the same machine pairing again rotates one agent's token instead of creating a second agent. Studio records the type with the agent. cli is kubb studio, which any member can approve. user and sandbox are the Docker image, run normally or as a sandbox. Only an admin can approve them. A denial throws PairingDeniedError, an expired code PairingExpiredError, and an aborted signal PairingCanceledError.

CI snapshots

createSnapshot generates the project like kubb generate, with the formatter, the linter, and output.postGenerate. It then packs the output as an npm tarball and sends one POST /api/snapshots with the organization CI API key as x-api-key.

import { createSnapshot } from '@kubb/studio'

const snapshot = await createSnapshot({
  apiKey: process.env.KUBB_TOKEN!,
  config,
  id: 'gh:123:pr-4',
  name: 'acme/api#4',
  packageName: '@acme/api',
  version: '1.0.0',
  commit: process.env.GITHUB_SHA,
  baseId: 'gh:123:refs/heads/main',
})

Snapshots that share an id belong to one CI agent in Studio. changes lists the files added, changed, and removed since that agent's previous snapshot of the package. With baseId, branchChanges compares against the latest snapshot of the CI agent with that id, such as the base branch's.

Supporting Kubb

Kubb is an open source project, and its development is funded entirely by sponsors. If you would like to become a sponsor, please consider:

License

MIT