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

@cablejs/client

v0.2.3

Published

Typed procedure proxy, HTTP links, and per-host resumable sockets.

Downloads

794

Readme

client

The procedure client imports your shared contract type and calls the portable RPC runtime through HTTP batches or an in-process link. It never imports server types.

import { createClient } from "@cablejs/client";
import type { Api } from "./contract.js";

const client = createClient<Api>({
  url: "https://api.example.com/_cable",
  auth: { token: () => sessionStorage.getItem("token") ?? undefined },
});

const posts = await client.posts.list.query({ limit: 10 });
await client.posts.create.mutate("A new post");

Concurrent calls share a POST batch, capped at 20 requests or 10 milliseconds by default. Use batchLink({ maxBatch, maxWait }) to change these bounds. A response must contain exactly one result for each request ID; malformed batches reject all pending calls. A failed batch does not poison subsequent requests.

Links are factories with isolated state per client. Each returns a handler that can pass a call to next or finish it as a transport. headers and auth.token are evaluated for each HTTP batch. onError observes a failed procedure call; throwing in that observer does not replace the original error.

To use a query's declared GET transport, pass contract: api in the client options. This also infers the client type, so an explicit type argument is optional. Type-only clients use POST because TypeScript erases their transport metadata. The default base endpoint is /_cable for same-origin requests.

Wire inputs, outputs, and error payloads must be JSON-native. Use schema transforms to produce strings from Dates or other application objects before serialization. Unsupported values are rejected instead of silently changing type.

Pass the runtime contract to use channels:

import { api } from "./contract.js";

const client = createClient({ contract: api, url: "/_cable" });
const room = client.room({ roomId: "general" });
const off = room.on("message", (message) => console.log(message));
await room.send({ text: "Hello" }, { ack: true });
room.presence.update({ name: "Jonah" });
// When the view is no longer needed:
off();
room.dispose();

Event names, procedure methods, presence, and history come from your channel contract. Creating a handle is lazy. Subscribing, publishing an event, or updating presence opens its socket. Handles for the same canonical channel key share a connection within one client. Dispose each handle when finished; the last release closes the socket after 30 seconds, configurable through ws.idleClose.

Host procedures use the open socket or fall back to an HTTP POST when disconnected. An HTTP-only call does not open a socket. Channel HTTP fallback requires an adapter that serves /_cable/host/:key/:procedure; the memory Host supplies the engine and socket seam for local tests. Credentials are refreshed for each HTTP call and socket connection. Raw channel parameters travel with requests so schema transformations run once at each validation boundary.

Reconnect uses exponential backoff. Replay resumes from the last delivered event, deduplicates sequences, and waits for the final welcome chunk before reporting open. A retained-history gap emits reset. Optional ws.cursors persists sequence cursors through a sessionStorage-compatible interface. Presence snapshots commit only after all welcome chunks arrive; local presence is republished on reconnect. Acknowledged events and host calls reject if their connection is interrupted; they are never automatically repeated.

Use onStatus to observe connecting, open, resuming, and closed, and onError for asynchronous channel errors. Acknowledgement and procedure failures reject their promises with CableError. Observer exceptions cannot break delivery to other listeners. ws.createSocket accepts a browser-compatible socket factory for deterministic tests or custom transports.