{"_id":"@antseed/web-sdk","_rev":"5-ef81b083675c0104946b3f0ab4114446","name":"@antseed/web-sdk","dist-tags":{"latest":"0.1.4"},"versions":{"0.1.0":{"name":"@antseed/web-sdk","version":"0.1.0","_id":"@antseed/web-sdk@0.1.0","maintainers":[{"name":"shahafan","email":"santwarg@gmail.com"}],"dist":{"shasum":"e1fc1e709c2fd199bc7262d7dc82c06f281b6180","tarball":"https://registry.npmjs.org/@antseed/web-sdk/-/web-sdk-0.1.0.tgz","fileCount":31,"integrity":"sha512-rLHiwVwMhhMD94th2c9SMU92iM4N0RkNZGQV9S7cEs5DdiotHXpasHZ0+Ig464yHvV3XuZEdxAfmL9ta3LztSg==","signatures":[{"sig":"MEUCIQDulvU5W6HWfQuqx6fTUBYQk2cgVvcFuAFwPiGV8EKZBAIgL3w9QS6G6iWsyA3htNrCH23rt4Ns5nL6sweAG5Ojupc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":170878},"main":"dist/index.js","type":"module","_from":"file:antseed-web-sdk-0.1.0.tgz","types":"dist/index.d.ts","scripts":{"test":"vitest run src","build":"tsc","example":"esbuild examples/main.ts --bundle --format=esm --outdir=examples/dist --servedir=examples --serve=127.0.0.1:8974","prebuild":"node ../../scripts/remove-paths.mjs dist","typecheck":"tsc --noEmit","test:browser":"playwright test --config browser-e2e/playwright.config.ts","build:example":"esbuild examples/main.ts --bundle --format=esm --outdir=examples/dist"},"_npmUser":{"name":"shahafan","email":"santwarg@gmail.com"},"_resolved":"/tmp/c4c8c8b489da704c3fb27d8ad3170442/antseed-web-sdk-0.1.0.tgz","_integrity":"sha512-rLHiwVwMhhMD94th2c9SMU92iM4N0RkNZGQV9S7cEs5DdiotHXpasHZ0+Ig464yHvV3XuZEdxAfmL9ta3LztSg==","_npmVersion":"10.8.2","description":"Browser buyer SDK for AntSeed: connect to sellers over WebRTC via a signaling relay, pay with in-browser EIP-712 signatures","directories":{},"_nodeVersion":"20.20.2","dependencies":{"ethers":"~6.16.0","@antseed/protocol":"0.1.4","@antseed/buyer-core":"0.1.6"},"_hasShrinkwrap":false,"devDependencies":{"ws":"^8.18.0","vite":"^5.4.0","vitest":"^2.0.0","esbuild":"^0.25.0","@types/ws":"^8.5.12","typescript":"^5.5.0","@types/node":"^20.11.0","@antseed/node":"0.2.114","fake-indexeddb":"^6.2.2","@playwright/test":"^1.55.0","node-datachannel":"^0.7.0"},"_npmOperationalInternal":{"tmp":"tmp/web-sdk_0.1.0_1787134521531_0.6719771769343035","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@antseed/web-sdk","version":"0.1.1","_id":"@antseed/web-sdk@0.1.1","maintainers":[{"name":"shahafan","email":"santwarg@gmail.com"}],"dist":{"shasum":"cc6f584a8ffa579049937e6724840f9721f8bb80","tarball":"https://registry.npmjs.org/@antseed/web-sdk/-/web-sdk-0.1.1.tgz","fileCount":31,"integrity":"sha512-MMHd2R5wqL9slHv7Vb7UDaQmDn4WCoh3u7OPPkWx8+q2Vl5Mp5rC8JIYp+7ZXZtxqZ/VqxtydDeSRiAm/NxmrQ==","signatures":[{"sig":"MEUCIQDL1DgpyVNV/P+ZJDkFo25ThpNKDurxaJH2YxP4CZmDCgIgag1trKX9C9X+BPNxydxKRd81buN3xaIm90CHXrHHI1M=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":170878},"main":"dist/index.js","type":"module","_from":"file:antseed-web-sdk-0.1.1.tgz","types":"dist/index.d.ts","scripts":{"test":"vitest run src","build":"tsc","example":"esbuild examples/main.ts --bundle --format=esm --outdir=examples/dist --servedir=examples --serve=127.0.0.1:8974","prebuild":"node ../../scripts/remove-paths.mjs dist","typecheck":"tsc --noEmit","test:browser":"playwright test --config browser-e2e/playwright.config.ts","build:example":"esbuild examples/main.ts --bundle --format=esm --outdir=examples/dist"},"_npmUser":{"name":"shahafan","email":"santwarg@gmail.com"},"_resolved":"/tmp/926316a13db1e9cac63426bca0b6bb67/antseed-web-sdk-0.1.1.tgz","_integrity":"sha512-MMHd2R5wqL9slHv7Vb7UDaQmDn4WCoh3u7OPPkWx8+q2Vl5Mp5rC8JIYp+7ZXZtxqZ/VqxtydDeSRiAm/NxmrQ==","_npmVersion":"10.8.2","description":"Browser buyer SDK for AntSeed: connect to sellers over WebRTC via a signaling relay, pay with in-browser EIP-712 signatures","directories":{},"_nodeVersion":"20.20.2","dependencies":{"ethers":"~6.16.0","@antseed/protocol":"0.1.4","@antseed/buyer-core":"0.1.7"},"_hasShrinkwrap":false,"devDependencies":{"ws":"^8.18.0","vite":"^5.4.0","vitest":"^2.0.0","esbuild":"^0.25.0","@types/ws":"^8.5.12","typescript":"^5.5.0","@types/node":"^20.11.0","@antseed/node":"0.2.115","fake-indexeddb":"^6.2.2","@playwright/test":"^1.55.0","node-datachannel":"^0.7.0"},"_npmOperationalInternal":{"tmp":"tmp/web-sdk_0.1.1_1787228350692_0.6482820320900378","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@antseed/web-sdk","version":"0.1.2","_id":"@antseed/web-sdk@0.1.2","maintainers":[{"name":"shahafan","email":"santwarg@gmail.com"}],"dist":{"shasum":"cd47f0bcb6a4c2c43c2a9db8779ed4b6273aa2db","tarball":"https://registry.npmjs.org/@antseed/web-sdk/-/web-sdk-0.1.2.tgz","fileCount":31,"integrity":"sha512-ab9ZtXjUyTmGqBHUFdjq+Pg6jrmKQ3czdcPN4/SFZUJATTEPjXFONF1xE0L6PrmvwBoOHI3XYcr4PdJ/1wyoAQ==","signatures":[{"sig":"MEUCIAU/56M3sdNJKwAIhdPW61xqNPv82oL1CiRFt+9UP2FdAiEAmHKNiqMQp36Buh2DBg/CeFxsPg5jXD6efV+3KuFga3k=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":170878},"main":"dist/index.js","type":"module","_from":"file:antseed-web-sdk-0.1.2.tgz","types":"dist/index.d.ts","scripts":{"test":"vitest run src","build":"tsc","example":"esbuild examples/main.ts --bundle --format=esm --outdir=examples/dist --servedir=examples --serve=127.0.0.1:8974","prebuild":"node ../../scripts/remove-paths.mjs dist","typecheck":"tsc --noEmit","test:browser":"playwright test --config browser-e2e/playwright.config.ts","build:example":"esbuild examples/main.ts --bundle --format=esm --outdir=examples/dist"},"_npmUser":{"name":"shahafan","email":"santwarg@gmail.com"},"_resolved":"/tmp/a40ef92f6032911c7110634e509df430/antseed-web-sdk-0.1.2.tgz","_integrity":"sha512-ab9ZtXjUyTmGqBHUFdjq+Pg6jrmKQ3czdcPN4/SFZUJATTEPjXFONF1xE0L6PrmvwBoOHI3XYcr4PdJ/1wyoAQ==","_npmVersion":"10.8.2","description":"Browser buyer SDK for AntSeed: connect to sellers over WebRTC via a signaling relay, pay with in-browser EIP-712 signatures","directories":{},"_nodeVersion":"20.20.2","dependencies":{"ethers":"~6.16.0","@antseed/protocol":"0.1.4","@antseed/buyer-core":"0.1.8"},"_hasShrinkwrap":false,"devDependencies":{"ws":"^8.18.0","vite":"^5.4.0","vitest":"^2.0.0","esbuild":"^0.25.0","@types/ws":"^8.5.12","typescript":"^5.5.0","@types/node":"^20.11.0","@antseed/node":"0.2.117","fake-indexeddb":"^6.2.2","@playwright/test":"^1.55.0","node-datachannel":"^0.7.0"},"_npmOperationalInternal":{"tmp":"tmp/web-sdk_0.1.2_1787858919536_0.01591927084752154","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@antseed/web-sdk","version":"0.1.3","_id":"@antseed/web-sdk@0.1.3","maintainers":[{"name":"shahafan","email":"santwarg@gmail.com"}],"dist":{"shasum":"e06fb8d8869e47dabd43381bbb85b23358caeae1","tarball":"https://registry.npmjs.org/@antseed/web-sdk/-/web-sdk-0.1.3.tgz","fileCount":31,"integrity":"sha512-tIQwBqVH4J1cE2wMYYEpiCtmsX+W0xmtu9ugrvcvuiCHqDaSrhmn/tCKUcOR9oOPdiQHzQgVjf3NYQ/kWMtZeA==","signatures":[{"sig":"MEUCIQCM5l05uoWrFy07yOi40sB2UBHk6KP17y1GSw9qaoXsDAIgWF1C4NesGyZstxjBe9g6p5lp+weFojat8NcZVazde5k=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":170878},"main":"dist/index.js","type":"module","_from":"file:antseed-web-sdk-0.1.3.tgz","types":"dist/index.d.ts","scripts":{"test":"vitest run src","build":"tsc","example":"esbuild examples/main.ts --bundle --format=esm --outdir=examples/dist --servedir=examples --serve=127.0.0.1:8974","prebuild":"node ../../scripts/remove-paths.mjs dist","typecheck":"tsc --noEmit","test:browser":"playwright test --config browser-e2e/playwright.config.ts","build:example":"esbuild examples/main.ts --bundle --format=esm --outdir=examples/dist"},"_npmUser":{"name":"shahafan","email":"santwarg@gmail.com"},"_resolved":"/tmp/5869945c9d6f8c06d583570dfa2a5146/antseed-web-sdk-0.1.3.tgz","_integrity":"sha512-tIQwBqVH4J1cE2wMYYEpiCtmsX+W0xmtu9ugrvcvuiCHqDaSrhmn/tCKUcOR9oOPdiQHzQgVjf3NYQ/kWMtZeA==","_npmVersion":"10.8.2","description":"Browser buyer SDK for AntSeed: connect to sellers over WebRTC via a signaling relay, pay with in-browser EIP-712 signatures","directories":{},"_nodeVersion":"20.20.2","dependencies":{"ethers":"~6.16.0","@antseed/protocol":"0.1.4","@antseed/buyer-core":"0.1.9"},"_hasShrinkwrap":false,"devDependencies":{"ws":"^8.18.0","vite":"^5.4.0","vitest":"^2.0.0","esbuild":"^0.25.0","@types/ws":"^8.5.12","typescript":"^5.5.0","@types/node":"^20.11.0","@antseed/node":"0.2.118","fake-indexeddb":"^6.2.2","@playwright/test":"^1.55.0","node-datachannel":"^0.7.0"},"_npmOperationalInternal":{"tmp":"tmp/web-sdk_0.1.3_1788934395979_0.9596292680491338","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"_id":"@antseed/web-sdk@0.1.4","dist":{"shasum":"bcd821a53fb58feeb304db9397b9322fbbb9a675","tarball":"https://registry.npmjs.org/@antseed/web-sdk/-/web-sdk-0.1.4.tgz","fileCount":31,"integrity":"sha512-pbN6LIbnbLT0R1WcoYRI9WS1ISv3+Pv7HrFh1ymdzqxJ5feLHaASl8r9nZSVYg65rvfukHpJOYBmomvEmswDTQ==","signatures":[{"sig":"MEQCIADnMN5b+JveSs8hQEheLFc/siShsAHGQeh0FnbOcE0LAiAFv2TT8NegUcMNGPyfkmdxNb5c4w7f2Cgac7Dr3y57vA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQC04HEoC4bEKBoTDG2m8COYjgVnBETngfBd3qj8SaFhrwIgAayfCM6d2bkrrIpKCvOg64g79NJjeLhTmfWxVly2SkI="}],"unpackedSize":170879},"main":"dist/index.js","name":"@antseed/web-sdk","type":"module","_from":"file:antseed-web-sdk-0.1.4.tgz","types":"dist/index.d.ts","scripts":{"test":"vitest run src","build":"tsc","example":"esbuild examples/main.ts --bundle --format=esm --outdir=examples/dist --servedir=examples --serve=127.0.0.1:8974","prebuild":"node ../../scripts/remove-paths.mjs dist","typecheck":"tsc --noEmit","test:browser":"playwright test --config browser-e2e/playwright.config.ts","build:example":"esbuild examples/main.ts --bundle --format=esm --outdir=examples/dist"},"version":"0.1.4","_npmUser":{"name":"shahafan","email":"santwarg@gmail.com"},"_resolved":"/tmp/504dd245d4a64f8daee0827be46623f9/antseed-web-sdk-0.1.4.tgz","_integrity":"sha512-pbN6LIbnbLT0R1WcoYRI9WS1ISv3+Pv7HrFh1ymdzqxJ5feLHaASl8r9nZSVYg65rvfukHpJOYBmomvEmswDTQ==","_npmVersion":"11.19.0","description":"Browser buyer SDK for AntSeed: connect to sellers over WebRTC via a signaling relay, pay with in-browser EIP-712 signatures","directories":{},"maintainers":[{"name":"shahafan","email":"santwarg@gmail.com"}],"_nodeVersion":"24.21.0","dependencies":{"ethers":"~6.16.0","@antseed/protocol":"0.1.4","@antseed/buyer-core":"0.1.10"},"_hasShrinkwrap":false,"devDependencies":{"ws":"^8.18.0","vite":"^5.4.0","vitest":"^2.0.0","esbuild":"^0.25.0","@types/ws":"^8.5.12","typescript":"^5.5.0","@types/node":"^20.11.0","@antseed/node":"0.2.119","fake-indexeddb":"^6.2.2","@playwright/test":"^1.55.0","node-datachannel":"^0.7.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/web-sdk_0.1.4_1789637775842_0.09847565208701292"}}},"time":{"created":"2026-08-19T10:15:21.232Z","modified":"2026-09-17T09:36:16.107Z","0.1.0":"2026-08-19T10:15:21.668Z","0.1.1":"2026-08-20T12:19:10.836Z","0.1.2":"2026-08-27T19:28:39.680Z","0.1.3":"2026-09-09T06:13:16.120Z","0.1.4":"2026-09-17T09:36:15.952Z"},"description":"Browser buyer SDK for AntSeed: connect to sellers over WebRTC via a signaling relay, pay with in-browser EIP-712 signatures","maintainers":[{"name":"shahafan","email":"santwarg@gmail.com"}],"readme":"# @antseed/web-sdk\n\nBrowser buyer SDK for AntSeed. Connects to unmodified sellers over WebRTC\nDataChannels (signaled through an [@antseed/relay](../../apps/relay)) and pays\nper request with in-browser EIP-712 signatures. No native modules; the only\nruntime dependency is ethers.\n\n```ts\nimport { AntseedWebClient } from '@antseed/web-sdk';\n\nconst client = await AntseedWebClient.create({\n  relayUrl: 'https://relay.example.com',\n  privateKey: buyerHotWalletKey,        // peerId = its EVM address\n  connection: {\n    iceServers: [\n      { urls: 'stun:stun.example.com' },\n      { urls: 'turns:turn.example.com', username, credential },\n    ],\n    onConnectionInfo: ({ path }) => showPath(path), // direct | relay | unknown\n  },\n});\n\nconst sellers = await client.sellers();\nconst session = await client.connect(sellers[0].peerId);\n\nconst response = await session.request(\n  {\n    path: '/v1/chat/completions',\n    provider: 'openai',\n    headers: { accept: 'text/event-stream' },\n    body: JSON.stringify({ model: 'gpt-oss-120b', stream: true, messages: [...] }),\n  },\n  { onChunk: (data, done) => render(new TextDecoder().decode(data)) },\n);\n```\n\n## Example page\n\nA working single-page example (seller discovery, connect, streaming chat)\nlives in [`examples/example.html`](examples/example.html):\n\n```bash\npnpm --filter @antseed/web-sdk run example\n# open http://127.0.0.1:8974/example.html\n```\n\nIt expects a reachable relay (`node apps/relay/dist/index.js`, default port\n8917 — use `RELAY_STATIC_SELLERS=<peerId>@<host>:<port>` to pin a local\nseller) and works unfunded against sellers that accept free requests.\n\n## Durable channel state and multiple tabs\n\nBy default the client uses an in-memory channel store: on reload the latest\nsigned SpendingAuth state is gone and reserved funds stay locked until the\nsession deadline passes. Production apps should inject a durable store:\n\n```ts\nconst client = new AntseedWebClient({ relayUrl, wallet, channelStore: myStore });\n```\n\n`channelStore` takes any `BuyerChannelStore` (re-exported here). For\ncrash-safety implement the optional `flush()`: it is awaited after each newly\nsigned authorization is persisted and *before* it is transmitted, so it must\nnot resolve until the write is durably committed (e.g. IndexedDB behind a\nsynchronous in-memory cache). If several tabs can share the store, the\nimplementation must also serialize signing (e.g. `navigator.locks`) —\nSpendingAuth amounts are cumulative per channel, and two tabs signing\nconcurrently corrupt the sequence. Without a shared store, each tab opens its\nown channel and reserves its own budget.\n\n## ICE / TURN configuration\n\n`connection.iceServers` accepts bare URL strings or full `RTCIceServer`\nentries (for TURN credentials); `connection.iceTransportPolicy: 'relay'`\nforces TURN-only paths. `connection.onConnectionInfo` reports the selected\npath (`'direct' | 'relay' | 'unknown'`) once connected, without exposing\naddresses or raw candidates.\n\n## Architecture\n\nThis package contains only the browser-specific pieces: relay signaling\n(`hello` envelope, SDP offer, trickle ICE), the `RTCPeerConnection`\ntransport, keepalive, channel-store adapters, and cross-tab coordination.\nEverything else is shared code, not a reimplementation. Production clients\nuse an IndexedDB store; the in-memory store remains available only through\nthe explicit `ephemeral()` API:\n\n- **@antseed/protocol** — wire format: message types, frame/HTTP/payment\n  codecs, EIP-712 payment signatures, connection auth. Same modules\n  @antseed/node runs.\n- **@antseed/buyer-core** — the buyer machinery: `BuyerRequestHandler`,\n  `BuyerPaymentManager`, `BuyerPaymentNegotiator`, `ProxyMux`/`PaymentMux`.\n  The exact classes behind the node/CLI buyer proxy, wired here to a WebRTC\n  DataChannel and the configured channel store (in-memory by default).\n\nSo 402 negotiation, ReserveAuth/AuthAck, NeedAuth cost validation, cumulative\nSpendingAuth metadata, streaming, and chunked uploads behave identically to\nthe node buyer. One browser-specific override: uploads chunk above 192 KiB\n(not 512 KiB) to stay under the ~256 KiB SCTP message ceiling browsers\nnegotiate with libdatachannel sellers. Defaults target Base mainnet; override\n`payment.*` for other chains.\n\nThe relay bridge is closed as soon as the DataChannel opens — it is only\nneeded for signaling, and holding it would consume the relay's per-IP bridge\nslots. There is no re-signaling path; a dropped DataChannel means a fresh\n`connect()`.\n\n## Persistence and multiple tabs\n\n`AntseedWebClient.create()` is asynchronous because it acquires an exclusive\nWeb Lock for the buyer identity and hydrates IndexedDB before the payment\nmanager may sign. Only one tab can use a buyer on the same chain/channels\ncontract at a time. A second tab fails with `BuyerAlreadyActiveError` by\ndefault; set `persistence.waitForLock` to wait instead. A crashed tab releases\nits Web Lock automatically, and its successor recovers the last durably\ncommitted channel state.\n\nEvery ReserveAuth and SpendingAuth is committed to IndexedDB before it is\nsent. The database contains channel identifiers, signatures, cumulative\namounts, metadata, and recovery context, but never the buyer private key.\nUse `onPersistenceError` to surface background failures from ordinary\nstatus/accounting writes immediately; awaited authorization commits and\n`close()` also reject when persistence is unhealthy.\nCall `await client.close()` when the application is done to flush storage and\nrelease the lock. Page-unload handlers are not a channel recovery mechanism.\n\n`AntseedWebClient.ephemeral()` retains in-memory behavior for tests and free\ninteroperability experiments. It must not be used for paid traffic because a\nreload loses its channel state and it provides no multi-tab exclusion.\n\n`SellerSession.close()` closes only the WebRTC transport. Use\n`await session.closeChannel()` to request cooperative settlement from a\nsupporting seller. `client.listActiveChannels()` exposes locally unresolved\nchannels for recovery UI. If the seller is unavailable, call\n`session.requestOnChainClose(operatorSigner)` and, after the contract grace\nperiod, `session.withdrawTimedOutChannel(operatorSigner)`. The signer must be\nthe operator configured for the buyer in AntseedDeposits; the SDK does not\nassume that the browser wallet or any particular backend owns that role.\n\nThe relay verifies DHT metadata before caching it, and the SDK rejects a\nnon-empty seller snapshot older than `maxSellerSnapshotAgeMs` (15 minutes by\ndefault) before normalizing it into the shared buyer pricing/capability view.\nThe relay remains a trusted discovery-availability boundary; connection auth,\nseller response authentication, and payment signatures remain end to end.\n\n## Known limitation: large non-streamed responses\n\nChunking currently protects the upload direction only. A seller sends a\nnon-streamed response body as a single DataChannel message, and browsers cap\nreceived SCTP messages at ~256 KiB — a larger response (e.g. base64 image\noutput) will kill the DataChannel. Until seller-side response chunking\nexists, prefer streaming (`accept: text/event-stream`) for potentially large\nresponses.\n\n## Prerequisites for paying sellers\n\nThe buyer address must have USDC deposited in AntseedDeposits (directly or\nvia the gasless EIP-3009 sweep). Deposit UX is out of scope for this SDK.\n\n## Testing\n\n`vitest run` covers byte-for-byte parity with `@antseed/node` (hello\nenvelope, frame codec, EIP-712 signatures, metadata hashing) and an\nend-to-end suite that drives the real `@antseed/node` seller listener through\na real relay instance, with `node-datachannel/polyfill` standing in for the\nbrowser's `RTCPeerConnection`. `pnpm run test:browser` additionally launches\nreal Chromium and Firefox runtimes, connects their native WebRTC stacks to an\nunchanged seller through the relay, and verifies multi-tab exclusion plus\ncrash takeover. The browser suite also completes paid 402 negotiation, verifies\nthe EIP-712 authorizations, reloads IndexedDB, simulates lost seller state, and\nrecovers the same on-chain channel without issuing a second reserve.\n","readmeFilename":"README.md"}