@derivation/rpc 0.5.0 → 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 +21 -29
  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
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/shared-worker-client.ts","../src/client-message.ts","../src/client.ts","../src/messageport-transport.ts"],"sourcesContent":["import { Graph } from \"derivation\";\nimport { Client } from \"./client.js\";\nimport { MessagePortTransport } from \"./messageport-transport.js\";\nimport { StreamSinks, RPCDefinition } from \"./stream-types.js\";\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): Client<Defs> {\n const transport = new MessagePortTransport(port);\n port.start();\n return new Client<Defs>(transport, sinks, graph);\n}\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\";\nimport { Transport } from \"./transport.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 Client<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 private heartbeatTimeout: NodeJS.Timeout | undefined;\n private inactivityTimeout: NodeJS.Timeout | undefined;\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 private resetHeartbeat() {\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n }\n\n this.heartbeatTimeout = setTimeout(() => {\n this.sendMessage(ClientMessage.heartbeat());\n }, 10_000);\n }\n\n private resetInactivity() {\n if (this.inactivityTimeout) {\n clearTimeout(this.inactivityTimeout);\n }\n\n this.inactivityTimeout = setTimeout(() => {\n this.close();\n }, 30_000);\n }\n\n constructor(\n private transport: Transport,\n private sinks: StreamSinks<Defs[\"streams\"]>,\n private graph: Graph,\n ) {\n this.transport.onMessage((data: string) => {\n const message = JSON.parse(data) as ServerMessage;\n this.handleMessage(message);\n });\n this.resetHeartbeat();\n this.resetInactivity();\n }\n\n private handleMessage(message: ServerMessage) {\n this.resetInactivity();\n\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(`[Client] Received delta with ${changeCount} changes for streams: ${Object.keys(message.changes).join(\", \")}`);\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(`[Client] Received mutation result for call ${message.id}:`, message.success ? \"success\" : \"error\");\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.resetHeartbeat();\n this.transport.send(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 clearTimeout(this.heartbeatTimeout);\n clearTimeout(this.inactivityTimeout);\n try {\n this.transport.close();\n } catch {}\n }\n\n setPresence(value: Record<string, unknown>): void {\n this.sendMessage(ClientMessage.presence(value));\n }\n}\n","import { Transport } from \"./transport.js\";\n\n/**\n * Transport implementation for MessagePort (SharedWorker communication).\n */\nexport class MessagePortTransport implements Transport {\n constructor(private port: MessagePort) {}\n\n send(data: string): void {\n console.log(\"[MessagePortTransport] Sending:\", data.substring(0, 100) + (data.length > 100 ? \"...\" : \"\"));\n this.port.postMessage(data);\n }\n\n onMessage(handler: (data: string) => void): void {\n this.port.onmessage = (event: MessageEvent) => {\n console.log(\"[MessagePortTransport] Received:\", event.data.substring(0, 100) + (event.data.length > 100 ? \"...\" : \"\"));\n handler(event.data);\n };\n }\n\n onClose(handler: () => void): void {\n // MessagePort doesn't have a reliable close event\n // We'll use messageerror as a signal, though it's not perfect\n this.port.onmessageerror = handler;\n }\n\n close(): void {\n this.port.close();\n }\n\n // MessagePort doesn't provide bufferedAmount\n get bufferedAmount(): undefined {\n return undefined;\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,26 +0,0 @@
1
- import { Graph } from 'derivation';
2
- import { C as Client } from './client-DJZfuakf.cjs';
3
- import { R as RPCDefinition, h as StreamSinks } from './stream-types-Q_EqNLtO.cjs';
4
- import './transport.cjs';
5
-
6
- /**
7
- * Create a client connected to a SharedWorker.
8
- *
9
- * @example
10
- * ```typescript
11
- * // main.ts
12
- * const graph = new Graph();
13
- * const worker = new SharedWorker('/worker.js');
14
- *
15
- * const client = createSharedWorkerClient(worker.port, {
16
- * streams: {
17
- * todos: setSink(graph, todoIso),
18
- * },
19
- * }, graph);
20
- *
21
- * const todos = await client.run('todos', { filter: 'active' });
22
- * ```
23
- */
24
- declare function createSharedWorkerClient<Defs extends RPCDefinition>(port: MessagePort, sinks: StreamSinks<Defs["streams"]>, graph: Graph): Client<Defs>;
25
-
26
- export { createSharedWorkerClient };
@@ -1,26 +0,0 @@
1
- import { Graph } from 'derivation';
2
- import { C as Client } from './client-TPsVZH_B.js';
3
- import { R as RPCDefinition, h as StreamSinks } from './stream-types-Q_EqNLtO.js';
4
- import './transport.js';
5
-
6
- /**
7
- * Create a client connected to a SharedWorker.
8
- *
9
- * @example
10
- * ```typescript
11
- * // main.ts
12
- * const graph = new Graph();
13
- * const worker = new SharedWorker('/worker.js');
14
- *
15
- * const client = createSharedWorkerClient(worker.port, {
16
- * streams: {
17
- * todos: setSink(graph, todoIso),
18
- * },
19
- * }, graph);
20
- *
21
- * const todos = await client.run('todos', { filter: 'active' });
22
- * ```
23
- */
24
- declare function createSharedWorkerClient<Defs extends RPCDefinition>(port: MessagePort, sinks: StreamSinks<Defs["streams"]>, graph: Graph): Client<Defs>;
25
-
26
- export { createSharedWorkerClient };
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/client-message.ts","../src/client.ts","../src/messageport-transport.ts","../src/shared-worker-client.ts"],"sourcesContent":["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\";\nimport { Transport } from \"./transport.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 Client<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 private heartbeatTimeout: NodeJS.Timeout | undefined;\n private inactivityTimeout: NodeJS.Timeout | undefined;\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 private resetHeartbeat() {\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n }\n\n this.heartbeatTimeout = setTimeout(() => {\n this.sendMessage(ClientMessage.heartbeat());\n }, 10_000);\n }\n\n private resetInactivity() {\n if (this.inactivityTimeout) {\n clearTimeout(this.inactivityTimeout);\n }\n\n this.inactivityTimeout = setTimeout(() => {\n this.close();\n }, 30_000);\n }\n\n constructor(\n private transport: Transport,\n private sinks: StreamSinks<Defs[\"streams\"]>,\n private graph: Graph,\n ) {\n this.transport.onMessage((data: string) => {\n const message = JSON.parse(data) as ServerMessage;\n this.handleMessage(message);\n });\n this.resetHeartbeat();\n this.resetInactivity();\n }\n\n private handleMessage(message: ServerMessage) {\n this.resetInactivity();\n\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(`[Client] Received delta with ${changeCount} changes for streams: ${Object.keys(message.changes).join(\", \")}`);\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(`[Client] Received mutation result for call ${message.id}:`, message.success ? \"success\" : \"error\");\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.resetHeartbeat();\n this.transport.send(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 clearTimeout(this.heartbeatTimeout);\n clearTimeout(this.inactivityTimeout);\n try {\n this.transport.close();\n } catch {}\n }\n\n setPresence(value: Record<string, unknown>): void {\n this.sendMessage(ClientMessage.presence(value));\n }\n}\n","import { Transport } from \"./transport.js\";\n\n/**\n * Transport implementation for MessagePort (SharedWorker communication).\n */\nexport class MessagePortTransport implements Transport {\n constructor(private port: MessagePort) {}\n\n send(data: string): void {\n console.log(\"[MessagePortTransport] Sending:\", data.substring(0, 100) + (data.length > 100 ? \"...\" : \"\"));\n this.port.postMessage(data);\n }\n\n onMessage(handler: (data: string) => void): void {\n this.port.onmessage = (event: MessageEvent) => {\n console.log(\"[MessagePortTransport] Received:\", event.data.substring(0, 100) + (event.data.length > 100 ? \"...\" : \"\"));\n handler(event.data);\n };\n }\n\n onClose(handler: () => void): void {\n // MessagePort doesn't have a reliable close event\n // We'll use messageerror as a signal, though it's not perfect\n this.port.onmessageerror = handler;\n }\n\n close(): void {\n this.port.close();\n }\n\n // MessagePort doesn't provide bufferedAmount\n get bufferedAmount(): undefined {\n return undefined;\n }\n}\n","import { Graph } from \"derivation\";\nimport { Client } from \"./client.js\";\nimport { MessagePortTransport } from \"./messageport-transport.js\";\nimport { StreamSinks, RPCDefinition } from \"./stream-types.js\";\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): Client<Defs> {\n const transport = new MessagePortTransport(port);\n port.start();\n return new Client<Defs>(transport, sinks, graph);\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/shared-worker-server.ts","../src/client-message.ts","../src/server-message.ts","../src/shared-worker-client-handler.ts","../src/weak-list.ts","../src/messageport-transport.ts"],"sourcesContent":["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\";\nimport { MessagePortTransport } from \"./messageport-transport.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 transport and client handler\n const transport = new MessagePortTransport(port);\n client = new SharedWorkerClientHandler<Defs, Ctx>(\n transport,\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","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 { 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\";\nimport { Transport } from \"./transport.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 transport: Transport;\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 transport: Transport,\n context: Ctx,\n streamEndpoints: StreamEndpoints<Defs[\"streams\"], Ctx>,\n mutationEndpoints: MutationEndpoints<Defs[\"mutations\"], Ctx>,\n presenceHandler?: PresenceHandler,\n ) {\n this.transport = transport;\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.transport.onMessage((data: string) => this.handleMessage(data));\n this.transport.onClose(() => 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(\n `Mutation \"${name}\" (${id}) completed successfully`,\n );\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(`[ClientHandler] Sending delta with ${Object.keys(changes).length} changes for streams: ${Object.keys(changes).join(\", \")}`);\n this.sendMessage(ServerMessage.delta(changes));\n }\n }\n\n sendMessage(message: ServerMessage) {\n if (this.closed) return;\n this.transport.send(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(`[ClientHandler] Cleaning up ${this.streams.size} active streams`);\n this.streams.clear();\n\n try {\n this.transport.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 { Transport } from \"./transport.js\";\n\n/**\n * Transport implementation for MessagePort (SharedWorker communication).\n */\nexport class MessagePortTransport implements Transport {\n constructor(private port: MessagePort) {}\n\n send(data: string): void {\n console.log(\"[MessagePortTransport] Sending:\", data.substring(0, 100) + (data.length > 100 ? \"...\" : \"\"));\n this.port.postMessage(data);\n }\n\n onMessage(handler: (data: string) => void): void {\n this.port.onmessage = (event: MessageEvent) => {\n console.log(\"[MessagePortTransport] Received:\", event.data.substring(0, 100) + (event.data.length > 100 ? \"...\" : \"\"));\n handler(event.data);\n };\n }\n\n onClose(handler: () => void): void {\n // MessagePort doesn't have a reliable close event\n // We'll use messageerror as a signal, though it's not perfect\n this.port.onmessageerror = handler;\n }\n\n close(): void {\n this.port.close();\n }\n\n // MessagePort doesn't provide bufferedAmount\n get bufferedAmount(): undefined {\n return undefined;\n }\n}\n"],"mappings":"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","names":["import_zod","HeartbeatMessageSchema"]}
@@ -1,31 +0,0 @@
1
- import { Graph } from 'derivation';
2
- import { R as RPCDefinition, g as StreamEndpoints, c as MutationEndpoints } from './stream-types-Q_EqNLtO.cjs';
3
- import { P as PresenceHandler } from './presence-manager-4LlEyuGp.cjs';
4
-
5
- type SharedWorkerServerOptions<Defs extends RPCDefinition, Ctx = void> = {
6
- streams: StreamEndpoints<Defs["streams"], Ctx>;
7
- mutations: MutationEndpoints<Defs["mutations"], Ctx>;
8
- createContext: (port: MessagePort) => Ctx | Promise<Ctx>;
9
- presenceHandler?: PresenceHandler;
10
- };
11
- /**
12
- * Set up a SharedWorker server for RPC communication.
13
- * This creates a shared Graph that all connected tabs can interact with.
14
- *
15
- * @example
16
- * ```typescript
17
- * // worker.ts
18
- * const { graph } = setupSharedWorker({
19
- * streams: {
20
- * todos: async (args, ctx) => new ReactiveSourceAdapter(source, iso),
21
- * },
22
- * mutations: {
23
- * addTodo: async (args, ctx) => ({ success: true, value: newTodo }),
24
- * },
25
- * createContext: (port) => ({ portId: crypto.randomUUID() }),
26
- * });
27
- * ```
28
- */
29
- declare function setupSharedWorker<Defs extends RPCDefinition, Ctx = void>(options: SharedWorkerServerOptions<Defs, Ctx>, graph: Graph): void;
30
-
31
- export { type SharedWorkerServerOptions, setupSharedWorker };
@@ -1,31 +0,0 @@
1
- import { Graph } from 'derivation';
2
- import { R as RPCDefinition, g as StreamEndpoints, c as MutationEndpoints } from './stream-types-Q_EqNLtO.js';
3
- import { P as PresenceHandler } from './presence-manager-4LlEyuGp.js';
4
-
5
- type SharedWorkerServerOptions<Defs extends RPCDefinition, Ctx = void> = {
6
- streams: StreamEndpoints<Defs["streams"], Ctx>;
7
- mutations: MutationEndpoints<Defs["mutations"], Ctx>;
8
- createContext: (port: MessagePort) => Ctx | Promise<Ctx>;
9
- presenceHandler?: PresenceHandler;
10
- };
11
- /**
12
- * Set up a SharedWorker server for RPC communication.
13
- * This creates a shared Graph that all connected tabs can interact with.
14
- *
15
- * @example
16
- * ```typescript
17
- * // worker.ts
18
- * const { graph } = setupSharedWorker({
19
- * streams: {
20
- * todos: async (args, ctx) => new ReactiveSourceAdapter(source, iso),
21
- * },
22
- * mutations: {
23
- * addTodo: async (args, ctx) => ({ success: true, value: newTodo }),
24
- * },
25
- * createContext: (port) => ({ portId: crypto.randomUUID() }),
26
- * });
27
- * ```
28
- */
29
- declare function setupSharedWorker<Defs extends RPCDefinition, Ctx = void>(options: SharedWorkerServerOptions<Defs, Ctx>, graph: Graph): void;
30
-
31
- export { type SharedWorkerServerOptions, setupSharedWorker };
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/client-message.ts","../src/server-message.ts","../src/shared-worker-client-handler.ts","../src/weak-list.ts","../src/messageport-transport.ts","../src/shared-worker-server.ts"],"sourcesContent":["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 { 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\";\nimport { Transport } from \"./transport.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 transport: Transport;\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 transport: Transport,\n context: Ctx,\n streamEndpoints: StreamEndpoints<Defs[\"streams\"], Ctx>,\n mutationEndpoints: MutationEndpoints<Defs[\"mutations\"], Ctx>,\n presenceHandler?: PresenceHandler,\n ) {\n this.transport = transport;\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.transport.onMessage((data: string) => this.handleMessage(data));\n this.transport.onClose(() => 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(\n `Mutation \"${name}\" (${id}) completed successfully`,\n );\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(`[ClientHandler] Sending delta with ${Object.keys(changes).length} changes for streams: ${Object.keys(changes).join(\", \")}`);\n this.sendMessage(ServerMessage.delta(changes));\n }\n }\n\n sendMessage(message: ServerMessage) {\n if (this.closed) return;\n this.transport.send(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(`[ClientHandler] Cleaning up ${this.streams.size} active streams`);\n this.streams.clear();\n\n try {\n this.transport.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 { Transport } from \"./transport.js\";\n\n/**\n * Transport implementation for MessagePort (SharedWorker communication).\n */\nexport class MessagePortTransport implements Transport {\n constructor(private port: MessagePort) {}\n\n send(data: string): void {\n console.log(\"[MessagePortTransport] Sending:\", data.substring(0, 100) + (data.length > 100 ? \"...\" : \"\"));\n this.port.postMessage(data);\n }\n\n onMessage(handler: (data: string) => void): void {\n this.port.onmessage = (event: MessageEvent) => {\n console.log(\"[MessagePortTransport] Received:\", event.data.substring(0, 100) + (event.data.length > 100 ? \"...\" : \"\"));\n handler(event.data);\n };\n }\n\n onClose(handler: () => void): void {\n // MessagePort doesn't have a reliable close event\n // We'll use messageerror as a signal, though it's not perfect\n this.port.onmessageerror = handler;\n }\n\n close(): void {\n this.port.close();\n }\n\n // MessagePort doesn't provide bufferedAmount\n get bufferedAmount(): undefined {\n return undefined;\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\";\nimport { MessagePortTransport } from \"./messageport-transport.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 transport and client handler\n const transport = new MessagePortTransport(port);\n client = new SharedWorkerClientHandler<Defs, Ctx>(\n transport,\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":["z","HeartbeatMessageSchema"]}
@@ -1,19 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __copyProps = (to, from, except, desc) => {
7
- if (from && typeof from === "object" || typeof from === "function") {
8
- for (let key of __getOwnPropNames(from))
9
- if (!__hasOwnProp.call(to, key) && key !== except)
10
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
- }
12
- return to;
13
- };
14
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
-
16
- // src/transport.ts
17
- var transport_exports = {};
18
- module.exports = __toCommonJS(transport_exports);
19
- //# sourceMappingURL=transport.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/transport.ts"],"sourcesContent":["/**\n * Transport abstraction for RPC communication.\n * Allows the same RPC system to work over WebSocket or MessagePort.\n */\nexport interface Transport {\n /**\n * Send a string message through the transport.\n */\n send(data: string): void;\n\n /**\n * Register a handler for incoming messages.\n */\n onMessage(handler: (data: string) => void): void;\n\n /**\n * Register a handler for transport closure/disconnection.\n */\n onClose(handler: () => void): void;\n\n /**\n * Close the transport connection.\n */\n close(): void;\n\n /**\n * Number of bytes buffered to be sent (optional, used for flow control).\n * MessagePort doesn't provide this, so it's optional.\n */\n readonly bufferedAmount?: number;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -1,29 +0,0 @@
1
- /**
2
- * Transport abstraction for RPC communication.
3
- * Allows the same RPC system to work over WebSocket or MessagePort.
4
- */
5
- interface Transport {
6
- /**
7
- * Send a string message through the transport.
8
- */
9
- send(data: string): void;
10
- /**
11
- * Register a handler for incoming messages.
12
- */
13
- onMessage(handler: (data: string) => void): void;
14
- /**
15
- * Register a handler for transport closure/disconnection.
16
- */
17
- onClose(handler: () => void): void;
18
- /**
19
- * Close the transport connection.
20
- */
21
- close(): void;
22
- /**
23
- * Number of bytes buffered to be sent (optional, used for flow control).
24
- * MessagePort doesn't provide this, so it's optional.
25
- */
26
- readonly bufferedAmount?: number;
27
- }
28
-
29
- export type { Transport };
@@ -1,29 +0,0 @@
1
- /**
2
- * Transport abstraction for RPC communication.
3
- * Allows the same RPC system to work over WebSocket or MessagePort.
4
- */
5
- interface Transport {
6
- /**
7
- * Send a string message through the transport.
8
- */
9
- send(data: string): void;
10
- /**
11
- * Register a handler for incoming messages.
12
- */
13
- onMessage(handler: (data: string) => void): void;
14
- /**
15
- * Register a handler for transport closure/disconnection.
16
- */
17
- onClose(handler: () => void): void;
18
- /**
19
- * Close the transport connection.
20
- */
21
- close(): void;
22
- /**
23
- * Number of bytes buffered to be sent (optional, used for flow control).
24
- * MessagePort doesn't provide this, so it's optional.
25
- */
26
- readonly bufferedAmount?: number;
27
- }
28
-
29
- export type { Transport };
package/dist/transport.js DELETED
@@ -1 +0,0 @@
1
- //# sourceMappingURL=transport.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/web-socket-server.ts","../src/client-message.ts","../src/server-message.ts","../src/queue.ts","../src/rate-limiter.ts","../src/client-handler.ts","../src/weak-list.ts","../src/node-web-socket-transport.ts"],"sourcesContent":["import { parse } from \"url\";\nimport { Server, IncomingMessage } from \"http\";\nimport { WebSocketServer, WebSocket, RawData } from \"ws\";\nimport { ClientHandler } from \"./client-handler.js\";\nimport WeakList from \"./weak-list.js\";\nimport { StreamEndpoints, MutationEndpoints, RPCDefinition } from \"./stream-types.js\";\nimport { Graph } from \"derivation\";\nimport { PresenceHandler } from \"./presence-manager.js\";\nimport { NodeWebSocketTransport } from \"./node-web-socket-transport.js\";\n\nexport type WebSocketServerOptions<Ctx> = {\n createContext: (ws: WebSocket, req: IncomingMessage) => Ctx | Promise<Ctx>;\n presenceHandler?: PresenceHandler;\n path?: string;\n};\n\nexport function setupWebSocketServer<Defs extends RPCDefinition, Ctx = void>(\n graph: Graph,\n server: Server,\n streamEndpoints: StreamEndpoints<Defs[\"streams\"], Ctx>,\n mutationEndpoints: MutationEndpoints<Defs[\"mutations\"], Ctx>,\n options: WebSocketServerOptions<Ctx>,\n) {\n const { createContext, presenceHandler, path = \"/api/ws\" } = options;\n const clients = new WeakList<ClientHandler<Defs, Ctx>>();\n\n graph.afterStep(() => {\n for (const client of clients) {\n client.handleStep();\n }\n });\n\n const wss = new WebSocketServer({ noServer: true, maxPayload: 100 * 1024 });\n\n // Handle WebSocket connections for reactive streams\n wss.on(\"connection\", (ws, req) => {\n const { pathname } = parse(req.url || \"/\", true);\n if (pathname === path) {\n const messageBuffer: RawData[] = [];\n let client: ClientHandler<Defs, Ctx> | null = null;\n\n // Set up temporary message handler to buffer messages\n const tempMessageHandler = (msg: RawData) => {\n messageBuffer.push(msg);\n };\n ws.on(\"message\", tempMessageHandler);\n\n // Create context (handle both sync and async)\n Promise.resolve(createContext(ws, req))\n .then((context) => {\n // Remove temporary handler\n ws.removeListener(\"message\", tempMessageHandler);\n\n // Create transport and client handler\n const transport = new NodeWebSocketTransport(ws);\n client = new ClientHandler<Defs, Ctx>(\n transport,\n context,\n streamEndpoints,\n mutationEndpoints,\n presenceHandler,\n );\n clients.add(client);\n\n // Process buffered messages\n for (const msg of messageBuffer) {\n client.handleMessage(msg.toString());\n }\n messageBuffer.length = 0;\n })\n .catch((err) => {\n console.error(\"Error creating context:\", err);\n ws.close();\n });\n }\n });\n\n // Handle HTTP upgrade (for /api/ws)\n server.on(\"upgrade\", (req, socket, head) => {\n const { pathname } = parse(req.url || \"/\", true);\n\n if (pathname === \"/api/ws\") {\n wss.handleUpgrade(req, socket, head, (ws) => {\n wss.emit(\"connection\", ws, req);\n });\n } else {\n socket.destroy();\n }\n });\n}\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 { 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","export class Queue<T> {\n private front: T[] = [];\n private back: T[] = [];\n\n get length(): number {\n return this.front.length + this.back.length;\n }\n\n isEmpty(): boolean {\n return this.front.length === 0 && this.back.length === 0;\n }\n\n push(item: T): void {\n this.front.push(item);\n }\n\n peek(): T | undefined {\n if (this.back.length === 0) {\n if (this.front.length === 0) {\n return undefined;\n }\n return this.front[0];\n }\n return this.back[this.back.length - 1];\n }\n\n pop(): T | undefined {\n if (this.back.length === 0) {\n // Reverse front and swap to back\n this.back = this.front.reverse();\n this.front = [];\n }\n return this.back.pop();\n }\n}\n","import { Queue } from \"./queue.js\";\n\nexport class RateLimiter {\n private readonly timestamps = new Queue<bigint>();\n private readonly maxOccurrences: number;\n private readonly windowNanos: bigint;\n\n constructor(maxOccurrences: number, windowSeconds: number) {\n this.maxOccurrences = maxOccurrences;\n this.windowNanos = BigInt(windowSeconds) * BigInt(1_000_000_000);\n }\n\n trigger(): boolean {\n const now = process.hrtime.bigint();\n\n const cutoff = now - this.windowNanos;\n while (!this.timestamps.isEmpty()) {\n const oldest = this.timestamps.peek();\n if (oldest === undefined || oldest >= cutoff) {\n break;\n }\n this.timestamps.pop();\n }\n\n if (this.timestamps.length >= this.maxOccurrences) {\n return true;\n }\n\n this.timestamps.push(now);\n\n return false;\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 { RateLimiter } from \"./rate-limiter.js\";\nimport { PresenceHandler } from \"./presence-manager.js\";\nimport { Transport } from \"./transport.js\";\n\nexport class ClientHandler<Defs extends RPCDefinition, Ctx = void> {\n private readonly transport: Transport;\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 private heartbeatTimeout: NodeJS.Timeout | undefined;\n private inactivityTimeout: NodeJS.Timeout | undefined;\n private readonly rateLimiter: RateLimiter;\n\n constructor(\n transport: Transport,\n context: Ctx,\n streamEndpoints: StreamEndpoints<Defs[\"streams\"], Ctx>,\n mutationEndpoints: MutationEndpoints<Defs[\"mutations\"], Ctx>,\n presenceHandler?: PresenceHandler,\n ) {\n this.transport = transport;\n this.context = context;\n this.streamEndpoints = streamEndpoints;\n this.mutationEndpoints = mutationEndpoints;\n this.presenceHandler = presenceHandler;\n this.rateLimiter = new RateLimiter(100, 300); // 100 messages over 5 minutes\n\n console.log(\"new client connected\");\n\n // Set up transport handlers\n this.transport.onMessage((data: string) => this.handleMessage(data));\n this.transport.onClose(() => this.handleDisconnect());\n\n this.resetHeartbeat();\n this.resetInactivity();\n }\n\n private resetHeartbeat() {\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n }\n\n this.heartbeatTimeout = setTimeout(() => {\n this.sendMessage(ServerMessage.heartbeat());\n }, 10_000);\n }\n\n private resetInactivity() {\n if (this.inactivityTimeout) {\n clearTimeout(this.inactivityTimeout);\n }\n\n this.inactivityTimeout = setTimeout(() => {\n this.close();\n }, 30_000);\n }\n\n handleMessage(message: string) {\n this.resetInactivity();\n\n // Check rate limit\n if (this.rateLimiter.trigger()) {\n console.log(\"Rate limit exceeded, closing connection\");\n this.close();\n return;\n }\n\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 (err) {\n console.error(\"Invalid client message:\", err);\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(\n `Mutation \\\"${name}\\\" (${id}) completed successfully`,\n );\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 this.sendMessage(ServerMessage.delta(changes));\n }\n }\n\n sendMessage(message: ServerMessage) {\n this.resetHeartbeat();\n\n if (!this.closed) {\n // Check buffer if available (WebSocket provides this, MessagePort doesn't)\n if (\n this.transport.bufferedAmount !== undefined &&\n this.transport.bufferedAmount > 100 * 1024\n ) {\n console.log(\"Send buffer exceeded 100KB, closing connection\");\n this.close();\n return;\n }\n\n try {\n this.transport.send(JSON.stringify(message));\n } catch (err) {\n console.error(\"Failed to send message:\", err);\n this.close();\n }\n }\n }\n\n private handleDisconnect() {\n console.log(\"client disconnected\");\n this.close();\n }\n\n close() {\n if (this.closed) return;\n this.closed = true;\n clearTimeout(this.heartbeatTimeout);\n clearTimeout(this.inactivityTimeout);\n\n if (this.presenceHandler && this.currentPresence !== undefined) {\n this.presenceHandler.remove(this.currentPresence);\n }\n\n try {\n this.transport.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 { WebSocket, RawData } from \"ws\";\nimport { Transport } from \"./transport.js\";\n\n/**\n * Transport implementation for Node.js WebSocket (server-side using 'ws' library).\n */\nexport class NodeWebSocketTransport implements Transport {\n private messageHandlerSet = false;\n private closeHandlerSet = false;\n\n constructor(private ws: WebSocket) {}\n\n send(data: string): void {\n this.ws.send(data);\n }\n\n onMessage(handler: (data: string) => void): void {\n if (!this.messageHandlerSet) {\n this.ws.on(\"message\", (data: RawData) => {\n handler(data.toString());\n });\n this.messageHandlerSet = true;\n }\n }\n\n onClose(handler: () => void): void {\n if (!this.closeHandlerSet) {\n this.ws.on(\"close\", handler);\n this.closeHandlerSet = true;\n }\n }\n\n close(): void {\n this.ws.close();\n }\n\n get bufferedAmount(): number {\n return this.ws.bufferedAmount;\n }\n}\n"],"mappings":"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","names":["import_zod","HeartbeatMessageSchema"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/web-socket-server.ts","../src/client-message.ts","../src/server-message.ts","../src/queue.ts","../src/rate-limiter.ts","../src/client-handler.ts","../src/weak-list.ts","../src/node-web-socket-transport.ts"],"sourcesContent":["import { parse } from \"url\";\nimport { Server, IncomingMessage } from \"http\";\nimport { WebSocketServer, WebSocket, RawData } from \"ws\";\nimport { ClientHandler } from \"./client-handler.js\";\nimport WeakList from \"./weak-list.js\";\nimport { StreamEndpoints, MutationEndpoints, RPCDefinition } from \"./stream-types.js\";\nimport { Graph } from \"derivation\";\nimport { PresenceHandler } from \"./presence-manager.js\";\nimport { NodeWebSocketTransport } from \"./node-web-socket-transport.js\";\n\nexport type WebSocketServerOptions<Ctx> = {\n createContext: (ws: WebSocket, req: IncomingMessage) => Ctx | Promise<Ctx>;\n presenceHandler?: PresenceHandler;\n path?: string;\n};\n\nexport function setupWebSocketServer<Defs extends RPCDefinition, Ctx = void>(\n graph: Graph,\n server: Server,\n streamEndpoints: StreamEndpoints<Defs[\"streams\"], Ctx>,\n mutationEndpoints: MutationEndpoints<Defs[\"mutations\"], Ctx>,\n options: WebSocketServerOptions<Ctx>,\n) {\n const { createContext, presenceHandler, path = \"/api/ws\" } = options;\n const clients = new WeakList<ClientHandler<Defs, Ctx>>();\n\n graph.afterStep(() => {\n for (const client of clients) {\n client.handleStep();\n }\n });\n\n const wss = new WebSocketServer({ noServer: true, maxPayload: 100 * 1024 });\n\n // Handle WebSocket connections for reactive streams\n wss.on(\"connection\", (ws, req) => {\n const { pathname } = parse(req.url || \"/\", true);\n if (pathname === path) {\n const messageBuffer: RawData[] = [];\n let client: ClientHandler<Defs, Ctx> | null = null;\n\n // Set up temporary message handler to buffer messages\n const tempMessageHandler = (msg: RawData) => {\n messageBuffer.push(msg);\n };\n ws.on(\"message\", tempMessageHandler);\n\n // Create context (handle both sync and async)\n Promise.resolve(createContext(ws, req))\n .then((context) => {\n // Remove temporary handler\n ws.removeListener(\"message\", tempMessageHandler);\n\n // Create transport and client handler\n const transport = new NodeWebSocketTransport(ws);\n client = new ClientHandler<Defs, Ctx>(\n transport,\n context,\n streamEndpoints,\n mutationEndpoints,\n presenceHandler,\n );\n clients.add(client);\n\n // Process buffered messages\n for (const msg of messageBuffer) {\n client.handleMessage(msg.toString());\n }\n messageBuffer.length = 0;\n })\n .catch((err) => {\n console.error(\"Error creating context:\", err);\n ws.close();\n });\n }\n });\n\n // Handle HTTP upgrade (for /api/ws)\n server.on(\"upgrade\", (req, socket, head) => {\n const { pathname } = parse(req.url || \"/\", true);\n\n if (pathname === \"/api/ws\") {\n wss.handleUpgrade(req, socket, head, (ws) => {\n wss.emit(\"connection\", ws, req);\n });\n } else {\n socket.destroy();\n }\n });\n}\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 { 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","export class Queue<T> {\n private front: T[] = [];\n private back: T[] = [];\n\n get length(): number {\n return this.front.length + this.back.length;\n }\n\n isEmpty(): boolean {\n return this.front.length === 0 && this.back.length === 0;\n }\n\n push(item: T): void {\n this.front.push(item);\n }\n\n peek(): T | undefined {\n if (this.back.length === 0) {\n if (this.front.length === 0) {\n return undefined;\n }\n return this.front[0];\n }\n return this.back[this.back.length - 1];\n }\n\n pop(): T | undefined {\n if (this.back.length === 0) {\n // Reverse front and swap to back\n this.back = this.front.reverse();\n this.front = [];\n }\n return this.back.pop();\n }\n}\n","import { Queue } from \"./queue.js\";\n\nexport class RateLimiter {\n private readonly timestamps = new Queue<bigint>();\n private readonly maxOccurrences: number;\n private readonly windowNanos: bigint;\n\n constructor(maxOccurrences: number, windowSeconds: number) {\n this.maxOccurrences = maxOccurrences;\n this.windowNanos = BigInt(windowSeconds) * BigInt(1_000_000_000);\n }\n\n trigger(): boolean {\n const now = process.hrtime.bigint();\n\n const cutoff = now - this.windowNanos;\n while (!this.timestamps.isEmpty()) {\n const oldest = this.timestamps.peek();\n if (oldest === undefined || oldest >= cutoff) {\n break;\n }\n this.timestamps.pop();\n }\n\n if (this.timestamps.length >= this.maxOccurrences) {\n return true;\n }\n\n this.timestamps.push(now);\n\n return false;\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 { RateLimiter } from \"./rate-limiter.js\";\nimport { PresenceHandler } from \"./presence-manager.js\";\nimport { Transport } from \"./transport.js\";\n\nexport class ClientHandler<Defs extends RPCDefinition, Ctx = void> {\n private readonly transport: Transport;\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 private heartbeatTimeout: NodeJS.Timeout | undefined;\n private inactivityTimeout: NodeJS.Timeout | undefined;\n private readonly rateLimiter: RateLimiter;\n\n constructor(\n transport: Transport,\n context: Ctx,\n streamEndpoints: StreamEndpoints<Defs[\"streams\"], Ctx>,\n mutationEndpoints: MutationEndpoints<Defs[\"mutations\"], Ctx>,\n presenceHandler?: PresenceHandler,\n ) {\n this.transport = transport;\n this.context = context;\n this.streamEndpoints = streamEndpoints;\n this.mutationEndpoints = mutationEndpoints;\n this.presenceHandler = presenceHandler;\n this.rateLimiter = new RateLimiter(100, 300); // 100 messages over 5 minutes\n\n console.log(\"new client connected\");\n\n // Set up transport handlers\n this.transport.onMessage((data: string) => this.handleMessage(data));\n this.transport.onClose(() => this.handleDisconnect());\n\n this.resetHeartbeat();\n this.resetInactivity();\n }\n\n private resetHeartbeat() {\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n }\n\n this.heartbeatTimeout = setTimeout(() => {\n this.sendMessage(ServerMessage.heartbeat());\n }, 10_000);\n }\n\n private resetInactivity() {\n if (this.inactivityTimeout) {\n clearTimeout(this.inactivityTimeout);\n }\n\n this.inactivityTimeout = setTimeout(() => {\n this.close();\n }, 30_000);\n }\n\n handleMessage(message: string) {\n this.resetInactivity();\n\n // Check rate limit\n if (this.rateLimiter.trigger()) {\n console.log(\"Rate limit exceeded, closing connection\");\n this.close();\n return;\n }\n\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 (err) {\n console.error(\"Invalid client message:\", err);\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(\n `Mutation \\\"${name}\\\" (${id}) completed successfully`,\n );\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 this.sendMessage(ServerMessage.delta(changes));\n }\n }\n\n sendMessage(message: ServerMessage) {\n this.resetHeartbeat();\n\n if (!this.closed) {\n // Check buffer if available (WebSocket provides this, MessagePort doesn't)\n if (\n this.transport.bufferedAmount !== undefined &&\n this.transport.bufferedAmount > 100 * 1024\n ) {\n console.log(\"Send buffer exceeded 100KB, closing connection\");\n this.close();\n return;\n }\n\n try {\n this.transport.send(JSON.stringify(message));\n } catch (err) {\n console.error(\"Failed to send message:\", err);\n this.close();\n }\n }\n }\n\n private handleDisconnect() {\n console.log(\"client disconnected\");\n this.close();\n }\n\n close() {\n if (this.closed) return;\n this.closed = true;\n clearTimeout(this.heartbeatTimeout);\n clearTimeout(this.inactivityTimeout);\n\n if (this.presenceHandler && this.currentPresence !== undefined) {\n this.presenceHandler.remove(this.currentPresence);\n }\n\n try {\n this.transport.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 { WebSocket, RawData } from \"ws\";\nimport { Transport } from \"./transport.js\";\n\n/**\n * Transport implementation for Node.js WebSocket (server-side using 'ws' library).\n */\nexport class NodeWebSocketTransport implements Transport {\n private messageHandlerSet = false;\n private closeHandlerSet = false;\n\n constructor(private ws: WebSocket) {}\n\n send(data: string): void {\n this.ws.send(data);\n }\n\n onMessage(handler: (data: string) => void): void {\n if (!this.messageHandlerSet) {\n this.ws.on(\"message\", (data: RawData) => {\n handler(data.toString());\n });\n this.messageHandlerSet = true;\n }\n }\n\n onClose(handler: () => void): void {\n if (!this.closeHandlerSet) {\n this.ws.on(\"close\", handler);\n this.closeHandlerSet = true;\n }\n }\n\n close(): void {\n this.ws.close();\n }\n\n get bufferedAmount(): number {\n return this.ws.bufferedAmount;\n }\n}\n"],"mappings":"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","names":["z","HeartbeatMessageSchema"]}
@@ -1,52 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/web-socket-transport.ts
21
- var web_socket_transport_exports = {};
22
- __export(web_socket_transport_exports, {
23
- WebSocketTransport: () => WebSocketTransport
24
- });
25
- module.exports = __toCommonJS(web_socket_transport_exports);
26
- var WebSocketTransport = class {
27
- constructor(ws) {
28
- this.ws = ws;
29
- }
30
- send(data) {
31
- this.ws.send(data);
32
- }
33
- onMessage(handler) {
34
- this.ws.onmessage = (event) => {
35
- handler(event.data);
36
- };
37
- }
38
- onClose(handler) {
39
- this.ws.onclose = handler;
40
- }
41
- close() {
42
- this.ws.close();
43
- }
44
- get bufferedAmount() {
45
- return this.ws.bufferedAmount;
46
- }
47
- };
48
- // Annotate the CommonJS export names for ESM import in node:
49
- 0 && (module.exports = {
50
- WebSocketTransport
51
- });
52
- //# sourceMappingURL=web-socket-transport.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/web-socket-transport.ts"],"sourcesContent":["import { Transport } from \"./transport.js\";\n\n/**\n * Transport implementation for browser WebSocket (client-side).\n */\nexport class WebSocketTransport implements Transport {\n constructor(private ws: globalThis.WebSocket) {}\n\n send(data: string): void {\n this.ws.send(data);\n }\n\n onMessage(handler: (data: string) => void): void {\n this.ws.onmessage = (event: MessageEvent) => {\n handler(event.data);\n };\n }\n\n onClose(handler: () => void): void {\n this.ws.onclose = handler;\n }\n\n close(): void {\n this.ws.close();\n }\n\n get bufferedAmount(): number {\n return this.ws.bufferedAmount;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAKO,IAAM,qBAAN,MAA8C;AAAA,EACnD,YAAoB,IAA0B;AAA1B;AAAA,EAA2B;AAAA,EAE/C,KAAK,MAAoB;AACvB,SAAK,GAAG,KAAK,IAAI;AAAA,EACnB;AAAA,EAEA,UAAU,SAAuC;AAC/C,SAAK,GAAG,YAAY,CAAC,UAAwB;AAC3C,cAAQ,MAAM,IAAI;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,QAAQ,SAA2B;AACjC,SAAK,GAAG,UAAU;AAAA,EACpB;AAAA,EAEA,QAAc;AACZ,SAAK,GAAG,MAAM;AAAA,EAChB;AAAA,EAEA,IAAI,iBAAyB;AAC3B,WAAO,KAAK,GAAG;AAAA,EACjB;AACF;","names":[]}
@@ -1,16 +0,0 @@
1
- import { Transport } from './transport.cjs';
2
-
3
- /**
4
- * Transport implementation for browser WebSocket (client-side).
5
- */
6
- declare class WebSocketTransport implements Transport {
7
- private ws;
8
- constructor(ws: globalThis.WebSocket);
9
- send(data: string): void;
10
- onMessage(handler: (data: string) => void): void;
11
- onClose(handler: () => void): void;
12
- close(): void;
13
- get bufferedAmount(): number;
14
- }
15
-
16
- export { WebSocketTransport };