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

@s1chat/sdk

v0.1.1

Published

Headless livestream chat SDK for s1chat (protocol-only, browser bundle).

Readme

@s1chat/sdk

Headless livechat SDK for s1chat. Pure protocol — no UI, no theme, no copy.

The TypeScript SDK that 30+ FE landing pages use to talk to s1chat-core. You bring the UI; the SDK gives you a typed connection, identity, room lifecycle, message I/O, and reconnection.

| | | | --- | --- | | Status | Functional (K1–K3 complete). Browser runtime not yet smoke-tested live; see caveats. | | Bundle | ESM 31KB · IIFE 34KB · ~10KB gzipped (under the 18KB budget) | | Targets | ES2020, evergreen browsers | | Deps | Zero runtime deps — no @rocket.chat/* leak into the browser |

Install

yarn add @s1chat/sdk
# or
npm install @s1chat/sdk

Or load directly via <script> (exposes window.S1ChatSDK):

<script src="https://unpkg.com/@s1chat/sdk/dist/index.global.js"></script>

Quick start

import { S1Chat } from '@s1chat/sdk';

const chat = await S1Chat.init({
  siteId: 'landing-blackfriday-2026',
  host: 'https://chat.s1.example',
});

// Guest mode — SDK generates and persists a token in localStorage.
await chat.identify();

// SSO mode — your landing's BE mints an HMAC-signed token.
// await chat.identify({ ssoToken: '<jwt from your landing BE>' });

const room = await chat.openRoom();

chat.on('message', (m) => {
  console.log(`[${m.from.kind}] ${m.text}`);
});
chat.on('agentJoined', (a) => console.log(`Agent ${a.name} joined`));
chat.on('roomClosed', () => console.log('Chat ended'));

await chat.send('Hello!');

Public API

All methods are on the S1Chat instance returned by init(). Types are exported alongside.

| method | purpose | | --- | --- | | S1Chat.init(opts) | Fetch site config, return a configured client. Does NOT open the WebSocket. | | chat.identify(opts?) | Upsert visitor. ssoToken for authenticated, nothing for guest. Returns Visitor. | | chat.openRoom() | Open or resume a livechat room + subscribe to the message stream. Returns Room. | | chat.send(text) | Send a chat message. Queues during reconnect and flushes on reconnect. | | chat.loadHistory(opts?) | Fetch prior messages via REST (paginated). Returns Message[]. | | chat.setTyping(active) | Publish typing/stopped indicator to the agent. No-op without a room. | | chat.on(event, cb) | Subscribe to events. Returns an unsubscribe fn. | | chat.close() | Tear down the WebSocket. Keeps the visitor token for next session. | | chat.logout() | close() + wipe the persisted visitor token. Use for "start new chat" or sign-out. | | chat.state | Read-only current state ('idle' \| 'connecting' \| 'ready' \| 'reconnecting' \| 'closed'). | | S1Chat.getPersistedRoomId(siteId) | Static helper — useful for showing "resume?" UI before init. |

Events

| event | payload | when | | --- | --- | --- | | message | Message | New message in the room (visitor's echo or agent reply). | | agentTyping | Agent | Agent is currently typing. Fires repeatedly; debounce client-side. | | agentJoined | Agent | Agent took the inquiry and joined the room. | | roomClosed | void | Server closed the room. Local chat.room is nulled. | | banned | string | Server rejected the visitor as banned. State transitions to closed. | | stateChange | S1ChatState | Any state-machine transition. Useful for showing connection status UI. |

State machine

idle ──init──► connecting ──identify+room──► ready ◄──► reconnecting
                    │                          │              │
                    └──────────────────────────┴──────────► closed
  • idle — only briefly, before init() resolves
  • connecting — config fetched, WS not yet opened or room not yet subscribed
  • ready — WS open, room subscribed, send() works synchronously
  • reconnecting — WS dropped; send() queues into the outbox, flushed on reconnect
  • closed — terminal; call S1Chat.init() again to start a new session

Persistence

The SDK persists two values per siteId so a page reload (or new tab) can resume the same visitor + room:

| key | storage | when set | when cleared | | --- | --- | --- | --- | | s1chat:<siteId>:visitorToken | localStorage (+ cookie fallback) | first identify() | logout() | | s1chat:<siteId>:roomId | localStorage (+ cookie fallback) | first openRoom() | close(), logout(), server-side roomClosed |

Examples

| folder | what | | --- | --- | | examples/vanilla-html/ | Single-file HTML page using <script src=".../index.global.js"> — copy-paste runnable. | | examples/nuxt/ | A Vue 3 useS1Chat composable + <Chat> SFC. Works in Vite+Vue and Nuxt 3. | | examples/react/ | A React <Chat> component using the SDK directly. Drop into your own Vite/Next.js app. |

SSO setup

If your landing site authenticates visitors, your BE mints a JWT-like HMAC-signed token (HS256) and your FE passes it to identify():

// Server-side (your landing BE)
import { createHmac } from 'crypto';

const now = Math.floor(Date.now() / 1000);
// 1. Encode the payload as base64url — this is what the HMAC signs.
const payloadB64 = Buffer.from(JSON.stringify({
  siteId: 'landing-blackfriday-2026',
  externalUserId: 'user_42',
  name: 'Alice',
  email: '[email protected]',
  iat: now,                  // required: issued-at (seconds)
  exp: now + 300,            // 5 min validity
})).toString('base64url');
// 2. Sign the base64url payload string (not the raw JSON).
const sig = createHmac('sha256', process.env.S1CHAT_HMAC_KEY)
  .update(payloadB64)
  .digest('base64url');
const ssoToken = `${payloadB64}.${sig}`;

The HMAC key is the one s1chat-core returned when you created the Site. Rotation is supported via POST /api/v1/s1c/sites/:siteId/rotate-secret; previous key remains valid for the grace period (default 60min).

Full sequence + key rotation flow: ../../docs/usage.md §4 and §10.

Caveats

  • Browser runtime untested: the SDK passes 57/57 unit tests under happy-dom and builds clean, but full visitor↔agent flow via a real browser has not been smoke-tested. K4 examples are the first chance to do that. Open an issue at the parent repo if you hit anything.
  • No file upload yet: features.fileUpload is reported by init() but the SDK has no sendFile() method. Coming in Phase-5.
  • No read receipts yet: same — features.readReceipt flags it, no method exposed.
  • Agent typing is not debounced: every user-activity event fires agentTyping. Add your own "stopped typing after N ms idle" timer in the consuming component (the SDK is protocol-only, no UX baked in).

Scripts

| script | what it does | | --- | --- | | yarn workspace @s1chat/sdk build | ESM + CJS + IIFE bundles via tsup | | yarn workspace @s1chat/sdk dev | tsup --watch | | yarn workspace @s1chat/sdk test | vitest (happy-dom) | | yarn workspace @s1chat/sdk typecheck | tsc --noEmit | | yarn workspace @s1chat/sdk lint | eslint |

Project context

License

TBD — inherits from the parent repo's choice.