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

@signalling/sdk

v1.0.1

Published

Browser-first JavaScript SDK for the Confrnce signalling backend (REST + DPoP + WebSocket + WebRTC). Self-contained — vendor or publish without cloning the server repo.

Readme

@signalling/sdk

A browser-first JavaScript SDK for the Confrnce signalling API. It is explicitly designed as an API wrapper, not a parallel stack — every public method maps onto a real route or wire-protocol artefact on the server. The integrator writes their own UI; the SDK handles auth, DPoP signing, the WebSocket handshake, WebRTC peer orchestration, and room state.

Standalone distribution

This folder is self-contained. Third parties can vendor it alone (copy the directory, npm install, npm run build) or split it into a dedicated Git repository — no backend or monorepo checkout is required. Protocol details (DPoP, WebSocket handshake) are summarized under docs/ in this package.

Internal reference: If you also maintain the server repo, architectural notes may live alongside the backend (e.g. AUTH_FLOW.md). This README is the SDK consumer entry point.

Table of contents

Why this SDK

Without the SDK, an integrator has to:

  • run the OIDC + PKCE handshake themselves;
  • generate a non-extractable P-256 keypair, persist it in IndexedDB, never let it leave the device;
  • sign every outbound HTTP request with a fresh DPoP JWT, including the htm / htu / iat / jti / nonce claims;
  • handle Use-DPoP-Nonce retry loops;
  • run a two-stage WebSocket handshake (HTTP ticket + WS upgrade + DPoP first frame within 5 s + ack), strip query / fragment from htu, decode the ticket nonce out of the JWT body, and react to a dozen 4xxx close codes;
  • wire RTCPeerConnection instances, fan SDP offers / answers / ICE candidates over the room WebSocket, fall back to TURN when ICE fails, surface the local screen-share lifecycle.

This SDK does all of that for you. Under the hood, every call ultimately hits the backend’s HTTP routes and WebSocket wire format your server documents.

What's inside

src/
  api/         REST client (DPoP-signed; nonce-retry)
  auth/        Login / bind / logout / me
  dpop/        WebCrypto P-256 keypair + JWS proofs (IndexedDB-persisted)
  websocket/   Ticket → upgrade → DPoP first-frame → ack
  room/        REST wrapper + local clientId tracking
  webrtc/      Peer orchestration over the room WebSocket
  devices/     getUserMedia / getDisplayMedia / device enumeration
  internal/    base64url, logger, typed event emitter (NOT exported)
  types/       Public domain types + error classes
  index.ts     SignallingSDK + Call composition

Installation

npm install @signalling/sdk

The package ships ESM (dist/index.mjs), CJS (dist/index.js), and TS declarations. No runtime dependencies are required.

Quickstart

import { SignallingSDK } from "@signalling/sdk";

// 1. Initialise (eagerly loads the DPoP keypair from IndexedDB)
const sdk = await SignallingSDK.create({
  baseUrl: "https://api.example.com",
  authMode: "bff",
  logLevel: "info",
});

// 2. Authenticate (BFF redirect → Keycloak → /auth/complete page)
if (!(await sdk.auth.isAuthenticated())) {
  // First load: send the user to Keycloak.
  sdk.auth.login("/dashboard");
  // ...
}

// 3. On the SPA's /auth/complete page:
const bindToken = sdk.auth.bindTokenFromFragment();
if (bindToken) {
  const { returnTo } = await sdk.auth.completeBind(bindToken);
  window.location.assign(returnTo || "/");
}

// 4. Create or join a room.
const room = await sdk.rooms.create();              // { roomId, clientId }
const call = await sdk.calls.joinRoom({
  roomId: room.roomId,
  media:  { audio: true, video: true },
});

// 5. React to events.
call.on("peer.joined",  (p) => console.log("joined:", p.clientId));
call.on("stream.added", ({ clientId, stream }) => attachToDom(clientId, stream));
call.on("peer.left",    (p) => removeFromDom(p.clientId));
call.on("connection.closed", ({ code }) => console.warn("WS closed:", code));

// 6. Tear down on unmount.
await call.leave();

Public API

class SignallingSDK {
  static create(config: SignallingSDKConfig): Promise<SignallingSDK>;

  // Module entry points (all stateful).
  auth:    AuthClient;       // login / completeBind / logout / me / updateProfile
  rooms:   RoomManager;      // create / join / view / leave / screenshare / permissions
  devices: DeviceManager;    // getLocalStream / getScreenShare / listInventory
  api:     ApiClient;        // raw REST surface (escape hatch)
  ws:      WebSocketClient;  // raw WebSocket (escape hatch)
  webrtc:  WebRTCManager;    // raw RTCPeerConnection orchestration
  dpop:    DPoPManager;      // raw DPoP signer
  logger:  Logger;

  // High-level orchestration: join + ws + webrtc in one call.
  calls: { joinRoom(config: CallConfig): Promise<Call> };
}

class Call extends TypedEventEmitter<CallEventMap> {
  readonly roomId:   number | string;
  readonly clientId: string;
  localStream:       MediaStream | null;

  setMicEnabled(on: boolean): void;
  setCameraEnabled(on: boolean): void;
  setLocalStream(s: MediaStream | null): Promise<void>;
  startScreenShare(): Promise<MediaStream>;
  stopScreenShare(): Promise<void>;
  leave(): Promise<void>;
}

The full strongly-typed event map (CallEventMap, WebRTCEventMap, WebSocketEventMap, AuthEventMap) is exported from the entry point.

Backend contract this SDK wraps

Every public method ultimately reaches one of:

| SDK method | Backend route | |---------------------------------------------|-------------------------------------------------------------------| | sdk.auth.login() | GET /auth/login (browser navigation) | | sdk.auth.completeBind(token) | POST /auth/dpop/bind | | sdk.auth.getCurrentUser() | GET /me | | sdk.auth.updateProfile(...) | PATCH /me | | sdk.auth.logout() | POST /auth/logout | | sdk.auth.logoutAll() | POST /auth/logout-all | | sdk.auth.openAccountConsole() | GET /auth/account (browser navigation) | | sdk.rooms.create() | POST /createroom | | sdk.rooms.join(id) | POST /joinroom/{roomId} | | sdk.rooms.view(id) | GET /viewroom/{roomId} | | sdk.rooms.leave() | DELETE /leaveroom/{roomId}/{clientId} | | sdk.rooms.startScreenShare() | POST /room/{roomId}/{clientId}/screen-share/start | | sdk.rooms.stopScreenShare() | POST /room/{roomId}/{clientId}/screen-share/stop | | sdk.rooms.myPermissions() | GET /room/{roomId}/{clientId}/permissions | | sdk.rooms.updatePermissions(...) | PUT /room/{roomId}/{clientId}/permissions | | sdk.api.getTurnCredentials() | POST /v1/turn/credentials | | sdk.api.searchUserByEmail(email) | GET /users/search?email=... | | sdk.api.issueWSTicket() | POST /auth/ws-ticket | | Internal — used by ws.connectRoom | WS /ws/{roomId}/{clientId}?ticket=... | | Internal — used by ws.connectGlobal | WS /global/ws?ticket=... |

Every authed REST call carries a DPoP: <jws> header generated fresh by DPoPManager. Every WS upgrade is followed by a single { "type": "dpop_handshake", "proof": "..." } frame; the SDK waits for { "type": "dpop_handshake_ack" } before passing application messages through.

Documentation

The docs/ folder contains task-oriented guides:

If you change a public method here, update the matching doc in the same PR. The docs are checked manually in code review against the shipped surface. "# signalling-js-sdk"