@derivation/rpc 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/index.cjs +0 -209
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +0 -2
  4. package/dist/index.d.ts +0 -2
  5. package/dist/index.js +0 -208
  6. package/dist/index.js.map +1 -1
  7. package/dist/{shared-worker-server.cjs → shared-worker.cjs} +185 -47
  8. package/dist/shared-worker.cjs.map +1 -0
  9. package/dist/shared-worker.d.cts +68 -0
  10. package/dist/shared-worker.d.ts +68 -0
  11. package/dist/{shared-worker-server.js → shared-worker.js} +179 -43
  12. package/dist/shared-worker.js.map +1 -0
  13. package/dist/{shared-worker-client.cjs → websocket-client.cjs} +21 -55
  14. package/dist/websocket-client.cjs.map +1 -0
  15. package/dist/{client-DJZfuakf.d.cts → websocket-client.d.cts} +4 -5
  16. package/dist/{client-TPsVZH_B.d.ts → websocket-client.d.ts} +4 -5
  17. package/dist/{shared-worker-client.js → websocket-client.js} +16 -50
  18. package/dist/websocket-client.js.map +1 -0
  19. package/dist/{web-socket-server.cjs → websocket-server.cjs} +19 -49
  20. package/dist/websocket-server.cjs.map +1 -0
  21. package/dist/{web-socket-server.js → websocket-server.js} +19 -49
  22. package/dist/websocket-server.js.map +1 -0
  23. package/package.json +18 -28
  24. package/dist/shared-worker-client.cjs.map +0 -1
  25. package/dist/shared-worker-client.d.cts +0 -26
  26. package/dist/shared-worker-client.d.ts +0 -26
  27. package/dist/shared-worker-client.js.map +0 -1
  28. package/dist/shared-worker-server.cjs.map +0 -1
  29. package/dist/shared-worker-server.d.cts +0 -31
  30. package/dist/shared-worker-server.d.ts +0 -31
  31. package/dist/shared-worker-server.js.map +0 -1
  32. package/dist/transport.cjs +0 -19
  33. package/dist/transport.cjs.map +0 -1
  34. package/dist/transport.d.cts +0 -29
  35. package/dist/transport.d.ts +0 -29
  36. package/dist/transport.js +0 -1
  37. package/dist/transport.js.map +0 -1
  38. package/dist/web-socket-server.cjs.map +0 -1
  39. package/dist/web-socket-server.js.map +0 -1
  40. package/dist/web-socket-transport.cjs +0 -52
  41. package/dist/web-socket-transport.cjs.map +0 -1
  42. package/dist/web-socket-transport.d.cts +0 -16
  43. package/dist/web-socket-transport.d.ts +0 -16
  44. package/dist/web-socket-transport.js +0 -27
  45. package/dist/web-socket-transport.js.map +0 -1
  46. /package/dist/{web-socket-server.d.cts → websocket-server.d.cts} +0 -0
  47. /package/dist/{web-socket-server.d.ts → websocket-server.d.ts} +0 -0
@@ -17,12 +17,14 @@ var __copyProps = (to, from, except, desc) => {
17
17
  };
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
 
