{"_id":"@alternet/wss-mux-client","_rev":"5-67240151a065e3cef044e0affeb07e1b","name":"@alternet/wss-mux-client","dist-tags":{"latest":"0.6.2"},"versions":{"0.5.2":{"name":"@alternet/wss-mux-client","version":"0.5.2","keywords":["websocket","wss-mux","realtime","multiplexer","pubsub"],"license":"MIT OR Apache-2.0","_id":"@alternet/wss-mux-client@0.5.2","maintainers":[{"name":"evan.macgregor","email":"evan@macgregor.llc"}],"homepage":"https://github.com/alternet-dev/wss-mux/tree/trunk/clients/typescript#readme","bugs":{"url":"https://github.com/alternet-dev/wss-mux/issues"},"dist":{"shasum":"95ab2f2bd71226be415193052db25996ab272813","tarball":"https://registry.npmjs.org/@alternet/wss-mux-client/-/wss-mux-client-0.5.2.tgz","fileCount":20,"integrity":"sha512-FtCdVrIBOuhtmPfSvZezrYADn/4mVkOELo/39sEYRDlAnBwHEhHwzx2OcQENTf3XJ8BkzTq5k2ffA9M9Dy9q+w==","signatures":[{"sig":"MEQCIAIB2TP9PF43Ww22cF1K9zbXt19QeNj+E4Za7DOdWEG0AiBNqU33EsokZXVLJWLOWS5scf5vcEmtWbnte1kGuk0CIQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":50546},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"f1902a02945cf491e3b32a9a922448c43475be70","scripts":{"test":"node --test tests/client.test.mjs tests/reconnect.test.mjs tests/e2e.test.mjs","build":"tsc","clean":"rm -rf dist","test:e2e":"WSS_MUX_E2E=1 node --test tests/e2e.test.mjs","typecheck":"tsc --noEmit","prepublishOnly":"npm run clean && npm run build"},"_npmUser":{"name":"evan.macgregor","email":"evan@macgregor.llc"},"repository":{"url":"git+https://github.com/alternet-dev/wss-mux.git","type":"git","directory":"clients/typescript"},"_npmVersion":"10.8.2","description":"Browser TypeScript client for wss-mux WebSocket multiplexer","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ws":"^8.16.0","@types/ws":"^8.5.0","typescript":"^5.4.0","@types/node":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/wss-mux-client_0.5.2_1779863337922_0.5678283080261173","host":"s3://npm-registry-packages-npm-production"}},"0.5.3":{"name":"@alternet/wss-mux-client","version":"0.5.3","keywords":["websocket","wss-mux","realtime","multiplexer","pubsub"],"license":"MIT OR Apache-2.0","_id":"@alternet/wss-mux-client@0.5.3","maintainers":[{"name":"evan.macgregor","email":"evan@macgregor.llc"}],"homepage":"https://github.com/alternet-dev/wss-mux/tree/trunk/clients/typescript#readme","bugs":{"url":"https://github.com/alternet-dev/wss-mux/issues"},"dist":{"shasum":"860c15653977a8e60883675711370542e9c17382","tarball":"https://registry.npmjs.org/@alternet/wss-mux-client/-/wss-mux-client-0.5.3.tgz","fileCount":20,"integrity":"sha512-9dnS56H6Q4bNgePGyz3neGe1TDxFrkuxDmcJoI8lLD5U+bYEy+k8QCq7m0Xp5xYQrWsRVFUXiOfbsxlElW3v8g==","signatures":[{"sig":"MEUCIQDKL/20LGwvx1TmbYG1otiMSQ/AK25Zlg6u57XmXfF4NQIgSQgeFeB441JWY2JR6QTj+oC0FOAItMfQK5NBlL5LuIo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alternet%2fwss-mux-client@0.5.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":50546},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"fb8de3b3b09c62815b3f25049c402fdd2e06a834","scripts":{"test":"node --test tests/client.test.mjs tests/reconnect.test.mjs tests/e2e.test.mjs","build":"tsc","clean":"rm -rf dist","test:e2e":"WSS_MUX_E2E=1 node --test tests/e2e.test.mjs","typecheck":"tsc --noEmit","prepublishOnly":"npm run clean && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:100f5a4b-4ebd-4cfc-b22f-67bace14bf7c"}},"repository":{"url":"git+https://github.com/alternet-dev/wss-mux.git","type":"git","directory":"clients/typescript"},"_npmVersion":"11.15.0","description":"Browser TypeScript client for wss-mux WebSocket multiplexer","directories":{},"sideEffects":false,"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ws":"^8.16.0","@types/ws":"^8.5.0","typescript":"^5.4.0","@types/node":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/wss-mux-client_0.5.3_1779898803753_0.9486144461747774","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@alternet/wss-mux-client","version":"0.6.0","keywords":["websocket","wss-mux","realtime","multiplexer","pubsub"],"license":"MIT OR Apache-2.0","_id":"@alternet/wss-mux-client@0.6.0","maintainers":[{"name":"evan.macgregor","email":"evan@macgregor.llc"}],"homepage":"https://github.com/alternet-dev/wss-mux/tree/trunk/clients/typescript#readme","bugs":{"url":"https://github.com/alternet-dev/wss-mux/issues"},"dist":{"shasum":"e708386efd050aa28689503f662fdcb2c73e390d","tarball":"https://registry.npmjs.org/@alternet/wss-mux-client/-/wss-mux-client-0.6.0.tgz","fileCount":20,"integrity":"sha512-n03riip2B3f8wVkLzAa67rEzYZ2GTTQ7COCsocvXGIugApoB7IP56iQsVOQPRDGM2yuiWfcz9eGB9/iA2cNDXQ==","signatures":[{"sig":"MEUCIHkyUJrduLt+MM7SeE/jj+us+BkYTDfObZfhdNvo0E2sAiEA1yH8c+LljVMlmximxXf3tJ1xqzgrNj8FU/MsrGZpsso=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alternet%2fwss-mux-client@0.6.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":60014},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"db7eada2577339c8f58d21ed6539cdceabb39738","scripts":{"test":"node --test tests/client.test.mjs tests/reconnect.test.mjs tests/publish.test.mjs tests/e2e.test.mjs","build":"tsc","clean":"rm -rf dist","test:e2e":"WSS_MUX_E2E=1 node --test tests/e2e.test.mjs","typecheck":"tsc --noEmit","prepublishOnly":"npm run clean && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:100f5a4b-4ebd-4cfc-b22f-67bace14bf7c"}},"repository":{"url":"git+https://github.com/alternet-dev/wss-mux.git","type":"git","directory":"clients/typescript"},"_npmVersion":"11.16.0","description":"Browser TypeScript client for wss-mux WebSocket multiplexer","directories":{},"sideEffects":false,"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ws":"^8.16.0","@types/ws":"^8.5.0","typescript":"^5.4.0","@types/node":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/wss-mux-client_0.6.0_1780117163063_0.3993794790858709","host":"s3://npm-registry-packages-npm-production"}},"0.6.1":{"name":"@alternet/wss-mux-client","version":"0.6.1","keywords":["websocket","wss-mux","realtime","multiplexer","pubsub"],"license":"MIT OR Apache-2.0","_id":"@alternet/wss-mux-client@0.6.1","maintainers":[{"name":"evan.macgregor","email":"evan@macgregor.llc"}],"homepage":"https://github.com/alternet-dev/wss-mux/tree/trunk/clients/typescript#readme","bugs":{"url":"https://github.com/alternet-dev/wss-mux/issues"},"dist":{"shasum":"e94d5332ab6c01f879f6b18acd1e2fc9df220ba4","tarball":"https://registry.npmjs.org/@alternet/wss-mux-client/-/wss-mux-client-0.6.1.tgz","fileCount":20,"integrity":"sha512-51k/c3IRLhhJhw5Rxlz74+2nmAYEVJdg+WOTCDXonfrSsgHbe5AzR37DWPz72HHRONJXshnyhUCs2JULDiDRZg==","signatures":[{"sig":"MEUCIQDUJgJlQxNgX+QJPKdNjoA5iG9IFVO8dEbtJ1HjlH/lLAIgNrEYjEAO6y/aqSDskOX4I1L910mGDq2DeXug2g4rD9Q=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alternet%2fwss-mux-client@0.6.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":61292},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"4211a5be187d4c41110e4f1b186bb12a7a9d645c","scripts":{"test":"node --test tests/client.test.mjs tests/reconnect.test.mjs tests/publish.test.mjs tests/e2e.test.mjs","build":"tsc","clean":"rm -rf dist","test:e2e":"WSS_MUX_E2E=1 node --test tests/e2e.test.mjs","typecheck":"tsc --noEmit","prepublishOnly":"npm run clean && npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:100f5a4b-4ebd-4cfc-b22f-67bace14bf7c"}},"repository":{"url":"git+https://github.com/alternet-dev/wss-mux.git","type":"git","directory":"clients/typescript"},"_npmVersion":"11.16.0","description":"Browser TypeScript client for wss-mux WebSocket multiplexer","directories":{},"sideEffects":false,"_nodeVersion":"24.16.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ws":"^8.16.0","@types/ws":"^8.5.0","typescript":"^5.4.0","@types/node":"^20.0.0"},"_npmOperationalInternal":{"tmp":"tmp/wss-mux-client_0.6.1_1780127524467_0.09041647012743592","host":"s3://npm-registry-packages-npm-production"}},"0.6.2":{"name":"@alternet/wss-mux-client","version":"0.6.2","description":"Browser TypeScript client for wss-mux WebSocket multiplexer","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"build":"tsc","typecheck":"tsc --noEmit","test":"node --test tests/client.test.mjs tests/reconnect.test.mjs tests/publish.test.mjs tests/e2e.test.mjs","test:e2e":"WSS_MUX_E2E=1 node --test tests/e2e.test.mjs","clean":"rm -rf dist","prepublishOnly":"npm run clean && npm run build"},"devDependencies":{"typescript":"^5.4.0","@types/node":"^20.0.0","ws":"^8.16.0","@types/ws":"^8.5.0"},"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/alternet-dev/wss-mux.git","directory":"clients/typescript"},"homepage":"https://github.com/alternet-dev/wss-mux/tree/trunk/clients/typescript#readme","bugs":{"url":"https://github.com/alternet-dev/wss-mux/issues"},"license":"MIT OR Apache-2.0","keywords":["websocket","wss-mux","realtime","multiplexer","pubsub"],"engines":{"node":">=20"},"sideEffects":false,"gitHead":"331e88ede82d9b812862381b03203f37c65dfcfa","_id":"@alternet/wss-mux-client@0.6.2","_nodeVersion":"24.16.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-m8X6UWkM0tPRfwovvIx3ZIXN0ObdoRIDd2YKU5+7+pUiqLV6nCOxJDTPfA7OpgE92i++VGfLtYnIOXgGfX5KuQ==","shasum":"32a62ec507f372e6cd2ca2cd97d3016b4586207b","tarball":"https://registry.npmjs.org/@alternet/wss-mux-client/-/wss-mux-client-0.6.2.tgz","fileCount":20,"unpackedSize":61292,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alternet%2fwss-mux-client@0.6.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCICAgvrasTPK4FdmLIq47OE6ULHmWGdlEwtmXfcDfrrhOAiEArNHI7/VmmTYK+l3AOXphRt1qUdxkJ5JBTFLAKG14Fis="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:100f5a4b-4ebd-4cfc-b22f-67bace14bf7c"}},"directories":{},"maintainers":[{"name":"evan.macgregor","email":"evan@macgregor.llc"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/wss-mux-client_0.6.2_1780188946994_0.20185862115098097"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-27T06:28:57.757Z","modified":"2026-05-31T00:55:47.520Z","0.5.2":"2026-05-27T06:28:58.084Z","0.5.3":"2026-05-27T16:20:03.904Z","0.6.0":"2026-05-30T04:59:23.203Z","0.6.1":"2026-05-30T07:52:04.638Z","0.6.2":"2026-05-31T00:55:47.147Z"},"bugs":{"url":"https://github.com/alternet-dev/wss-mux/issues"},"license":"MIT OR Apache-2.0","homepage":"https://github.com/alternet-dev/wss-mux/tree/trunk/clients/typescript#readme","keywords":["websocket","wss-mux","realtime","multiplexer","pubsub"],"repository":{"type":"git","url":"git+https://github.com/alternet-dev/wss-mux.git","directory":"clients/typescript"},"description":"Browser TypeScript client for wss-mux WebSocket multiplexer","maintainers":[{"name":"evan.macgregor","email":"evan@macgregor.llc"}],"readme":"# @alternet/wss-mux-client\n\nBrowser TypeScript client for the [wss-mux](https://github.com/alternet-dev/wss-mux)\nWebSocket multiplexer.\n\n- Zero runtime dependencies.\n- Browser-first (uses `globalThis.WebSocket`; injectable for other hosts).\n- Automatic reconnect with exponential backoff.\n- Token refresh via a caller-provided `getToken` callback on initial connect\n  and on close-code `4401` (`expired_token`).\n- Subscribe **and** publish over a single WebSocket connection.\n- Typed errors for the documented wss-mux error codes and close codes.\n\n## Install\n\n```bash\nnpm install @alternet/wss-mux-client\n```\n\n## Quickstart\n\n```ts\nimport { WssMuxClient } from \"@alternet/wss-mux-client\";\n\nconst client = new WssMuxClient({\n  // Whatever path your wss-mux deployment serves the WebSocket on; the\n  // handshake response from your auth endpoint is the canonical source.\n  wssUrl: \"wss://realtime.example.com/stream\",\n  getToken: async () => kcAuth.token,            // your token source\n  onError: (err) => console.warn(err.code, err.message),\n});\n\nconst sid = await client.subscribe(\"notification_banner\", \"*\", (event) => {\n  console.log(event.payload);\n});\n\n// Publish over the same connection.\nawait client.publish(\"chat_messages\", \"room-42\", {\n  from: \"alice\",\n  text: \"hello\",\n});\n\n// later...\nawait client.unsubscribe(sid);\nawait client.close();\n```\n\nThe `getToken` callback is called on the initial connect and whenever the\nserver closes the connection with code `4401`. Other reconnects reuse the\ncached token.\n\n### `getToken` contract (in detail)\n\nThe SDK invokes `getToken()` in exactly two situations:\n\n1. **Initial connection.** Once, before sending the first `auth` frame.\n2. **Reconnect after a close-code 4401.** When the server closes with\n   `4401` (`expired_token` / `unauthenticated`), the SDK re-invokes\n   `getToken()` before re-auth'ing, sends the **freshly returned value**\n   on the new connection, and replays subscriptions.\n\nThe fresh value reaches the wire — the SDK does not cache the previous\ntoken across a 4401-driven reconnect. (Other reconnects, e.g. a transient\n1006 disconnect, *do* reuse the cached token to avoid hammering the\ntoken issuer on flapping connections.)\n\nThis is the safety net the SDK provides for token rotation: the consumer\nkeeps the latest token reachable from inside the callback — typically a\nReact ref, an atom, a signal, or whatever your framework's \"read the\ncurrent value\" primitive is — and `getToken` returns whatever is\ncurrent at refresh time. The SDK calls it for you when it matters; you\ndon't have to re-mount the client.\n\nPre-emptive token refresh (refreshing before the server says 4401) is\nout of scope — it's an app-layer concern. The 4401-driven path above is\nthe safety net for when that pre-emptive refresh missed.\n\n## API\n\n### `new WssMuxClient(options)`\n\n| Option | Type | Default | Description |\n|---|---|---|---|\n| `wssUrl` | `string` | required | Full WebSocket URL: `wss://host[:port]/path`. |\n| `getToken` | `() => string \\| Promise<string>` | required | Returns the auth token. |\n| `WebSocket` | `typeof WebSocket` | `globalThis.WebSocket` | Constructor override for non-browser hosts. |\n| `reconnect.maxAttempts` | `number` | `Infinity` | Cap on reconnect attempts. |\n| `reconnect.initialBackoffMs` | `number` | `1000` | Initial backoff. |\n| `reconnect.maxBackoffMs` | `number` | `30000` | Max backoff. |\n| `reconnect.backoffMultiplier` | `number` | `2` | Backoff multiplier per attempt. |\n| `onError` | `(err: ProtocolError) => void` | — | Called when the server sends an `error` frame. |\n| `onStateChange` | `(state: ConnectionState) => void` | — | Called on connection state transitions. |\n| `publishSettleMs` | `number` | `250` | How long `publish()` waits for a possible error frame before resolving. |\n\n### `client.subscribe(stream, [key], callback) → Promise<SubscriptionId>`\n\nBinds a subscription. The callback is invoked for every matching event.\nOmit `key` to receive all events on the stream.\n\n### `client.unsubscribe(id) → Promise<void>`\n\nRemoves a subscription. Idempotent.\n\n### `client.publish(stream, [key], payload) → Promise<void>`\n\nEmits an event on `stream`. Same downstream dispatch path as the server's\nHTTP `POST /events` — same per-subscription delivery, same coalescing,\nsame peer fanout. The connection's principals must intersect the stream's\n`publish` audience on the server; otherwise the call rejects with a\n`ProtocolError` whose `code` is `unauthorized_publish`.\n\nAck-by-absence: the server does not send a success frame. The returned\npromise resolves once the settle window (`publishSettleMs`, default\n250 ms) elapses without an error frame matching the publish's id. If an\nerror frame arrives within the window the promise rejects with the\nmatching `ProtocolError`. If the connection drops while pending, it\nrejects with `ConnectionClosedError`.\n\n### `client.close() → Promise<void>`\n\nGraceful shutdown. After calling `close()`, no further `subscribe()` calls\nare accepted.\n\n### `client.connectionState`\n\nCurrent state: `\"idle\" | \"connecting\" | \"authenticating\" | \"ready\" |\n\"reconnecting\" | \"closing\" | \"closed\"`.\n\n## Error handling\n\n`ProtocolError` wraps server-sent `error` frames. The `code` field is one\nof the documented wss-mux error codes (`unauthorized_subscribe`,\n`unauthorized_publish`, `publish_payload_too_large`, `unknown_stream`,\n`duplicate_subscription_id`, `rate_limited`, `overflow`, etc.). For\nper-subscription fatal codes the SDK automatically removes the\nsubscription from its local map; for publish errors the awaited\n`publish()` promise rejects (and `onError` still fires for parity).\n\n`ConnectionClosedError` is surfaced when the server closes with code\n`4400` (`bad_frame`), which indicates a protocol bug — the SDK does not\nreconnect in that case.\n\n## Development\n\n```bash\nnpm install\nnpm run typecheck\nnpm run build\nnpm test          # unit tests via node:test\nnpm run test:e2e  # against a real wss-mux instance; see tests/e2e.test.mjs\n                  # — the repo-level harness at `tests/e2e/run.sh` boots a\n                  # wss-mux binary and exports the env vars this suite reads.\n```\n\n## License\n\nMIT OR Apache-2.0.\n","readmeFilename":"README.md"}