{"_id":"@chronista-club/unison-client","_rev":"6-ec6b4c14bef6cd3c6dd12372efa5817a","name":"@chronista-club/unison-client","dist-tags":{"latest":"1.2.0"},"versions":{"1.0.0-rc.1":{"name":"@chronista-club/unison-client","version":"1.0.0-rc.1","keywords":["unison","protocol","quic","webtransport","rpc","streaming","polyglot","type-safe"],"license":"MIT","_id":"@chronista-club/unison-client@1.0.0-rc.1","maintainers":[{"name":"mako357","email":"mito@chronista.club"}],"homepage":"https://github.com/chronista-club/club-unison/tree/main/clients/typescript","bugs":{"url":"https://github.com/chronista-club/club-unison/issues"},"dist":{"shasum":"bfc86984dd1607df312948fcf46d49d30bcc19ae","tarball":"https://registry.npmjs.org/@chronista-club/unison-client/-/unison-client-1.0.0-rc.1.tgz","fileCount":50,"integrity":"sha512-xvIX7y4xylb15E2TNRkmnbkKIOo9Z86aSSQ87z1NneJTqigkK1G5/Hlh8svGlRyK/TZNTYJppkJxizCX/Q4sdg==","signatures":[{"sig":"MEQCIGit8OaAxI66lxb0u3ronOmIEFhReNqzN6eeiqfqYUhPAiAI1sqq35cEbweap0X7aXpPtlTzaVBd9RahpRuxrQ66Sg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":397407},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"ff71980e2d738b06956a1ae73bd9dbbbfed34f39","scripts":{"dev":"vite","test":"vitest run","bench":"vitest bench","build":"vite build && tsc --emitDeclarationOnly --outDir dist","clean":"rm -rf dist coverage node_modules/.vite","example":"vite-node examples/vp-dashboard.ts","typecheck":"tsc --noEmit && tsc -p tsconfig.test.json","test:watch":"vitest"},"_npmUser":{"name":"mako357","email":"mito@chronista.club"},"repository":{"url":"git+https://github.com/chronista-club/club-unison.git","type":"git","directory":"clients/typescript"},"_npmVersion":"10.9.7","description":"TypeScript client SDK for the Unison protocol (= polyglot client base, server stays Rust)","directories":{},"_nodeVersion":"22.22.2","dependencies":{"@bufbuild/protobuf":"^2.12.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^6.0.0","vitest":"^3.0.0","typescript":"^5.7.0","@types/node":"^22.0.0","@fails-components/webtransport":"^1.6.2","@fails-components/webtransport-transport-http3-quiche":"^1.6.2"},"_npmOperationalInternal":{"tmp":"tmp/unison-client_1.0.0-rc.1_1778962267032_0.7391359727487292","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@chronista-club/unison-client","version":"1.0.0","keywords":["unison","protocol","quic","webtransport","rpc","streaming","polyglot","type-safe"],"license":"MIT","_id":"@chronista-club/unison-client@1.0.0","maintainers":[{"name":"mako357","email":"mito@chronista.club"}],"homepage":"https://github.com/chronista-club/club-unison/tree/main/clients/typescript","bugs":{"url":"https://github.com/chronista-club/club-unison/issues"},"dist":{"shasum":"dc7967469587d53113e14da050ae0f051f1ec9ce","tarball":"https://registry.npmjs.org/@chronista-club/unison-client/-/unison-client-1.0.0.tgz","fileCount":51,"integrity":"sha512-DG/VycdP3MYHi6itd78exCnBE+UPtO5X4UV22DtHrWXBW+HMD2pf8l9+F5uY4vwbQcN1NJJDiB4bjXQKhi6SPg==","signatures":[{"sig":"MEUCIQCAcL4fjIZhpo3nk4+yoo5NT/o/srCFxAs32cSdlaLe0QIgY/ZTtoGXvPHXhVUAqVAccQPYPzQsRrm6NmguI9TmpdY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":398453},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"e6c3f8790f3746911a7cf14607ffbb3fc6452c96","scripts":{"dev":"vite","test":"vitest run","bench":"vitest bench","build":"vite build && tsc --emitDeclarationOnly --outDir dist","clean":"rm -rf dist coverage node_modules/.vite","example":"vite-node examples/vp-dashboard.ts","typecheck":"tsc --noEmit && tsc -p tsconfig.test.json","test:watch":"vitest"},"_npmUser":{"name":"mako357","email":"mito@chronista.club"},"repository":{"url":"git+https://github.com/chronista-club/club-unison.git","type":"git","directory":"clients/typescript"},"_npmVersion":"10.9.7","description":"TypeScript client SDK for the Unison protocol (= polyglot client base, server stays Rust)","directories":{},"_nodeVersion":"22.22.2","dependencies":{"@bufbuild/protobuf":"^2.12.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^6.0.0","vitest":"^3.0.0","typescript":"^5.7.0","@types/node":"^22.0.0","@fails-components/webtransport":"^1.6.2","@fails-components/webtransport-transport-http3-quiche":"^1.6.2"},"_npmOperationalInternal":{"tmp":"tmp/unison-client_1.0.0_1779713139161_0.021039357640079137","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@chronista-club/unison-client","version":"1.1.0","keywords":["unison","protocol","quic","webtransport","channel","streaming","polyglot","type-safe"],"license":"MIT","_id":"@chronista-club/unison-client@1.1.0","maintainers":[{"name":"mako357","email":"mito@chronista.club"}],"homepage":"https://github.com/chronista-club/club-unison/tree/main/clients/typescript","bugs":{"url":"https://github.com/chronista-club/club-unison/issues"},"dist":{"shasum":"2b13bf3ab1887e4ed8bad43c226eee729fde7277","tarball":"https://registry.npmjs.org/@chronista-club/unison-client/-/unison-client-1.1.0.tgz","fileCount":61,"integrity":"sha512-j5a4GWdpTYRWK7TSOJo7oBYpSgO0Pz3JUVyTU+ShnJ0zNhklWGwzfvF8r9SQDMPWJxMgg2SqkA+7IOXk7qRk5g==","signatures":[{"sig":"MEQCIB89eN9w7DChtn/zw/zPUoftNbnwk74rkBgEiqefsMaYAiBQk9c1xFRwizUSbNdjZpFXPr+/XaeDdDEVoP5qdG4/Tg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":436674},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./testing":{"types":"./dist/testing/index.d.ts","import":"./dist/testing.js"}},"gitHead":"39cdf7630c9af5e864793ffce37627edba2d602b","scripts":{"dev":"vite","test":"vitest run","bench":"vitest bench","build":"vite build && tsc --emitDeclarationOnly --outDir dist","clean":"rm -rf dist coverage node_modules/.vite","example":"vite-node examples/vp-dashboard.ts","typecheck":"tsc --noEmit && tsc -p tsconfig.test.json","test:watch":"vitest"},"_npmUser":{"name":"mako357","email":"mito@chronista.club"},"repository":{"url":"git+https://github.com/chronista-club/club-unison.git","type":"git","directory":"clients/typescript"},"_npmVersion":"11.13.0","description":"TypeScript client SDK for the Unison protocol (= polyglot client base, server stays Rust)","directories":{},"_nodeVersion":"24.16.0","dependencies":{"@bufbuild/protobuf":"^2.12.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^6.0.0","vitest":"^3.0.0","typescript":"^5.7.0","@types/node":"^22.0.0","@fails-components/webtransport":"^1.6.2","@fails-components/webtransport-transport-http3-quiche":"^1.6.2"},"_npmOperationalInternal":{"tmp":"tmp/unison-client_1.1.0_1781114663694_0.08522029434904566","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"@chronista-club/unison-client","version":"1.1.1","keywords":["unison","protocol","quic","webtransport","channel","streaming","polyglot","type-safe"],"license":"MIT","_id":"@chronista-club/unison-client@1.1.1","maintainers":[{"name":"mako357","email":"mito@chronista.club"}],"homepage":"https://github.com/chronista-club/club-unison/tree/main/clients/typescript","bugs":{"url":"https://github.com/chronista-club/club-unison/issues"},"dist":{"shasum":"e20ebf372c2764aebfd8dbab2ca0497d72ff7f53","tarball":"https://registry.npmjs.org/@chronista-club/unison-client/-/unison-client-1.1.1.tgz","fileCount":61,"integrity":"sha512-nhm3hg5zgc86JQ0gefSNeMO7l1GIk8TxVCxtd1enQ9Zyxu/z6uAg0v/H2RoMQSVPssHtcGzjtn+S5ty1GDZVRw==","signatures":[{"sig":"MEYCIQDLMRKceV6zV6OVVS3O6NJExPMEWOqTbcqJdBuGCACEdAIhANzC546DzQqXa5l019Z1vRzB89FTEPF3VxwvfIXNvsK4","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":437792},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./testing":{"types":"./dist/testing/index.d.ts","import":"./dist/testing.js"}},"gitHead":"e4dd8eb2d91030e10e9e427e1a63b06b56cd9941","scripts":{"dev":"vite","test":"vitest run","bench":"vitest bench","build":"vite build && tsc --emitDeclarationOnly --outDir dist","clean":"rm -rf dist coverage node_modules/.vite","example":"vite-node examples/vp-dashboard.ts","typecheck":"tsc --noEmit && tsc -p tsconfig.test.json","test:watch":"vitest"},"_npmUser":{"name":"mako357","email":"mito@chronista.club"},"repository":{"url":"git+https://github.com/chronista-club/club-unison.git","type":"git","directory":"clients/typescript"},"_npmVersion":"10.9.8","description":"TypeScript client SDK for the Unison protocol (= polyglot client base, server stays Rust)","directories":{},"_nodeVersion":"22.22.3","dependencies":{"@bufbuild/protobuf":"^2.12.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^6.0.0","vitest":"^3.0.0","typescript":"^5.7.0","@types/node":"^22.0.0","@fails-components/webtransport":"^1.6.2","@fails-components/webtransport-transport-http3-quiche":"^1.6.2"},"_npmOperationalInternal":{"tmp":"tmp/unison-client_1.1.1_1781722557588_0.8369271584354083","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@chronista-club/unison-client","version":"1.2.0","description":"TypeScript client SDK for the Unison protocol (= polyglot client base, server stays Rust)","license":"MIT","type":"module","main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./testing":{"types":"./dist/testing/index.d.ts","import":"./dist/testing.js"}},"scripts":{"build":"vite build && tsc --emitDeclarationOnly --outDir dist","dev":"vite","test":"vitest run","test:watch":"vitest","bench":"vitest bench","example":"vite-node examples/vp-dashboard.ts","typecheck":"tsc --noEmit && tsc -p tsconfig.test.json","clean":"rm -rf dist coverage node_modules/.vite"},"engines":{"node":">=20.0.0"},"repository":{"type":"git","url":"git+https://github.com/chronista-club/club-unison.git","directory":"clients/typescript"},"homepage":"https://github.com/chronista-club/club-unison/tree/main/clients/typescript","bugs":{"url":"https://github.com/chronista-club/club-unison/issues"},"keywords":["unison","protocol","quic","webtransport","channel","streaming","polyglot","type-safe"],"publishConfig":{"access":"public"},"devDependencies":{"@fails-components/webtransport":"^1.6.2","@fails-components/webtransport-transport-http3-quiche":"^1.6.2","@types/node":"^22.0.0","typescript":"^5.7.0","vite":"^6.0.0","vitest":"^3.0.0"},"dependencies":{"@bufbuild/protobuf":"^2.12.0"},"gitHead":"915da57359341af4d2e6b2b91d4296b6efb5a56d","_id":"@chronista-club/unison-client@1.2.0","_nodeVersion":"24.16.0","_npmVersion":"11.13.0","dist":{"integrity":"sha512-X4wQJpU6w8R5UGgowH3uH1sh6NmygzaYNGH50++LuKgIs3lokAUi3gITqRsW5ZUzVzo3Nzt6lgT3HhQ0dLLmgg==","shasum":"82a4bfc3956af61c410c3b03bcd0432d8eacaea3","tarball":"https://registry.npmjs.org/@chronista-club/unison-client/-/unison-client-1.2.0.tgz","fileCount":63,"unpackedSize":449886,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIGNUfqzR4pt45KiQp8ysdPXhVoZakW2VhRDsmmnG0XrTAiAk5fHtwdjLI9SmY9qms7X4mPbfT2dkF0+C1dwRW9JImw=="}]},"_npmUser":{"name":"mako357","email":"mito@chronista.club"},"directories":{},"maintainers":[{"name":"mako357","email":"mito@chronista.club"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/unison-client_1.2.0_1782556507563_0.9302838884969298"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-16T20:11:06.913Z","modified":"2026-06-27T10:35:07.827Z","1.0.0-rc.1":"2026-05-16T20:11:07.165Z","1.0.0":"2026-05-25T12:45:39.328Z","1.1.0":"2026-06-10T18:04:23.823Z","1.1.1":"2026-06-17T18:55:57.721Z","1.2.0":"2026-06-27T10:35:07.719Z"},"bugs":{"url":"https://github.com/chronista-club/club-unison/issues"},"license":"MIT","homepage":"https://github.com/chronista-club/club-unison/tree/main/clients/typescript","keywords":["unison","protocol","quic","webtransport","channel","streaming","polyglot","type-safe"],"repository":{"type":"git","url":"git+https://github.com/chronista-club/club-unison.git","directory":"clients/typescript"},"description":"TypeScript client SDK for the Unison protocol (= polyglot client base, server stays Rust)","maintainers":[{"name":"mako357","email":"mito@chronista.club"}],"readme":"# @chronista-club/unison-client\n\n> TypeScript client SDK for the [Unison protocol](https://github.com/chronista-club/club-unison).\n> Part of the **v1.0 polyglot client base** (= server stays Rust, client polyglot for adoption surface).\n\n**Status**: `1.1.1` — v1.0 GA + `/testing` subpath. Protocol API is frozen and the SDK is shipped to npm. It talks to the Rust server over **real WebTransport** (verified by `tests/integration/webtransport_e2e.test.ts`). See [design/typescript-client-api.md](../../design/typescript-client-api.md) for the SDK design contract.\n\n---\n\n## What this is\n\nUnison is a KDL schema-driven, QUIC-based protocol with both **stream channels** (request/response + event) and **datagram channels** (broadcast event). The Rust crate `club-unison` ships the server and Rust client. This package is the **TypeScript client SDK** that lets:\n\n- **Browsers** (via [WebTransport](https://www.w3.org/TR/webtransport/)) speak unison directly to a Rust server (= no REST gateway)\n- **Node.js** clients connect server-to-server in TypeScript (= optional, v1.x)\n\nThe asymmetric design — **fat Rust server, thin polyglot clients** — keeps complexity (TLS, accept loops, connection management) in one language while broadening the adoption surface.\n\n## v1.0 status (= what shipped)\n\nThe v1.0 sprint is feature-complete. All phases are done:\n\n- **Phase 1** ✅ — KDL-driven TypeScript code generation (type interfaces + channel metadata)\n- **Phase 2a-e** ✅ — Package skeleton, WebTransport transport adapter, channel wrappers\n  (`UnisonChannel<M>` / `DatagramChannel<M>`), codecs (`JsonCodec` + `ProtoCodec`), tests + bundle build\n- **Phase 3** ✅ — `connect()` facade + Vantage Point dashboard proof point demo\n- **Phase 4-5** ✅ — `unison` developer CLI (ping / sniff / mock / schema-lint), `ErrorCategory` framework\n- **Phase 6** ✅ — Rust-compatible wire format + **real WebTransport E2E** (TS SDK ↔ Rust server)\n- **Phase 7** ✅ — Cross-language E2E integration tests in CI\n- **Phase 8** ✅ — User-facing docs (this file + the guides below)\n\nWhat is **v1.x deferred** (honest gaps):\n\n- TypeScript codegen for datagram channels (Rust codegen has it; TS handwrites the meta for now)\n- proto-descriptor codegen (`ProtoCodec` works, but KDL → descriptor generation is not automated)\n- Node native WebTransport (Node needs the `@fails-components/webtransport` polyfill)\n- Safari / Firefox WebTransport (Chromium-based browsers are the official support matrix)\n- per-channel codec override, auto-reconnect helper\n\nSee [`design/typescript-client-api.md`](../../design/typescript-client-api.md) for the full API design contract.\n\n## Quickstart\n\nFor the full end-to-end walkthrough (KDL schema → Rust server → TS client), see\n[`guides/quickstart.md`](../../guides/quickstart.md). API reference:\n[`guides/typescript-sdk.md`](../../guides/typescript-sdk.md).\n\n```typescript\nimport { connect, type ChannelMeta } from \"@chronista-club/unison-client\";\n\nconst EchoMeta = {\n  name: \"echo\",\n  backend: \"stream\",\n  from: \"client\",\n  lifetime: \"persistent\",\n  events: [],\n  requests: { Echo: { request: \"EchoReq\", response: \"EchoResp\" } },\n} as const satisfies ChannelMeta;\n\n// Connect — cert pinning for a dev self-signed server (loopback only).\nconst client = await connect({\n  url: \"https://127.0.0.1:4439\",\n  trust: { certHash: \"<CERT_HASH printed by the server>\" },\n  awaitIdentity: false,\n});\n\nconst echo = await client.openChannel(EchoMeta);\nconst reply = await echo.request(\"Echo\", { text: \"hello-unison\" });\nconsole.log(reply); // { text: \"hello-unison\" }\n\nawait echo.close();\nawait client.disconnect();\n```\n\n## Testing utilities (`/testing` subpath)\n\nDrive the SDK end-to-end without a real WebTransport stack or a Rust server —\n`MockTransport` pairs in-memory endpoints and `StreamServerStub` speaks the same\nbyte-compatible frame protocol as the Rust server:\n\n```typescript\nimport { connect } from \"@chronista-club/unison-client\";\nimport {\n  MockTransport,\n  StreamServerStub,\n} from \"@chronista-club/unison-client/testing\";\n\nconst transport = new MockTransport();\nconst { server } = transport.prepare(); // server-side endpoint of the memory pipe\n\nconst client = await connect({\n  url: \"https://mock.local\", // any URL — never dialed with a mock transport\n  transport,\n  awaitIdentity: false,\n});\n\n// Server side: accept the stream and answer with an echo handler.\nconst serverSide = (async () => {\n  const accepted = await server.acceptStream();\n  if (accepted.done) throw new Error(\"no stream\");\n  return new StreamServerStub(accepted.value, (_method, payload) => payload);\n})();\n```\n\n`examples/vp-dashboard.ts` and `tests/integration/beta_freeze.test.ts` show the\nfull pattern (datagram channels, identity handshake via `sendIdentity`, nack\ninjection with `rejectOpen`).\n\nThe SDK's own integration tests (`tests/integration/`) import the same module,\nso the published harness can never drift from what CI verifies.\n\n## Architecture\n\n```\nclients/typescript/\n├── src/\n│   ├── index.ts           ← public entry (= re-exports the surface below)\n│   ├── client.ts          ← connect() + UnisonClient facade\n│   ├── transport/         ← WebTransport adapter\n│   ├── channel/           ← UnisonChannel / DatagramChannel + dispatcher + frame\n│   ├── codec/             ← JsonCodec + ProtoCodec\n│   ├── wire/              ← Rust-compatible packet / protocol-message encode/decode\n│   ├── error/             ← ErrorCategory framework\n│   └── testing/           ← /testing subpath (MockTransport + StreamServerStub)\n├── examples/              ← vp-dashboard.ts (Vantage Point proof point demo)\n├── tests/                 ← vitest unit + integration tests (incl. real WebTransport E2E)\n├── package.json\n├── tsconfig.json\n├── vite.config.ts\n└── vitest.config.ts\n```\n\n## Building from source\n\n```bash\ncd clients/typescript\nnpm install            # install dev deps (typescript / vite / vitest)\nnpm run build          # vite build → dist/index.js + tsc → dist/index.d.ts\nnpm test               # vitest run\nnpm run typecheck      # tsc --noEmit (= type safety verification)\n```\n\n## Versioning policy\n\n- TS package version is kept in **major.minor sync** with the Rust crate `club-unison`\n- `1.1.0` (current) — adds the `/testing` subpath + channel util re-exports; protocol API remains frozen since `1.0.0`; breaking changes to the public surface require v2.0\n- `1.x.0` — additive features (channels, codecs, error codes) that preserve API compatibility\n- `1.0.x` — patch fixes\n\n## Compatibility\n\n| Component | Required |\n|---|---|\n| Browser | Chromium-based 95+ (= WebTransport native) |\n| Node.js | 20+ (= ESM + modern features) |\n| TypeScript | 5.7+ (= consumer's tsconfig.json target) |\n| Rust server | `club-unison` major.minor 一致 |\n\nSafari / Firefox WebTransport support: tracked in v1.x roadmap, polyfill via WebSocket fallback is deferred to caller demand.\n\n## License\n\nMIT — see [LICENSE](./LICENSE) (bundled) or [LICENSE](../../LICENSE) in the repository root.\n\n## Contributing\n\nThis SDK is part of the `chronista-club/club-unison` monorepo. Issues + PRs at https://github.com/chronista-club/club-unison.\n","readmeFilename":"README.md"}