20
- // src/shared-worker-server.ts
21
- var shared_worker_server_exports = {};
22
- __export(shared_worker_server_exports, {
20
+ // src/shared-worker/index.ts
21
+ var shared_worker_exports = {};
22
+ __export(shared_worker_exports, {
23
+ SharedWorkerClient: () => SharedWorkerClient,
24
+ createSharedWorkerClient: () => createSharedWorkerClient,
23
25
  setupSharedWorker: () => setupSharedWorker
24
26
  });
25
- module.exports = __toCommonJS(shared_worker_server_exports);
27
+ module.exports = __toCommonJS(shared_worker_exports);
26
28
 
27
29
  // src/client-message.ts
28
30
  var import_zod = require("zod");
@@ -59,6 +61,164 @@ var ClientMessageSchema = import_zod.z.discriminatedUnion("type", [
59
61
  function parseClientMessage(data) {
60
62
  return ClientMessageSchema.parse(data);
61
63
  }
64
+ var ClientMessage = {
65
+ subscribe: (id, name, args) => ({
66
+ type: "subscribe",
67
+ id,
68
+ name,
69
+ args
70
+ }),
71
+ unsubscribe: (id) => ({
72
+ type: "unsubscribe",
73
+ id
74
+ }),
75
+ call: (id, name, args) => ({
76
+ type: "call",
77
+ id,
78
+ name,
79
+ args
80
+ }),
81
+ heartbeat: () => ({
82
+ type: "heartbeat"
83
+ }),
84
+ presence: (data) => ({
85
+ type: "presence",
86
+ data
87
+ })
88
+ };
89
+
90
+ // src/shared-worker/shared-worker-client.ts
91
+ function changer(sink, input) {
92
+ return (change) => {
93
+ const i = input.deref();
94
+ if (i) {
95
+ sink.apply(change, i);
96
+ }
97
+ };
98
+ }
99
+ var SharedWorkerClient = class {
100
+ constructor(port, sinks, graph) {
101
+ this.port = port;
102
+ this.sinks = sinks;
103
+ this.graph = graph;
104
+ this.nextId = 1;
105
+ this.pendingStreams = /* @__PURE__ */ new Map();
106
+ this.pendingMutations = /* @__PURE__ */ new Map();
107
+ this.activeStreams = /* @__PURE__ */ new Map();
108
+ this.registry = new FinalizationRegistry(
109
+ ([id, name]) => {
110
+ console.log(`\u{1F9F9} Stream ${id} (${name}) collected \u2014 unsubscribing`);
111
+ this.sendMessage(ClientMessage.unsubscribe(id));
112
+ this.activeStreams.delete(id);
113
+ }
114
+ );
115
+ this.port.onmessage = (event) => {
116
+ const message = JSON.parse(event.data);
117
+ this.handleMessage(message);
118
+ };
119
+ this.port.start();
120
+ }
121
+ handleMessage(message) {
122
+ switch (message.type) {
123
+ case "snapshot": {
124
+ console.log(`[Client] Received snapshot for stream ${message.id}`);
125
+ const resolve = this.pendingStreams.get(message.id);
126
+ if (resolve) {
127
+ resolve(message.snapshot);
128
+ this.pendingStreams.delete(message.id);
129
+ }
130
+ break;
131
+ }
132
+ case "delta": {
133
+ const changeCount = Object.keys(message.changes).length;
134
+ console.log(
135
+ `[Client] Received delta with ${changeCount} changes for streams: ${Object.keys(message.changes).join(", ")}`
136
+ );
137
+ for (const [idStr, change] of Object.entries(message.changes)) {
138
+ const id = Number(idStr);
139
+ const sink = this.activeStreams.get(id);
140
+ if (sink && change && typeof change === "object") {
141
+ sink(change);
142
+ } else if (!sink) {
143
+ console.log(`\u{1F9F9} Sink ${id} GC'd \u2014 auto-unsubscribing`);
144
+ this.sendMessage(ClientMessage.unsubscribe(id));
145
+ this.activeStreams.delete(id);
146
+ }
147
+ }
148
+ console.log("[Client] Stepping graph");
149
+ this.graph.step();
150
+ break;
151
+ }
152
+ case "result": {
153
+ console.log(
154
+ `[Client] Received mutation result for call ${message.id}:`,
155
+ message.success ? "success" : "error"
156
+ );
157
+ const resolve = this.pendingMutations.get(message.id);
158
+ if (resolve) {
159
+ if (message.success) {
160
+ resolve({ success: true, value: message.value });
161
+ } else {
162
+ resolve({
163
+ success: false,
164
+ error: message.error || "Unknown error"
165
+ });
166
+ }
167
+ this.pendingMutations.delete(message.id);
168
+ }
169
+ break;
170
+ }
171
+ case "heartbeat":
172
+ console.log("[Client] Received heartbeat");
173
+ break;
174
+ }
175
+ }
176
+ sendMessage(message) {
177
+ this.port.postMessage(JSON.stringify(message));
178
+ }
179
+ async run(key, args) {
180
+ console.log(
181
+ `Running stream ${String(key)} with args ${JSON.stringify(args)}`
182
+ );
183
+ const id = this.nextId++;
184
+ this.sendMessage(ClientMessage.subscribe(id, String(key), args));
185
+ const snapshot = await new Promise((resolve) => {
186
+ this.pendingStreams.set(id, resolve);
187
+ });
188
+ const endpoint = this.sinks[key];
189
+ const sinkAdapter = endpoint(snapshot);
190
+ const { stream, input } = sinkAdapter.build();
191
+ const inputRef = new WeakRef(input);
192
+ this.activeStreams.set(id, changer(sinkAdapter, inputRef));
193
+ this.registry.register(input, [id, String(key)]);
194
+ return stream;
195
+ }
196
+ async call(key, args) {
197
+ console.log(
198
+ `Calling mutation ${String(key)} with args ${JSON.stringify(args)}`
199
+ );
200
+ const id = this.nextId++;
201
+ this.sendMessage(
202
+ ClientMessage.call(id, String(key), args)
203
+ );
204
+ const result = await new Promise((resolve) => {
205
+ this.pendingMutations.set(
206
+ id,
207
+ resolve
208
+ );
209
+ });
210
+ return result;
211
+ }
212
+ close() {
213
+ this.port.close();
214
+ }
215
+ setPresence(value) {
216
+ this.sendMessage(ClientMessage.presence(value));
217
+ }
218
+ };
219
+ function createSharedWorkerClient(port, sinks, graph) {
220
+ return new SharedWorkerClient(port, sinks, graph);
221
+ }
62
222
 
63
223
  // src/server-message.ts
64
224
  var import_zod2 = require("zod");
@@ -114,19 +274,21 @@ var ServerMessage = {
114
274
  })
115
275
  };
116
276
 
117
- // src/shared-worker-client-handler.ts
277
+ // src/shared-worker/shared-worker-client-handler.ts
118
278
  var SharedWorkerClientHandler = class {
119
- constructor(transport, context, streamEndpoints, mutationEndpoints, presenceHandler) {
279
+ constructor(port, context, streamEndpoints, mutationEndpoints, presenceHandler) {
120
280
  this.closed = false;
121
281
  this.streams = /* @__PURE__ */ new Map();
122
- this.transport = transport;
282
+ this.port = port;
123
283
  this.context = context;
124
284
  this.streamEndpoints = streamEndpoints;
125
285
  this.mutationEndpoints = mutationEndpoints;
126
286
  this.presenceHandler = presenceHandler;
127
287
  console.log("new client connected");
128
- this.transport.onMessage((data) => this.handleMessage(data));
129
- this.transport.onClose(() => this.handleDisconnect());
288
+ this.port.onmessage = (event) => {
289
+ this.handleMessage(event.data);
290
+ };
291
+ this.port.onmessageerror = () => this.handleDisconnect();
130
292
  }
131
293
  handleMessage(message) {
132
294
  let data;
@@ -189,9 +351,7 @@ var SharedWorkerClientHandler = class {
189
351
  ).then((result) => {
190
352
  if (result.success) {
191
353
  this.sendMessage(ServerMessage.resultSuccess(id, result.value));
192
- console.log(
193
- `Mutation "${name}" (${id}) completed successfully`
194
- );
354
+ console.log(`Mutation "${name}" (${id}) completed successfully`);
195
355
  } else {
196
356
  this.sendMessage(ServerMessage.resultError(id, result.error));
197
357
  console.log(
@@ -235,13 +395,15 @@ var SharedWorkerClientHandler = class {
235
395
  changes[id] = change;
236
396
  }
237
397
  if (Object.keys(changes).length > 0) {
238
- console.log(`[ClientHandler] Sending delta with ${Object.keys(changes).length} changes for streams: ${Object.keys(changes).join(", ")}`);
398
+ console.log(
399
+ `[ClientHandler] Sending delta with ${Object.keys(changes).length} changes for streams: ${Object.keys(changes).join(", ")}`
400
+ );
239
401
  this.sendMessage(ServerMessage.delta(changes));
240
402
  }
241
403
  }
242
404
  sendMessage(message) {
243
405
  if (this.closed) return;
244
- this.transport.send(JSON.stringify(message));
406
+ this.port.postMessage(JSON.stringify(message));
245
407
  }
246
408
  handleDisconnect() {
247
409
  this.close();
@@ -253,10 +415,12 @@ var SharedWorkerClientHandler = class {
253
415
  if (this.presenceHandler && this.currentPresence) {
254
416
  this.presenceHandler.remove(this.currentPresence);
255
417
  }
256
- console.log(`[ClientHandler] Cleaning up ${this.streams.size} active streams`);
418
+ console.log(
419
+ `[ClientHandler] Cleaning up ${this.streams.size} active streams`
420
+ );
257
421
  this.streams.clear();
258
422
  try {
259
- this.transport.close();
423
+ this.port.close();
260
424
  } catch (e) {
261
425
  }
262
426
  }
@@ -283,34 +447,7 @@ var WeakList = class {
283
447
  }
284
448
  };
285
449
 
286
- // src/messageport-transport.ts
287
- var MessagePortTransport = class {
288
- constructor(port) {
289
- this.port = port;
290
- }
291
- send(data) {
292
- console.log("[MessagePortTransport] Sending:", data.substring(0, 100) + (data.length > 100 ? "..." : ""));
293
- this.port.postMessage(data);
294
- }
295
- onMessage(handler) {
296
- this.port.onmessage = (event) => {
297
- console.log("[MessagePortTransport] Received:", event.data.substring(0, 100) + (event.data.length > 100 ? "..." : ""));
298
- handler(event.data);
299
- };
300
- }
301
- onClose(handler) {
302
- this.port.onmessageerror = handler;
303
- }
304
- close() {
305
- this.port.close();
306
- }
307
- // MessagePort doesn't provide bufferedAmount
308
- get bufferedAmount() {
309
- return void 0;
310
- }
311
- };
312
-
313
- // src/shared-worker-server.ts
450
+ // src/shared-worker/shared-worker-server.ts
314
451
  function setupSharedWorker(options, graph) {
315
452
  const { streams, mutations, createContext, presenceHandler } = options;
316
453
  const clients = new WeakList();
@@ -333,9 +470,8 @@ function setupSharedWorker(options, graph) {
333
470
  port.onmessage = tempMessageHandler;
334
471
  Promise.resolve(createContext(port)).then((context) => {
335
472
  console.log("[SharedWorker] Context created, setting up client handler");
336
- const transport = new MessagePortTransport(port);
337
473
  client = new SharedWorkerClientHandler(
338
- transport,
474
+ port,
339
475
  context,
340
476
  streams,
341
477
  mutations,
@@ -358,6 +494,8 @@ function setupSharedWorker(options, graph) {
358
494
  }
359
495
  // Annotate the CommonJS export names for ESM import in node:
360
496
  0 && (module.exports = {
497
+ SharedWorkerClient,
498
+ createSharedWorkerClient,
361
499
  setupSharedWorker
362
500
  });
363
- //# sourceMappingURL=shared-worker-server.cjs.map
501
+ //# sourceMappingURL=shared-worker.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared-worker/index.ts","../src/client-message.ts","../src/shared-worker/shared-worker-client.ts","../src/server-message.ts","../src/shared-worker/shared-worker-client-handler.ts","../src/weak-list.ts","../src/shared-worker/shared-worker-server.ts"],"sourcesContent":["export * from \"./shared-worker-client.js\";\nexport * from \"./shared-worker-server.js\";\n","import { z } from \"zod\";\n\nexport const SubscribeMessageSchema = z.object({\n type: z.literal(\"subscribe\"),\n id: z.number(),\n name: z.string(),\n args: z.looseObject({}),\n});\nexport type SubscribeMessage = z.infer<typeof SubscribeMessageSchema>;\n\nexport const UnsubscribeMessageSchema = z.object({\n type: z.literal(\"unsubscribe\"),\n id: z.number(),\n});\nexport type UnsubscribeMessage = z.infer<typeof UnsubscribeMessageSchema>;\n\nexport const HeartbeatMessageSchema = z.object({\n type: z.literal(\"heartbeat\"),\n});\nexport type HeartbeatMessage = z.infer<typeof HeartbeatMessageSchema>;\n\nexport const CallMessageSchema = z.object({\n type: z.literal(\"call\"),\n id: z.number(),\n name: z.string(),\n args: z.looseObject({}),\n});\nexport type CallMessage = z.infer<typeof CallMessageSchema>;\n\nexport const PresenceMessageSchema = z.object({\n type: z.literal(\"presence\"),\n data: z.looseObject({}),\n});\nexport type PresenceMessage = z.infer<typeof PresenceMessageSchema>;\n\nexport const ClientMessageSchema = z.discriminatedUnion(\"type\", [\n SubscribeMessageSchema,\n UnsubscribeMessageSchema,\n HeartbeatMessageSchema,\n CallMessageSchema,\n PresenceMessageSchema,\n]);\nexport type ClientMessage = z.infer<typeof ClientMessageSchema>;\n\nexport function parseClientMessage(data: unknown): ClientMessage {\n return ClientMessageSchema.parse(data);\n}\n\nexport const ClientMessage = {\n subscribe: (\n id: number,\n name: string,\n args: object,\n ): SubscribeMessage => ({\n type: \"subscribe\",\n id,\n name,\n args: args as Record<string, unknown>,\n }),\n unsubscribe: (id: number): UnsubscribeMessage => ({\n type: \"unsubscribe\",\n id,\n }),\n call: (\n id: number,\n name: string,\n args: object,\n ): CallMessage => ({\n type: \"call\",\n id,\n name,\n args: args as Record<string, unknown>,\n }),\n heartbeat: (): HeartbeatMessage => ({\n type: \"heartbeat\",\n }),\n presence: (data: object): PresenceMessage => ({\n type: \"presence\",\n data: data as Record<string, unknown>,\n }),\n};\n","import { ClientMessage } from \"../client-message.js\";\nimport { ServerMessage } from \"../server-message.js\";\nimport type { Graph } from \"derivation\";\nimport type {\n Sink,\n StreamSinks,\n RPCDefinition,\n MutationResult,\n} from \"../stream-types.js\";\n\nfunction changer<T extends object, I extends object>(\n sink: Sink<T, I>,\n input: WeakRef<I>,\n): (change: object) => void {\n return (change) => {\n const i = input.deref();\n if (i) {\n sink.apply(change, i);\n }\n };\n}\n\nexport class SharedWorkerClient<Defs extends RPCDefinition> {\n private nextId = 1;\n private pendingStreams = new Map<number, (snapshot: object) => void>();\n private pendingMutations = new Map<\n number,\n (result: MutationResult<unknown>) => void\n >();\n private activeStreams = new Map<number, (change: object) => void>();\n\n private registry = new FinalizationRegistry<[number, string]>(\n ([id, name]) => {\n console.log(`🧹 Stream ${id} (${name}) collected — unsubscribing`);\n this.sendMessage(ClientMessage.unsubscribe(id));\n this.activeStreams.delete(id);\n },\n );\n\n constructor(\n private port: MessagePort,\n private sinks: StreamSinks<Defs[\"streams\"]>,\n private graph: Graph,\n ) {\n this.port.onmessage = (event: MessageEvent) => {\n const message = JSON.parse(event.data as string) as ServerMessage;\n this.handleMessage(message);\n };\n this.port.start();\n }\n\n private handleMessage(message: ServerMessage) {\n switch (message.type) {\n case \"snapshot\": {\n console.log(`[Client] Received snapshot for stream ${message.id}`);\n const resolve = this.pendingStreams.get(message.id);\n if (resolve) {\n resolve(message.snapshot as object);\n this.pendingStreams.delete(message.id);\n }\n break;\n }\n case \"delta\": {\n const changeCount = Object.keys(message.changes).length;\n console.log(\n `[Client] Received delta with ${changeCount} changes for streams: ${Object.keys(message.changes).join(\", \")}`,\n );\n for (const [idStr, change] of Object.entries(message.changes)) {\n const id = Number(idStr);\n const sink = this.activeStreams.get(id);\n\n if (sink && change && typeof change === \"object\") {\n sink(change);\n } else if (!sink) {\n console.log(`🧹 Sink ${id} GC'd — auto-unsubscribing`);\n this.sendMessage(ClientMessage.unsubscribe(id));\n this.activeStreams.delete(id);\n }\n }\n console.log(\"[Client] Stepping graph\");\n this.graph.step();\n break;\n }\n case \"result\": {\n console.log(\n `[Client] Received mutation result for call ${message.id}:`,\n message.success ? \"success\" : \"error\",\n );\n const resolve = this.pendingMutations.get(message.id);\n if (resolve) {\n if (message.success) {\n resolve({ success: true, value: message.value });\n } else {\n resolve({\n success: false,\n error: message.error || \"Unknown error\",\n });\n }\n this.pendingMutations.delete(message.id);\n }\n break;\n }\n case \"heartbeat\":\n console.log(\"[Client] Received heartbeat\");\n break;\n }\n }\n\n private sendMessage(message: ClientMessage) {\n this.port.postMessage(JSON.stringify(message));\n }\n\n async run<Key extends keyof Defs[\"streams\"]>(\n key: Key,\n args: Defs[\"streams\"][Key][\"args\"],\n ): Promise<Defs[\"streams\"][Key][\"returnType\"]> {\n console.log(\n `Running stream ${String(key)} with args ${JSON.stringify(args)}`,\n );\n const id = this.nextId++;\n\n this.sendMessage(ClientMessage.subscribe(id, String(key), args));\n\n const snapshot = await new Promise<object>((resolve) => {\n this.pendingStreams.set(id, resolve);\n });\n\n const endpoint = this.sinks[key];\n const sinkAdapter = endpoint(snapshot);\n const { stream, input } = sinkAdapter.build();\n const inputRef = new WeakRef(input);\n this.activeStreams.set(id, changer(sinkAdapter, inputRef));\n this.registry.register(input, [id, String(key)]);\n\n return stream;\n }\n\n async call<Key extends keyof Defs[\"mutations\"]>(\n key: Key,\n args: Defs[\"mutations\"][Key][\"args\"],\n ): Promise<MutationResult<Defs[\"mutations\"][Key][\"result\"]>> {\n console.log(\n `Calling mutation ${String(key)} with args ${JSON.stringify(args)}`,\n );\n const id = this.nextId++;\n\n this.sendMessage(\n ClientMessage.call(id, String(key), args as Record<string, unknown>),\n );\n\n const result = await new Promise<\n MutationResult<Defs[\"mutations\"][Key][\"result\"]>\n >((resolve) => {\n this.pendingMutations.set(\n id,\n resolve as (result: MutationResult<unknown>) => void,\n );\n });\n\n return result;\n }\n\n close() {\n this.port.close();\n }\n\n setPresence(value: Record<string, unknown>): void {\n this.sendMessage(ClientMessage.presence(value));\n }\n}\n\n/**\n * Create a client connected to a SharedWorker.\n *\n * @example\n * ```typescript\n * // main.ts\n * const graph = new Graph();\n * const worker = new SharedWorker('/worker.js');\n *\n * const client = createSharedWorkerClient(worker.port, {\n * streams: {\n * todos: setSink(graph, todoIso),\n * },\n * }, graph);\n *\n * const todos = await client.run('todos', { filter: 'active' });\n * ```\n */\nexport function createSharedWorkerClient<Defs extends RPCDefinition>(\n port: MessagePort,\n sinks: StreamSinks<Defs[\"streams\"]>,\n graph: Graph,\n): SharedWorkerClient<Defs> {\n return new SharedWorkerClient<Defs>(port, sinks, graph);\n}\n","import { z } from \"zod\";\n\nexport const HeartbeatMessageSchema = z.object({\n type: z.literal(\"heartbeat\"),\n});\nexport type HeartbeatMessage = z.infer<typeof HeartbeatMessageSchema>;\n\nexport const SubscribedSchema = z.object({\n type: z.literal(\"snapshot\"),\n id: z.number(),\n snapshot: z.unknown(),\n});\nexport type SubscribedMessage = z.infer<typeof SubscribedSchema>;\n\nexport const DeltaMessageSchema = z.object({\n type: z.literal(\"delta\"),\n changes: z.record(z.number(), z.unknown()),\n});\nexport type DeltaMessage = z.infer<typeof DeltaMessageSchema>;\n\nexport const ResultMessageSchema = z.object({\n type: z.literal(\"result\"),\n id: z.number(),\n success: z.boolean(),\n value: z.unknown().optional(),\n error: z.string().optional(),\n});\nexport type ResultMessage = z.infer<typeof ResultMessageSchema>;\n\nexport const ServerMessageSchema = z.discriminatedUnion(\"type\", [\n HeartbeatMessageSchema,\n SubscribedSchema,\n DeltaMessageSchema,\n ResultMessageSchema,\n]);\nexport type ServerMessage = z.infer<typeof ServerMessageSchema>;\n\nexport const ServerMessage = {\n heartbeat: (): HeartbeatMessage => ({\n type: \"heartbeat\",\n }),\n subscribed: (id: number, snapshot: unknown): SubscribedMessage => ({\n type: \"snapshot\",\n id,\n snapshot,\n }),\n delta: (changes: Record<string, unknown>): DeltaMessage => ({\n type: \"delta\",\n changes: changes,\n }),\n resultSuccess: (id: number, value: unknown): ResultMessage => ({\n type: \"result\",\n id,\n success: true,\n value,\n }),\n resultError: (id: number, error: string): ResultMessage => ({\n type: \"result\",\n id,\n success: false,\n error,\n }),\n};\n","import { parseClientMessage, ClientMessage } from \"../client-message.js\";\nimport { ServerMessage } from \"../server-message.js\";\nimport {\n Source,\n StreamEndpoints,\n MutationEndpoints,\n RPCDefinition,\n} from \"../stream-types.js\";\nimport { PresenceHandler } from \"../presence-manager.js\";\n\n/**\n * Client handler for SharedWorker connections (browser-only).\n * Simplified version without rate limiting, heartbeats, or inactivity timeouts.\n * Designed for same-origin trusted connections.\n */\nexport class SharedWorkerClientHandler<Defs extends RPCDefinition, Ctx = void> {\n private readonly port: MessagePort;\n private readonly context: Ctx;\n private readonly streamEndpoints: StreamEndpoints<Defs[\"streams\"], Ctx>;\n private readonly mutationEndpoints: MutationEndpoints<Defs[\"mutations\"], Ctx>;\n private readonly presenceHandler?: PresenceHandler;\n private currentPresence?: Record<string, unknown>;\n private closed = false;\n private readonly streams = new Map<number, Source<unknown>>();\n\n constructor(\n port: MessagePort,\n context: Ctx,\n streamEndpoints: StreamEndpoints<Defs[\"streams\"], Ctx>,\n mutationEndpoints: MutationEndpoints<Defs[\"mutations\"], Ctx>,\n presenceHandler?: PresenceHandler,\n ) {\n this.port = port;\n this.context = context;\n this.streamEndpoints = streamEndpoints;\n this.mutationEndpoints = mutationEndpoints;\n this.presenceHandler = presenceHandler;\n\n console.log(\"new client connected\");\n\n // Set up transport handlers\n this.port.onmessage = (event: MessageEvent) => {\n this.handleMessage(event.data as string);\n };\n this.port.onmessageerror = () => this.handleDisconnect();\n }\n\n handleMessage(message: string) {\n let data: object;\n try {\n data = JSON.parse(message);\n } catch {\n console.error(\"Invalid JSON received:\", message);\n return this.close();\n }\n\n let parsed: ClientMessage;\n try {\n parsed = parseClientMessage(data);\n } catch (error) {\n console.error(\"Invalid client message:\", error);\n return this.close();\n }\n\n this.handleClientMessage(parsed);\n }\n\n async handleClientMessage(message: ClientMessage) {\n switch (message.type) {\n case \"subscribe\": {\n const { id, name, args } = message;\n\n if (!(name in this.streamEndpoints)) {\n console.error(`Unknown stream: ${name}`);\n this.close();\n return;\n }\n\n const endpoint = this.streamEndpoints[name as keyof Defs[\"streams\"]];\n\n try {\n const source = await endpoint(\n args as Defs[\"streams\"][keyof Defs[\"streams\"]][\"args\"],\n this.context,\n );\n this.streams.set(id, source);\n this.sendMessage(ServerMessage.subscribed(id, source.Snapshot));\n console.log(`Client subscribed to \"${name}\" (${id})`);\n } catch (err) {\n console.error(`Error building stream ${name}:`, err);\n this.close();\n }\n break;\n }\n\n case \"unsubscribe\": {\n const { id } = message;\n this.streams.delete(id);\n console.log(`Client unsubscribed from ${id}`);\n break;\n }\n\n case \"call\": {\n const { id, name, args } = message;\n\n if (!(name in this.mutationEndpoints)) {\n console.error(`Unknown mutation: ${name}`);\n this.close();\n return;\n }\n\n const endpoint =\n this.mutationEndpoints[name as keyof Defs[\"mutations\"]];\n\n endpoint(\n args as Defs[\"mutations\"][keyof Defs[\"mutations\"]][\"args\"],\n this.context,\n )\n .then((result) => {\n if (result.success) {\n this.sendMessage(ServerMessage.resultSuccess(id, result.value));\n console.log(`Mutation \"${name}\" (${id}) completed successfully`);\n } else {\n this.sendMessage(ServerMessage.resultError(id, result.error));\n console.log(\n `Mutation \"${name}\" (${id}) returned error: ${result.error}`,\n );\n }\n })\n .catch((err) => {\n console.error(\n `Unhandled exception in mutation \"${name}\" (${id}):`,\n err,\n );\n this.close();\n });\n break;\n }\n\n case \"heartbeat\":\n break;\n\n case \"presence\": {\n if (!this.presenceHandler) {\n console.error(\"Presence not configured\");\n this.close();\n return;\n }\n\n const { data } = message;\n\n if (this.currentPresence !== undefined) {\n this.presenceHandler.update(this.currentPresence, data);\n } else {\n this.presenceHandler.add(data);\n }\n\n this.currentPresence = data;\n break;\n }\n }\n }\n\n handleStep() {\n if (this.closed) return;\n const changes: Record<number, unknown> = {};\n\n for (const [id, source] of this.streams) {\n const change = source.LastChange;\n if (change === null) continue;\n changes[id] = change;\n }\n\n if (Object.keys(changes).length > 0) {\n console.log(\n `[ClientHandler] Sending delta with ${Object.keys(changes).length} changes for streams: ${Object.keys(changes).join(\", \")}`,\n );\n this.sendMessage(ServerMessage.delta(changes));\n }\n }\n\n sendMessage(message: ServerMessage) {\n if (this.closed) return;\n this.port.postMessage(JSON.stringify(message));\n }\n\n private handleDisconnect() {\n this.close();\n }\n\n close() {\n if (this.closed) return;\n console.log(\"[ClientHandler] Closing client connection\");\n this.closed = true;\n\n if (this.presenceHandler && this.currentPresence) {\n this.presenceHandler.remove(this.currentPresence);\n }\n\n console.log(\n `[ClientHandler] Cleaning up ${this.streams.size} active streams`,\n );\n this.streams.clear();\n\n try {\n this.port.close();\n } catch {}\n }\n}\n","export default class WeakList<T extends object> implements Iterable<T> {\n private items: WeakRef<T>[] = [];\n\n add(value: T): void {\n this.items.push(new WeakRef(value));\n }\n\n *[Symbol.iterator](): Iterator<T> {\n const newItems: WeakRef<T>[] = [];\n\n for (const ref of this.items) {\n const value = ref.deref();\n if (value !== undefined) {\n yield value;\n newItems.push(ref);\n }\n }\n\n this.items = newItems;\n }\n}\n","import { Graph } from \"derivation\";\nimport { SharedWorkerClientHandler } from \"./shared-worker-client-handler.js\";\nimport WeakList from \"../weak-list.js\";\nimport {\n StreamEndpoints,\n MutationEndpoints,\n RPCDefinition,\n} from \"../stream-types.js\";\nimport { PresenceHandler } from \"../presence-manager.js\";\n\nexport type SharedWorkerServerOptions<\n Defs extends RPCDefinition,\n Ctx = void,\n> = {\n streams: StreamEndpoints<Defs[\"streams\"], Ctx>;\n mutations: MutationEndpoints<Defs[\"mutations\"], Ctx>;\n createContext: (port: MessagePort) => Ctx | Promise<Ctx>;\n presenceHandler?: PresenceHandler;\n};\n\n/**\n * Set up a SharedWorker server for RPC communication.\n * This creates a shared Graph that all connected tabs can interact with.\n *\n * @example\n * ```typescript\n * // worker.ts\n * const { graph } = setupSharedWorker({\n * streams: {\n * todos: async (args, ctx) => new ReactiveSourceAdapter(source, iso),\n * },\n * mutations: {\n * addTodo: async (args, ctx) => ({ success: true, value: newTodo }),\n * },\n * createContext: (port) => ({ portId: crypto.randomUUID() }),\n * });\n * ```\n */\nexport function setupSharedWorker<Defs extends RPCDefinition, Ctx = void>(\n options: SharedWorkerServerOptions<Defs, Ctx>,\n graph: Graph,\n) {\n const { streams, mutations, createContext, presenceHandler } = options;\n\n const clients = new WeakList<SharedWorkerClientHandler<Defs, Ctx>>();\n\n // After each graph step, broadcast deltas to all connected clients\n graph.afterStep(() => {\n console.log(\"[SharedWorker] Broadcasting deltas to clients\");\n for (const client of clients) {\n client.handleStep();\n }\n });\n\n // Handle SharedWorker connections\n const globalScope = self as unknown as SharedWorkerGlobalScope;\n globalScope.onconnect = (event: MessageEvent) => {\n console.log(\"[SharedWorker] New client connecting...\");\n const port = event.ports[0];\n const messageBuffer: string[] = [];\n let client: SharedWorkerClientHandler<Defs, Ctx> | null = null;\n\n // Set up temporary message handler to buffer messages\n const tempMessageHandler = (e: MessageEvent) => {\n console.log(\"[SharedWorker] Buffering message during setup:\", e.data);\n messageBuffer.push(e.data);\n };\n port.onmessage = tempMessageHandler;\n\n // Create context (handle both sync and async)\n Promise.resolve(createContext(port))\n .then((context) => {\n console.log(\"[SharedWorker] Context created, setting up client handler\");\n // Create client handler\n client = new SharedWorkerClientHandler<Defs, Ctx>(\n port,\n context,\n streams,\n mutations,\n presenceHandler,\n );\n clients.add(client);\n console.log(\"[SharedWorker] Client handler registered\");\n\n // Process buffered messages\n console.log(`[SharedWorker] Processing ${messageBuffer.length} buffered messages`);\n for (const msg of messageBuffer) {\n client.handleMessage(msg);\n }\n messageBuffer.length = 0;\n\n // Start the port\n port.start();\n console.log(\"[SharedWorker] Client connection ready\");\n })\n .catch((err) => {\n console.error(\"[SharedWorker] Error creating context:\", err);\n port.close();\n });\n };\n}\n"],"mappings":"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","names":["import_zod","HeartbeatMessageSchema"]}
@@ -0,0 +1,68 @@
1
+ import { Graph } from 'derivation';
2
+ import { R as RPCDefinition, h as StreamSinks, d as MutationResult, g as StreamEndpoints, c as MutationEndpoints } from './stream-types-Q_EqNLtO.cjs';
3
+ import { P as PresenceHandler } from './presence-manager-4LlEyuGp.cjs';
4
+
5
+ declare class SharedWorkerClient<Defs extends RPCDefinition> {
6
+ private port;
7
+ private sinks;
8
+ private graph;
9
+ private nextId;
10
+ private pendingStreams;
11
+ private pendingMutations;
12
+ private activeStreams;
13
+ private registry;
14
+ constructor(port: MessagePort, sinks: StreamSinks<Defs["streams"]>, graph: Graph);
15
+ private handleMessage;
16
+ private sendMessage;
17
+ run<Key extends keyof Defs["streams"]>(key: Key, args: Defs["streams"][Key]["args"]): Promise<Defs["streams"][Key]["returnType"]>;
18
+ call<Key extends keyof Defs["mutations"]>(key: Key, args: Defs["mutations"][Key]["args"]): Promise<MutationResult<Defs["mutations"][Key]["result"]>>;
19
+ close(): void;
20
+ setPresence(value: Record<string, unknown>): void;
21
+ }
22
+ /**
23
+ * Create a client connected to a SharedWorker.
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * // main.ts
28
+ * const graph = new Graph();
29
+ * const worker = new SharedWorker('/worker.js');
30
+ *
31
+ * const client = createSharedWorkerClient(worker.port, {
32
+ * streams: {
33
+ * todos: setSink(graph, todoIso),
34
+ * },
35
+ * }, graph);
36
+ *
37
+ * const todos = await client.run('todos', { filter: 'active' });
38
+ * ```
39
+ */
40
+ declare function createSharedWorkerClient<Defs extends RPCDefinition>(port: MessagePort, sinks: StreamSinks<Defs["streams"]>, graph: Graph): SharedWorkerClient<Defs>;
41
+
42
+ type SharedWorkerServerOptions<Defs extends RPCDefinition, Ctx = void> = {
43
+ streams: StreamEndpoints<Defs["streams"], Ctx>;
44
+ mutations: MutationEndpoints<Defs["mutations"], Ctx>;
45
+ createContext: (port: MessagePort) => Ctx | Promise<Ctx>;
46
+ presenceHandler?: PresenceHandler;
47
+ };
48
+ /**
49
+ * Set up a SharedWorker server for RPC communication.
50
+ * This creates a shared Graph that all connected tabs can interact with.
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * // worker.ts
55
+ * const { graph } = setupSharedWorker({
56
+ * streams: {
57
+ * todos: async (args, ctx) => new ReactiveSourceAdapter(source, iso),
58
+ * },
59
+ * mutations: {
60
+ * addTodo: async (args, ctx) => ({ success: true, value: newTodo }),
61
+ * },
62
+ * createContext: (port) => ({ portId: crypto.randomUUID() }),
63
+ * });
64
+ * ```
65
+ */
66
+ declare function setupSharedWorker<Defs extends RPCDefinition, Ctx = void>(options: SharedWorkerServerOptions<Defs, Ctx>, graph: Graph): void;
67
+
68
+ export { SharedWorkerClient, type SharedWorkerServerOptions, createSharedWorkerClient, setupSharedWorker };
@@ -0,0 +1,68 @@
1
+ import { Graph } from 'derivation';
2
+ import { R as RPCDefinition, h as StreamSinks, d as MutationResult, g as StreamEndpoints, c as MutationEndpoints } from './stream-types-Q_EqNLtO.js';
3
+ import { P as PresenceHandler } from './presence-manager-4LlEyuGp.js';
4
+
5
+ declare class SharedWorkerClient<Defs extends RPCDefinition> {
6
+ private port;
7
+ private sinks;
8
+ private graph;
9
+ private nextId;
10
+ private pendingStreams;
11
+ private pendingMutations;
12
+ private activeStreams;
13
+ private registry;
14
+ constructor(port: MessagePort, sinks: StreamSinks<Defs["streams"]>, graph: Graph);
15
+ private handleMessage;
16
+ private sendMessage;
17
+ run<Key extends keyof Defs["streams"]>(key: Key, args: Defs["streams"][Key]["args"]): Promise<Defs["streams"][Key]["returnType"]>;
18
+ call<Key extends keyof Defs["mutations"]>(key: Key, args: Defs["mutations"][Key]["args"]): Promise<MutationResult<Defs["mutations"][Key]["result"]>>;
19
+ close(): void;
20
+ setPresence(value: Record<string, unknown>): void;
21
+ }
22
+ /**
23
+ * Create a client connected to a SharedWorker.
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * // main.ts
28
+ * const graph = new Graph();
29
+ * const worker = new SharedWorker('/worker.js');
30
+ *
31
+ * const client = createSharedWorkerClient(worker.port, {
32
+ * streams: {
33
+ * todos: setSink(graph, todoIso),
34
+ * },
35
+ * }, graph);
36
+ *
37
+ * const todos = await client.run('todos', { filter: 'active' });
38
+ * ```
39
+ */
40
+ declare function createSharedWorkerClient<Defs extends RPCDefinition>(port: MessagePort, sinks: StreamSinks<Defs["streams"]>, graph: Graph): SharedWorkerClient<Defs>;
41
+
42
+ type SharedWorkerServerOptions<Defs extends RPCDefinition, Ctx = void> = {
43
+ streams: StreamEndpoints<Defs["streams"], Ctx>;
44
+ mutations: MutationEndpoints<Defs["mutations"], Ctx>;
45
+ createContext: (port: MessagePort) => Ctx | Promise<Ctx>;
46
+ presenceHandler?: PresenceHandler;
47
+ };
48
+ /**
49
+ * Set up a SharedWorker server for RPC communication.
50
+ * This creates a shared Graph that all connected tabs can interact with.
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * // worker.ts
55
+ * const { graph } = setupSharedWorker({
56
+ * streams: {
57
+ * todos: async (args, ctx) => new ReactiveSourceAdapter(source, iso),
58
+ * },
59
+ * mutations: {
60
+ * addTodo: async (args, ctx) => ({ success: true, value: newTodo }),
61
+ * },
62
+ * createContext: (port) => ({ portId: crypto.randomUUID() }),
63
+ * });
64
+ * ```
65
+ */
66
+ declare function setupSharedWorker<Defs extends RPCDefinition, Ctx = void>(options: SharedWorkerServerOptions<Defs, Ctx>, graph: Graph): void;
67
+
68
+ export { SharedWorkerClient, type SharedWorkerServerOptions, createSharedWorkerClient, setupSharedWorker };