{"_id":"@cioky/remult-partykit","_rev":"2-4535c001fdb9a4fd6234b54897f4c3eb","name":"@cioky/remult-partykit","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@cioky/remult-partykit","version":"0.1.0","_id":"@cioky/remult-partykit@0.1.0","maintainers":[{"name":"cioky","email":"vgromania3@gmail.com"}],"dist":{"shasum":"38da4e1b419a37f5151ee294112a3ed25e2eefe3","tarball":"https://registry.npmjs.org/@cioky/remult-partykit/-/remult-partykit-0.1.0.tgz","fileCount":21,"integrity":"sha512-zYg3BC1K9QfGEyFUfX8Is2Cy4+NVKNHQrYBS5eTJPT0J97WtRL5I/Rxm9DtDWdfkNG5nM29TjlpqIWjhDueeoQ==","signatures":[{"sig":"MEUCIHbYknY+Ybtwj9ViOJ8Y5x5anKP6eMirPBVKfKmVxBiPAiEAp7mzRnhVzr2RR/2YZ6RYVomfTwhQ7Qqj1y4lpamhnwk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":68437},"type":"module","shasum":"38da4e1b419a37f5151ee294112a3ed25e2eefe3","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./client":{"types":"./dist/client.d.ts","default":"./dist/client.js"},"./server":{"types":"./dist/server.d.ts","default":"./dist/server.js"},"./svelte":{"types":"./dist/svelte.d.ts","default":"./dist/svelte.js"},"./storage":{"types":"./dist/storage.d.ts","default":"./dist/storage.js"},"./durable-object":{"types":"./dist/durable-object.d.ts","default":"./dist/durable-object.js"}},"scripts":{"dev":"tsc -p tsconfig.build.json --watch","test":"bun test tests/client.test.ts tests/svelte.test.ts","build":"tsc -p tsconfig.build.json","check":"biome check src/","fallow":"bunx fallow","test:do":"vitest run","prepublishOnly":"bun run check && bun run build"},"_npmUser":{"name":"cioky","email":"vgromania3@gmail.com"},"_integrity":"sha512-zYg3BC1K9QfGEyFUfX8Is2Cy4+NVKNHQrYBS5eTJPT0J97WtRL5I/Rxm9DtDWdfkNG5nM29TjlpqIWjhDueeoQ==","_npmVersion":"10.8.3","description":"Realtime pub/sub engine + Svelte 5 reactive layer for Remult on Cloudflare Workers (partyserver).","directories":{},"_nodeVersion":"24.3.0","dependencies":{"remult":"^3.3.16","neverthrow":"^8.2.0","partyserver":"^0.5.8"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"svelte":"^5.56.8","vitest":"^4.1.10","typescript":"~6.0.3","@biomejs/biome":"2.5.5","@cloudflare/workers-types":"^5.20260727.1","@cloudflare/vitest-pool-workers":"^0.20.3"},"peerDependencies":{"svelte":"^5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/remult-partykit_0.1.0_1786473065665_0.9985706802337126","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@cioky/remult-partykit","version":"0.1.1","description":"Realtime pub/sub engine + Svelte 5 reactive layer for Remult on Cloudflare Workers (partyserver).","type":"module","publishConfig":{"access":"public"},"scripts":{"build":"tsc -p tsconfig.build.json","dev":"tsc -p tsconfig.build.json --watch","check":"biome check src/","fallow":"bunx fallow","test":"bun test tests/client.test.ts tests/svelte.test.ts","test:do":"vitest run","prepublishOnly":"bun run check && bun run build"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./client":{"types":"./dist/client.d.ts","default":"./dist/client.js"},"./durable-object":{"types":"./dist/durable-object.d.ts","default":"./dist/durable-object.js"},"./server":{"types":"./dist/server.d.ts","default":"./dist/server.js"},"./storage":{"types":"./dist/storage.d.ts","default":"./dist/storage.js"},"./svelte":{"types":"./dist/svelte.d.ts","default":"./dist/svelte.js"}},"dependencies":{"neverthrow":"^8.2.0","partyserver":"^0.5.8","remult":"^3.3.16"},"peerDependencies":{"svelte":"^5.0.0"},"devDependencies":{"@biomejs/biome":"2.5.5","@cloudflare/vitest-pool-workers":"^0.20.3","@cloudflare/workers-types":"^5.20260727.1","svelte":"^5.56.8","typescript":"~6.0.3","vitest":"^4.1.10"},"_id":"@cioky/remult-partykit@0.1.1","_integrity":"sha512-MF/Bvi2ShUq6hka/cryiKQ0j6h+TzD/9WIPsjWkKPQVRh3GFY4010hu6eKbmvylQfT2CfgaeUK0wHuiDAvU80Q==","_nodeVersion":"24.3.0","_npmVersion":"10.8.3","shasum":"631776c400cec95c973b021089e44ea311e4e875","dist":{"integrity":"sha512-MF/Bvi2ShUq6hka/cryiKQ0j6h+TzD/9WIPsjWkKPQVRh3GFY4010hu6eKbmvylQfT2CfgaeUK0wHuiDAvU80Q==","shasum":"631776c400cec95c973b021089e44ea311e4e875","tarball":"https://registry.npmjs.org/@cioky/remult-partykit/-/remult-partykit-0.1.1.tgz","fileCount":23,"unpackedSize":73351,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDLSlYH1H5q/d5aKobe8Qak2zX44QSydsInrhKVb8royAiBisXr6ocWIdBQtwZAp1YjZakd6kKtQAqNY0EvxvkGlBQ=="}]},"_npmUser":{"name":"cioky","email":"vgromania3@gmail.com"},"directories":{},"maintainers":[{"name":"cioky","email":"vgromania3@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/remult-partykit_0.1.1_1786475077739_0.7373988640992029"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-11T18:31:05.475Z","modified":"2026-08-11T19:04:38.070Z","0.1.0":"2026-08-11T18:31:05.867Z","0.1.1":"2026-08-11T19:04:37.897Z"},"description":"Realtime pub/sub engine + Svelte 5 reactive layer for Remult on Cloudflare Workers (partyserver).","maintainers":[{"name":"cioky","email":"vgromania3@gmail.com"}],"readme":"# @cioky/remult-partykit\n\nRealtime for [Remult](https://remult.dev) on Cloudflare Durable Objects + PartyServer.\nA single-socket WebSocket transport with per-channel authorization, remote\nsubscriptions, and an optional Svelte 5 reactive layer.\n\nAgnostic by design: room sharding, subscription authorization, and client\npublish policy are consumer-supplied hooks. No application knowledge ships in\nthe package — bring your own channel map and authz.\n\n## Install\n\n```bash\nbun add @cioky/remult-partykit\n```\n\nPeer dependency: `svelte` (only needed for the `/svelte` entry).\n\n## What you get\n\n| Entry | Contents |\n|---|---|\n| `.` | `RemultPartySubscriptionClient` (browser), `RemultPartySubscriptionServer` (SSR publisher, `ResultAsync<void, PublishError>`), `DurableObjectLiveQueryStorage`, typed error taxonomy (`PublishError`, `SubscribeRejectedError`) |\n| `/client` | `RemultPartySubscriptionClient` |\n| `/durable-object` | `RemultPartyRoom`, `RemultLiveQueryStorageRoom` (Cloudflare DO classes) |\n| `/server` | `RemultPartySubscriptionServer` + `RemultPartyServerOptions` |\n| `/storage` | `DurableObjectLiveQueryStorage` (Remult `LiveQueryStorage`) |\n| `/svelte` | Svelte 5 runes wiring: `initRemultClient`, `createLiveQuery`, reactive connection state |\n\n## Configuration surface\n\nEverything is a hook on `RemultPartyServerOptions` (server publisher) or by\nsubclassing `RemultPartyRoom` (DO side):\n\n- `resolveRoomId(channel)` — channel → room sharding. Default: one shared `global` room.\n- `validateSubscription(channel, roomName)` — per-subscription authz. Default: allow.\n- `allowClientPublish(channel, connectionId, payload)` — client `data` frame policy. Default: deny (server is authoritative).\n- `clientSenderId(room, connectionId)` — trusted sender stamping. Default: none.\n\nThe DO also exposes `resolveRoom(channel)` and an overridable `roomBinding()`\nfor multi-binding setups.\n\n## Quick start\n\n**Worker entry** — export the DO classes and route party requests:\n\n```ts\nimport { routePartykitRequest } from 'partyserver'\nimport { RemultPartyRoom, RemultLiveQueryStorageRoom } from '@cioky/remult-partykit/durable-object'\n\nexport { RemultPartyRoom, RemultLiveQueryStorageRoom }\n\nexport default {\n  async fetch(request, env, ctx) {\n    return (await routePartykitRequest(request, env, { prefix: 'parties' })) ??\n      new Response('Not Found', { status: 404 })\n  },\n} satisfies ExportedHandler<Env>\n```\n\n**Subclass the room** with your sharding + authz:\n\n```ts\nimport { RemultPartyRoom, type RemultPartyServerOptions } from '@cioky/remult-partykit'\n\nexport class MyRoom extends RemultPartyRoom {\n  protected options: RemultPartyServerOptions = {\n    resolveRoomId: (channel) => (channel.startsWith('user:') ? `user:${channel}` : 'global'),\n    validateSubscription: (channel, room) => room === this.name,\n  }\n}\n```\n\n**Server publisher** (SSR):\n\n```ts\nimport { RemultPartySubscriptionServer } from '@cioky/remult-partykit/server'\n\nconst server = new RemultPartySubscriptionServer(env.REMULT_ROOM, {\n  resolveRoomId: myChannelMap,\n})\nconst result = await server.publish('channel', payload) // ResultAsync<void, PublishError>\n```\n\n**Client** (browser):\n\n```ts\nimport { RemultPartySubscriptionClient } from '@cioky/remult-partykit/client'\n\nconst client = new RemultPartySubscriptionClient({\n  getSocketUrl: (room) => `wss://backend.example.com/parties/remult-room/${room}`,\n})\n```\n\n## Tests\n\n- `bun run test` — client + Svelte reactivity with real WebSockets (`Bun.serve`).\n- `bun run test:do` — DO rooms against real workerd via `@cloudflare/vitest-pool-workers`\n  (Hibernation API, `storage.sql`, D1).\n- `bun run check` — biome. `bun run fallow` — fallow analysis (advisory).\n\n## License\n\nMIT\n","readmeFilename":"README.md"}