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

@q9labsai/chalk-client

v4.1.15

Published

`@q9labsai/chalk-client` is Chalk's framework-agnostic `SpaceClient`. It connects a person to a Space, maintains the live Episode, and exposes one consistent `SpaceSnapshot` for any UI layer.

Readme

@q9labsai/chalk-client

@q9labsai/chalk-client is Chalk's framework-agnostic SpaceClient. It connects a person to a Space, maintains the live Episode, and exposes one consistent SpaceSnapshot for any UI layer.

A Space is the durable place for collaboration: its identity, configuration, members, and living content persist between Episodes. An Episode is one bounded run of live activity in that Space. join() always targets the Space; an Episode emerges when appropriate.

Install

pnpm add @q9labsai/chalk-client

Create and join a Space

Your backend mints an AccessGrant with the server SDK. Pass it through to the client unchanged: it is an opaque signed envelope, so application code does not construct or inspect it. getAccess may resolve with the fetch Response that carries the grant or with its decoded JSON; the client validates it and fails the join on a non-OK response or a malformed body.

import { createSpaceClient } from "@q9labsai/chalk-client";

const client = createSpaceClient({
  space: "design-review",
  getAccess: ({ space, reason }) => fetch(`/api/chalk/spaces/${space}/access?reason=${reason}`),
});

await client.join({
  displayName: "Ari",
  microphone: true,
  camera: false,
});

getAccess receives reason: "join" | "refresh" | "retry". Connection uses it for Entrance freshness, scheduled refresh, wake revalidation, and one refresh-and-retry after an access rejection. Keep the callback available for the full lifetime of the client.

Snapshot store

subscribe and getSnapshot form a framework-neutral external-store contract. Each snapshot has referentially stable slices, so UI code can select only the state it needs.

const unsubscribe = client.subscribe(() => {
  const snapshot = client.getSnapshot();
  renderConnection(snapshot.connection.status);
});

const snapshot = client.getSnapshot();
if (snapshot.self.can("sendChat")) {
  await client.chat.send({ text: "Ready when you are." });
}

unsubscribe();

SpaceSnapshot contains these slices:

  • connection: status, live Episode summary, and the latest failure
  • self: local Participant identity, role, capabilities, hand state, and can(capability)
  • participants: roster and admission queue
  • media: device selection, local and remote media, screen share, and requests
  • chat: messages, pending sends, read receipts, unread count, and pagination
  • reactions: active transient reactions
  • whiteboard: availability and engine state

Lifecycle and Episode controls

await client.leave();
await client.endEpisode();
await client.extendEpisode(15);
client.dispose();

endEpisode and extendEpisode are capability-gated. Use dispose() when the client will no longer be used; it releases the Connection and its resources.

Feature controllers

Lifecycle stays flat on SpaceClient; feature commands are namespaced.

await client.media.setMicrophoneEnabled(true);
await client.media.setCameraEnabled(true);
await client.media.setScreenShareEnabled(true);
await client.media.selectMicrophone("microphone-id");
await client.media.selectCamera("camera-id");
await client.media.selectSpeaker("speaker-id");
await client.media.acceptRequest("request-id");
await client.media.declineRequest("request-id");

await client.chat.send({ text: "Hello" });
await client.chat.loadOlder();
await client.chat.markRead("message-id");
const attachment = await client.chat.files.upload(file);
const url = client.chat.files.url(attachment);

await client.participants.assignRole("participant-id", "collaborator");
await client.participants.mute("participant-id");
await client.participants.stopVideo("participant-id");
await client.participants.stopScreenShare("participant-id");
await client.participants.requestMedia("participant-id", "microphone");
await client.participants.remove("participant-id");
await client.participants.admit("request-id");
await client.participants.deny("request-id");
await client.participants.raiseHand();
await client.participants.lowerHand();
await client.participants.renameSelf("Ari");

await client.reactions.send("🎉");
const transport = client.whiteboard.transport();

Events and failures

Use on for discrete events and snapshots for current state.

const stopListening = client.on("episodeEnded", ({ episode }) => {
  showEpisodeHistory(episode?.id);
});

client.on("error", ({ error }) => {
  reportSafeDiagnostic(error.code, error.recoverable);
});

stopListening();

Events are participantJoined, participantLeft, episodeEnded, screenShareStarted, screenShareStopped, and error. Public failures use stable codes such as access.invalid, episode.ended, and chat.payload_invalid.

Journey telemetry

Client telemetry is opt-in. Start a space.join journey when a Participant joins a Space, pass its context to HTTP or Sync boundaries, and flush the bounded queue when the surface is ready to export:

import { createTelemetryClient } from "@q9labsai/chalk-client/telemetry";

const telemetry = createTelemetryClient({ enabled: true, baseUrl: "https://api.example.com" });
const journey = telemetry.startJourney({ kind: "space.join" });
const response = await fetch("/api/chalk/spaces/design-review", { headers: journey.headers });
journey.terminal(response.ok ? "succeeded" : "failed");
await telemetry.flush();

Journey events carry journey_id, W3C traceparent, and optional tracestate. Attributes and the in-memory timeline are bounded, and the built-in client observations record aggregate RTC state only: access-grant contents, Participant identity, Space or Episode identifiers, media payloads, and request bodies stay out of telemetry.

Effect entry

The default entry is Promise-based. Effect applications can use the @q9labsai/chalk-client/effect entry for the same SpaceClient shape as an Effect program.