@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.
- package/dist/index.cjs +0 -209
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +0 -2
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -208
- package/dist/index.js.map +1 -1
- package/dist/{shared-worker-server.cjs → shared-worker.cjs} +185 -47
- package/dist/shared-worker.cjs.map +1 -0
- package/dist/shared-worker.d.cts +68 -0
- package/dist/shared-worker.d.ts +68 -0
- package/dist/{shared-worker-server.js → shared-worker.js} +179 -43
- package/dist/shared-worker.js.map +1 -0
- package/dist/{shared-worker-client.cjs → websocket-client.cjs} +21 -55
- package/dist/websocket-client.cjs.map +1 -0
- package/dist/{client-DJZfuakf.d.cts → websocket-client.d.cts} +4 -5
- package/dist/{client-TPsVZH_B.d.ts → websocket-client.d.ts} +4 -5
- package/dist/{shared-worker-client.js → websocket-client.js} +16 -50
- package/dist/websocket-client.js.map +1 -0
- package/dist/{web-socket-server.cjs → websocket-server.cjs} +19 -49
- package/dist/websocket-server.cjs.map +1 -0
- package/dist/{web-socket-server.js → websocket-server.js} +19 -49
- package/dist/websocket-server.js.map +1 -0
- package/package.json +21 -29
- package/dist/shared-worker-client.cjs.map +0 -1
- package/dist/shared-worker-client.d.cts +0 -26
- package/dist/shared-worker-client.d.ts +0 -26
- package/dist/shared-worker-client.js.map +0 -1
- package/dist/shared-worker-server.cjs.map +0 -1
- package/dist/shared-worker-server.d.cts +0 -31
- package/dist/shared-worker-server.d.ts +0 -31
- package/dist/shared-worker-server.js.map +0 -1
- package/dist/transport.cjs +0 -19
- package/dist/transport.cjs.map +0 -1
- package/dist/transport.d.cts +0 -29
- package/dist/transport.d.ts +0 -29
- package/dist/transport.js +0 -1
- package/dist/transport.js.map +0 -1
- package/dist/web-socket-server.cjs.map +0 -1
- package/dist/web-socket-server.js.map +0 -1
- package/dist/web-socket-transport.cjs +0 -52
- package/dist/web-socket-transport.cjs.map +0 -1
- package/dist/web-socket-transport.d.cts +0 -16
- package/dist/web-socket-transport.d.ts +0 -16
- package/dist/web-socket-transport.js +0 -27
- package/dist/web-socket-transport.js.map +0 -1
- /package/dist/{web-socket-server.d.cts → websocket-server.d.cts} +0 -0
- /package/dist/{web-socket-server.d.ts → websocket-server.d.ts} +0 -0
|
@@ -33,6 +33,164 @@ var ClientMessageSchema = z.discriminatedUnion("type", [
|
|
|
33
33
|
function parseClientMessage(data) {
|
|
34
34
|
return ClientMessageSchema.parse(data);
|
|
35
35
|
}
|
|
36
|
+
var ClientMessage = {
|
|
37
|
+
subscribe: (id, name, args) => ({
|
|
38
|
+
type: "subscribe",
|
|
39
|
+
id,
|
|
40
|
+
name,
|
|
41
|
+
args
|
|
42
|
+
}),
|
|
43
|
+
unsubscribe: (id) => ({
|
|
44
|
+
type: "unsubscribe",
|
|
45
|
+
id
|
|
46
|
+
}),
|
|
47
|
+
call: (id, name, args) => ({
|
|
48
|
+
type: "call",
|
|
49
|
+
id,
|
|
50
|
+
name,
|
|
51
|
+
args
|
|
52
|
+
}),
|
|
53
|
+
heartbeat: () => ({
|
|
54
|
+
type: "heartbeat"
|
|
55
|
+
}),
|
|
56
|
+
presence: (data) => ({
|
|
57
|
+
type: "presence",
|
|
58
|
+
data
|
|
59
|
+
})
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// src/shared-worker/shared-worker-client.ts
|
|
63
|
+
function changer(sink, input) {
|
|
64
|
+
return (change) => {
|
|
65
|
+
const i = input.deref();
|
|
66
|
+
if (i) {
|
|
67
|
+
sink.apply(change, i);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
var SharedWorkerClient = class {
|
|
72
|
+
constructor(port, sinks, graph) {
|
|
73
|
+
this.port = port;
|
|
74
|
+
this.sinks = sinks;
|
|
75
|
+
this.graph = graph;
|
|
76
|
+
this.nextId = 1;
|
|
77
|
+
this.pendingStreams = /* @__PURE__ */ new Map();
|
|
78
|
+
this.pendingMutations = /* @__PURE__ */ new Map();
|
|
79
|
+
this.activeStreams = /* @__PURE__ */ new Map();
|
|
80
|
+
this.registry = new FinalizationRegistry(
|
|
81
|
+
([id, name]) => {
|
|
82
|
+
console.log(`\u{1F9F9} Stream ${id} (${name}) collected \u2014 unsubscribing`);
|
|
83
|
+
this.sendMessage(ClientMessage.unsubscribe(id));
|
|
84
|
+
this.activeStreams.delete(id);
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
this.port.onmessage = (event) => {
|
|
88
|
+
const message = JSON.parse(event.data);
|
|
89
|
+
this.handleMessage(message);
|
|
90
|
+
};
|
|
91
|
+
this.port.start();
|
|
92
|
+
}
|
|
93
|
+
handleMessage(message) {
|
|
94
|
+
switch (message.type) {
|
|
95
|
+
case "snapshot": {
|
|
96
|
+
console.log(`[Client] Received snapshot for stream ${message.id}`);
|
|
97
|
+
const resolve = this.pendingStreams.get(message.id);
|
|
98
|
+
if (resolve) {
|
|
99
|
+
resolve(message.snapshot);
|
|
100
|
+
this.pendingStreams.delete(message.id);
|
|
101
|
+
}
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
case "delta": {
|
|
105
|
+
const changeCount = Object.keys(message.changes).length;
|
|
106
|
+
console.log(
|
|
107
|
+
`[Client] Received delta with ${changeCount} changes for streams: ${Object.keys(message.changes).join(", ")}`
|
|
108
|
+
);
|
|
109
|
+
for (const [idStr, change] of Object.entries(message.changes)) {
|
|
110
|
+
const id = Number(idStr);
|
|
111
|
+
const sink = this.activeStreams.get(id);
|
|
112
|
+
if (sink && change && typeof change === "object") {
|
|
113
|
+
sink(change);
|
|
114
|
+
} else if (!sink) {
|
|
115
|
+
console.log(`\u{1F9F9} Sink ${id} GC'd \u2014 auto-unsubscribing`);
|
|
116
|
+
this.sendMessage(ClientMessage.unsubscribe(id));
|
|
117
|
+
this.activeStreams.delete(id);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
console.log("[Client] Stepping graph");
|
|
121
|
+
this.graph.step();
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
case "result": {
|
|
125
|
+
console.log(
|
|
126
|
+
`[Client] Received mutation result for call ${message.id}:`,
|
|
127
|
+
message.success ? "success" : "error"
|
|
128
|
+
);
|
|
129
|
+
const resolve = this.pendingMutations.get(message.id);
|
|
130
|
+
if (resolve) {
|
|
131
|
+
if (message.success) {
|
|
132
|
+
resolve({ success: true, value: message.value });
|
|
133
|
+
} else {
|
|
134
|
+
resolve({
|
|
135
|
+
success: false,
|
|
136
|
+
error: message.error || "Unknown error"
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
this.pendingMutations.delete(message.id);
|
|
140
|
+
}
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
case "heartbeat":
|
|
144
|
+
console.log("[Client] Received heartbeat");
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
sendMessage(message) {
|
|
149
|
+
this.port.postMessage(JSON.stringify(message));
|
|
150
|
+
}
|
|
151
|
+
async run(key, args) {
|
|
152
|
+
console.log(
|
|
153
|
+
`Running stream ${String(key)} with args ${JSON.stringify(args)}`
|
|
154
|
+
);
|
|
155
|
+
const id = this.nextId++;
|
|
156
|
+
this.sendMessage(ClientMessage.subscribe(id, String(key), args));
|
|
157
|
+
const snapshot = await new Promise((resolve) => {
|
|
158
|
+
this.pendingStreams.set(id, resolve);
|
|
159
|
+
});
|
|
160
|
+
const endpoint = this.sinks[key];
|
|
161
|
+
const sinkAdapter = endpoint(snapshot);
|
|
162
|
+
const { stream, input } = sinkAdapter.build();
|
|
163
|
+
const inputRef = new WeakRef(input);
|
|
164
|
+
this.activeStreams.set(id, changer(sinkAdapter, inputRef));
|
|
165
|
+
this.registry.register(input, [id, String(key)]);
|
|
166
|
+
return stream;
|
|
167
|
+
}
|
|
168
|
+
async call(key, args) {
|
|
169
|
+
console.log(
|
|
170
|
+
`Calling mutation ${String(key)} with args ${JSON.stringify(args)}`
|
|
171
|
+
);
|
|
172
|
+
const id = this.nextId++;
|
|
173
|
+
this.sendMessage(
|
|
174
|
+
ClientMessage.call(id, String(key), args)
|
|
175
|
+
);
|
|
176
|
+
const result = await new Promise((resolve) => {
|
|
177
|
+
this.pendingMutations.set(
|
|
178
|
+
id,
|
|
179
|
+
resolve
|
|
180
|
+
);
|
|
181
|
+
});
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
close() {
|
|
185
|
+
this.port.close();
|
|
186
|
+
}
|
|
187
|
+
setPresence(value) {
|
|
188
|
+
this.sendMessage(ClientMessage.presence(value));
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
function createSharedWorkerClient(port, sinks, graph) {
|
|
192
|
+
return new SharedWorkerClient(port, sinks, graph);
|
|
193
|
+
}
|
|
36
194
|
|
|
37
195
|
// src/server-message.ts
|
|
38
196
|
import { z as z2 } from "zod";
|
|
@@ -88,19 +246,21 @@ var ServerMessage = {
|
|
|
88
246
|
})
|
|
89
247
|
};
|
|
90
248
|
|
|
91
|
-
// src/shared-worker-client-handler.ts
|
|
249
|
+
// src/shared-worker/shared-worker-client-handler.ts
|
|
92
250
|
var SharedWorkerClientHandler = class {
|
|
93
|
-
constructor(
|
|
251
|
+
constructor(port, context, streamEndpoints, mutationEndpoints, presenceHandler) {
|
|
94
252
|
this.closed = false;
|
|
95
253
|
this.streams = /* @__PURE__ */ new Map();
|
|
96
|
-
this.
|
|
254
|
+
this.port = port;
|
|
97
255
|
this.context = context;
|
|
98
256
|
this.streamEndpoints = streamEndpoints;
|
|
99
257
|
this.mutationEndpoints = mutationEndpoints;
|
|
100
258
|
this.presenceHandler = presenceHandler;
|
|
101
259
|
console.log("new client connected");
|
|
102
|
-
this.
|
|
103
|
-
|
|
260
|
+
this.port.onmessage = (event) => {
|
|
261
|
+
this.handleMessage(event.data);
|
|
262
|
+
};
|
|
263
|
+
this.port.onmessageerror = () => this.handleDisconnect();
|
|
104
264
|
}
|
|
105
265
|
handleMessage(message) {
|
|
106
266
|
let data;
|
|
@@ -163,9 +323,7 @@ var SharedWorkerClientHandler = class {
|
|
|
163
323
|
).then((result) => {
|
|
164
324
|
if (result.success) {
|
|
165
325
|
this.sendMessage(ServerMessage.resultSuccess(id, result.value));
|
|
166
|
-
console.log(
|
|
167
|
-
`Mutation "${name}" (${id}) completed successfully`
|
|
168
|
-
);
|
|
326
|
+
console.log(`Mutation "${name}" (${id}) completed successfully`);
|
|
169
327
|
} else {
|
|
170
328
|
this.sendMessage(ServerMessage.resultError(id, result.error));
|
|
171
329
|
console.log(
|
|
@@ -209,13 +367,15 @@ var SharedWorkerClientHandler = class {
|
|
|
209
367
|
changes[id] = change;
|
|
210
368
|
}
|
|
211
369
|
if (Object.keys(changes).length > 0) {
|
|
212
|
-
console.log(
|
|
370
|
+
console.log(
|
|
371
|
+
`[ClientHandler] Sending delta with ${Object.keys(changes).length} changes for streams: ${Object.keys(changes).join(", ")}`
|
|
372
|
+
);
|
|
213
373
|
this.sendMessage(ServerMessage.delta(changes));
|
|
214
374
|
}
|
|
215
375
|
}
|
|
216
376
|
sendMessage(message) {
|
|
217
377
|
if (this.closed) return;
|
|
218
|
-
this.
|
|
378
|
+
this.port.postMessage(JSON.stringify(message));
|
|
219
379
|
}
|
|
220
380
|
handleDisconnect() {
|
|
221
381
|
this.close();
|
|
@@ -227,10 +387,12 @@ var SharedWorkerClientHandler = class {
|
|
|
227
387
|
if (this.presenceHandler && this.currentPresence) {
|
|
228
388
|
this.presenceHandler.remove(this.currentPresence);
|
|
229
389
|
}
|
|
230
|
-
console.log(
|
|
390
|
+
console.log(
|
|
391
|
+
`[ClientHandler] Cleaning up ${this.streams.size} active streams`
|
|
392
|
+
);
|
|
231
393
|
this.streams.clear();
|
|
232
394
|
try {
|
|
233
|
-
this.
|
|
395
|
+
this.port.close();
|
|
234
396
|
} catch (e) {
|
|
235
397
|
}
|
|
236
398
|
}
|
|
@@ -257,34 +419,7 @@ var WeakList = class {
|
|
|
257
419
|
}
|
|
258
420
|
};
|
|
259
421
|
|
|
260
|
-
// src/
|
|
261
|
-
var MessagePortTransport = class {
|
|
262
|
-
constructor(port) {
|
|
263
|
-
this.port = port;
|
|
264
|
-
}
|
|
265
|
-
send(data) {
|
|
266
|
-
console.log("[MessagePortTransport] Sending:", data.substring(0, 100) + (data.length > 100 ? "..." : ""));
|
|
267
|
-
this.port.postMessage(data);
|
|
268
|
-
}
|
|
269
|
-
onMessage(handler) {
|
|
270
|
-
this.port.onmessage = (event) => {
|
|
271
|
-
console.log("[MessagePortTransport] Received:", event.data.substring(0, 100) + (event.data.length > 100 ? "..." : ""));
|
|
272
|
-
handler(event.data);
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
onClose(handler) {
|
|
276
|
-
this.port.onmessageerror = handler;
|
|
277
|
-
}
|
|
278
|
-
close() {
|
|
279
|
-
this.port.close();
|
|
280
|
-
}
|
|
281
|
-
// MessagePort doesn't provide bufferedAmount
|
|
282
|
-
get bufferedAmount() {
|
|
283
|
-
return void 0;
|
|
284
|
-
}
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
// src/shared-worker-server.ts
|
|
422
|
+
// src/shared-worker/shared-worker-server.ts
|
|
288
423
|
function setupSharedWorker(options, graph) {
|
|
289
424
|
const { streams, mutations, createContext, presenceHandler } = options;
|
|
290
425
|
const clients = new WeakList();
|
|
@@ -307,9 +442,8 @@ function setupSharedWorker(options, graph) {
|
|
|
307
442
|
port.onmessage = tempMessageHandler;
|
|
308
443
|
Promise.resolve(createContext(port)).then((context) => {
|
|
309
444
|
console.log("[SharedWorker] Context created, setting up client handler");
|
|
310
|
-
const transport = new MessagePortTransport(port);
|
|
311
445
|
client = new SharedWorkerClientHandler(
|
|
312
|
-
|
|
446
|
+
port,
|
|
313
447
|
context,
|
|
314
448
|
streams,
|
|
315
449
|
mutations,
|
|
@@ -331,6 +465,8 @@ function setupSharedWorker(options, graph) {
|
|
|
331
465
|
};
|
|
332
466
|
}
|
|
333
467
|
export {
|
|
468
|
+
SharedWorkerClient,
|
|
469
|
+
createSharedWorkerClient,
|
|
334
470
|
setupSharedWorker
|
|
335
471
|
};
|
|
336
|
-
//# sourceMappingURL=shared-worker
|
|
472
|
+
//# sourceMappingURL=shared-worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client-message.ts","../src/shared-worker/shared-worker-client.ts","../src/server-message.ts","../src/shared-worker/shared-worker-client-handler.ts","../src/weak-list.ts","../src/shared-worker/shared-worker-server.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const SubscribeMessageSchema = z.object({\n type: z.literal(\"subscribe\"),\n id: z.number(),\n name: z.string(),\n args: z.looseObject({}),\n});\nexport type SubscribeMessage = z.infer<typeof SubscribeMessageSchema>;\n\nexport const UnsubscribeMessageSchema = z.object({\n type: z.literal(\"unsubscribe\"),\n id: z.number(),\n});\nexport type UnsubscribeMessage = z.infer<typeof UnsubscribeMessageSchema>;\n\nexport const HeartbeatMessageSchema = z.object({\n type: z.literal(\"heartbeat\"),\n});\nexport type HeartbeatMessage = z.infer<typeof HeartbeatMessageSchema>;\n\nexport const CallMessageSchema = z.object({\n type: z.literal(\"call\"),\n id: z.number(),\n name: z.string(),\n args: z.looseObject({}),\n});\nexport type CallMessage = z.infer<typeof CallMessageSchema>;\n\nexport const PresenceMessageSchema = z.object({\n type: z.literal(\"presence\"),\n data: z.looseObject({}),\n});\nexport type PresenceMessage = z.infer<typeof PresenceMessageSchema>;\n\nexport const ClientMessageSchema = z.discriminatedUnion(\"type\", [\n SubscribeMessageSchema,\n UnsubscribeMessageSchema,\n HeartbeatMessageSchema,\n CallMessageSchema,\n PresenceMessageSchema,\n]);\nexport type ClientMessage = z.infer<typeof ClientMessageSchema>;\n\nexport function parseClientMessage(data: unknown): ClientMessage {\n return ClientMessageSchema.parse(data);\n}\n\nexport const ClientMessage = {\n subscribe: (\n id: number,\n name: string,\n args: object,\n ): SubscribeMessage => ({\n type: \"subscribe\",\n id,\n name,\n args: args as Record<string, unknown>,\n }),\n unsubscribe: (id: number): UnsubscribeMessage => ({\n type: \"unsubscribe\",\n id,\n }),\n call: (\n id: number,\n name: string,\n args: object,\n ): CallMessage => ({\n type: \"call\",\n id,\n name,\n args: args as Record<string, unknown>,\n }),\n heartbeat: (): HeartbeatMessage => ({\n type: \"heartbeat\",\n }),\n presence: (data: object): PresenceMessage => ({\n type: \"presence\",\n data: data as Record<string, unknown>,\n }),\n};\n","import { ClientMessage } from \"../client-message.js\";\nimport { ServerMessage } from \"../server-message.js\";\nimport type { Graph } from \"derivation\";\nimport type {\n Sink,\n StreamSinks,\n RPCDefinition,\n MutationResult,\n} from \"../stream-types.js\";\n\nfunction changer<T extends object, I extends object>(\n sink: Sink<T, I>,\n input: WeakRef<I>,\n): (change: object) => void {\n return (change) => {\n const i = input.deref();\n if (i) {\n sink.apply(change, i);\n }\n };\n}\n\nexport class SharedWorkerClient<Defs extends RPCDefinition> {\n private nextId = 1;\n private pendingStreams = new Map<number, (snapshot: object) => void>();\n private pendingMutations = new Map<\n number,\n (result: MutationResult<unknown>) => void\n >();\n private activeStreams = new Map<number, (change: object) => void>();\n\n private registry = new FinalizationRegistry<[number, string]>(\n ([id, name]) => {\n console.log(`🧹 Stream ${id} (${name}) collected — unsubscribing`);\n this.sendMessage(ClientMessage.unsubscribe(id));\n this.activeStreams.delete(id);\n },\n );\n\n constructor(\n private port: MessagePort,\n private sinks: StreamSinks<Defs[\"streams\"]>,\n private graph: Graph,\n ) {\n this.port.onmessage = (event: MessageEvent) => {\n const message = JSON.parse(event.data as string) as ServerMessage;\n this.handleMessage(message);\n };\n this.port.start();\n }\n\n private handleMessage(message: ServerMessage) {\n switch (message.type) {\n case \"snapshot\": {\n console.log(`[Client] Received snapshot for stream ${message.id}`);\n const resolve = this.pendingStreams.get(message.id);\n if (resolve) {\n resolve(message.snapshot as object);\n this.pendingStreams.delete(message.id);\n }\n break;\n }\n case \"delta\": {\n const changeCount = Object.keys(message.changes).length;\n console.log(\n `[Client] Received delta with ${changeCount} changes for streams: ${Object.keys(message.changes).join(\", \")}`,\n );\n for (const [idStr, change] of Object.entries(message.changes)) {\n const id = Number(idStr);\n const sink = this.activeStreams.get(id);\n\n if (sink && change && typeof change === \"object\") {\n sink(change);\n } else if (!sink) {\n console.log(`🧹 Sink ${id} GC'd — auto-unsubscribing`);\n this.sendMessage(ClientMessage.unsubscribe(id));\n this.activeStreams.delete(id);\n }\n }\n console.log(\"[Client] Stepping graph\");\n this.graph.step();\n break;\n }\n case \"result\": {\n console.log(\n `[Client] Received mutation result for call ${message.id}:`,\n message.success ? \"success\" : \"error\",\n );\n const resolve = this.pendingMutations.get(message.id);\n if (resolve) {\n if (message.success) {\n resolve({ success: true, value: message.value });\n } else {\n resolve({\n success: false,\n error: message.error || \"Unknown error\",\n });\n }\n this.pendingMutations.delete(message.id);\n }\n break;\n }\n case \"heartbeat\":\n console.log(\"[Client] Received heartbeat\");\n break;\n }\n }\n\n private sendMessage(message: ClientMessage) {\n this.port.postMessage(JSON.stringify(message));\n }\n\n async run<Key extends keyof Defs[\"streams\"]>(\n key: Key,\n args: Defs[\"streams\"][Key][\"args\"],\n ): Promise<Defs[\"streams\"][Key][\"returnType\"]> {\n console.log(\n `Running stream ${String(key)} with args ${JSON.stringify(args)}`,\n );\n const id = this.nextId++;\n\n this.sendMessage(ClientMessage.subscribe(id, String(key), args));\n\n const snapshot = await new Promise<object>((resolve) => {\n this.pendingStreams.set(id, resolve);\n });\n\n const endpoint = this.sinks[key];\n const sinkAdapter = endpoint(snapshot);\n const { stream, input } = sinkAdapter.build();\n const inputRef = new WeakRef(input);\n this.activeStreams.set(id, changer(sinkAdapter, inputRef));\n this.registry.register(input, [id, String(key)]);\n\n return stream;\n }\n\n async call<Key extends keyof Defs[\"mutations\"]>(\n key: Key,\n args: Defs[\"mutations\"][Key][\"args\"],\n ): Promise<MutationResult<Defs[\"mutations\"][Key][\"result\"]>> {\n console.log(\n `Calling mutation ${String(key)} with args ${JSON.stringify(args)}`,\n );\n const id = this.nextId++;\n\n this.sendMessage(\n ClientMessage.call(id, String(key), args as Record<string, unknown>),\n );\n\n const result = await new Promise<\n MutationResult<Defs[\"mutations\"][Key][\"result\"]>\n >((resolve) => {\n this.pendingMutations.set(\n id,\n resolve as (result: MutationResult<unknown>) => void,\n );\n });\n\n return result;\n }\n\n close() {\n this.port.close();\n }\n\n setPresence(value: Record<string, unknown>): void {\n this.sendMessage(ClientMessage.presence(value));\n }\n}\n\n/**\n * Create a client connected to a SharedWorker.\n *\n * @example\n * ```typescript\n * // main.ts\n * const graph = new Graph();\n * const worker = new SharedWorker('/worker.js');\n *\n * const client = createSharedWorkerClient(worker.port, {\n * streams: {\n * todos: setSink(graph, todoIso),\n * },\n * }, graph);\n *\n * const todos = await client.run('todos', { filter: 'active' });\n * ```\n */\nexport function createSharedWorkerClient<Defs extends RPCDefinition>(\n port: MessagePort,\n sinks: StreamSinks<Defs[\"streams\"]>,\n graph: Graph,\n): SharedWorkerClient<Defs> {\n return new SharedWorkerClient<Defs>(port, sinks, graph);\n}\n","import { z } from \"zod\";\n\nexport const HeartbeatMessageSchema = z.object({\n type: z.literal(\"heartbeat\"),\n});\nexport type HeartbeatMessage = z.infer<typeof HeartbeatMessageSchema>;\n\nexport const SubscribedSchema = z.object({\n type: z.literal(\"snapshot\"),\n id: z.number(),\n snapshot: z.unknown(),\n});\nexport type SubscribedMessage = z.infer<typeof SubscribedSchema>;\n\nexport const DeltaMessageSchema = z.object({\n type: z.literal(\"delta\"),\n changes: z.record(z.number(), z.unknown()),\n});\nexport type DeltaMessage = z.infer<typeof DeltaMessageSchema>;\n\nexport const ResultMessageSchema = z.object({\n type: z.literal(\"result\"),\n id: z.number(),\n success: z.boolean(),\n value: z.unknown().optional(),\n error: z.string().optional(),\n});\nexport type ResultMessage = z.infer<typeof ResultMessageSchema>;\n\nexport const ServerMessageSchema = z.discriminatedUnion(\"type\", [\n HeartbeatMessageSchema,\n SubscribedSchema,\n DeltaMessageSchema,\n ResultMessageSchema,\n]);\nexport type ServerMessage = z.infer<typeof ServerMessageSchema>;\n\nexport const ServerMessage = {\n heartbeat: (): HeartbeatMessage => ({\n type: \"heartbeat\",\n }),\n subscribed: (id: number, snapshot: unknown): SubscribedMessage => ({\n type: \"snapshot\",\n id,\n snapshot,\n }),\n delta: (changes: Record<string, unknown>): DeltaMessage => ({\n type: \"delta\",\n changes: changes,\n }),\n resultSuccess: (id: number, value: unknown): ResultMessage => ({\n type: \"result\",\n id,\n success: true,\n value,\n }),\n resultError: (id: number, error: string): ResultMessage => ({\n type: \"result\",\n id,\n success: false,\n error,\n }),\n};\n","import { parseClientMessage, ClientMessage } from \"../client-message.js\";\nimport { ServerMessage } from \"../server-message.js\";\nimport {\n Source,\n StreamEndpoints,\n MutationEndpoints,\n RPCDefinition,\n} from \"../stream-types.js\";\nimport { PresenceHandler } from \"../presence-manager.js\";\n\n/**\n * Client handler for SharedWorker connections (browser-only).\n * Simplified version without rate limiting, heartbeats, or inactivity timeouts.\n * Designed for same-origin trusted connections.\n */\nexport class SharedWorkerClientHandler<Defs extends RPCDefinition, Ctx = void> {\n private readonly port: MessagePort;\n private readonly context: Ctx;\n private readonly streamEndpoints: StreamEndpoints<Defs[\"streams\"], Ctx>;\n private readonly mutationEndpoints: MutationEndpoints<Defs[\"mutations\"], Ctx>;\n private readonly presenceHandler?: PresenceHandler;\n private currentPresence?: Record<string, unknown>;\n private closed = false;\n private readonly streams = new Map<number, Source<unknown>>();\n\n constructor(\n port: MessagePort,\n context: Ctx,\n streamEndpoints: StreamEndpoints<Defs[\"streams\"], Ctx>,\n mutationEndpoints: MutationEndpoints<Defs[\"mutations\"], Ctx>,\n presenceHandler?: PresenceHandler,\n ) {\n this.port = port;\n this.context = context;\n this.streamEndpoints = streamEndpoints;\n this.mutationEndpoints = mutationEndpoints;\n this.presenceHandler = presenceHandler;\n\n console.log(\"new client connected\");\n\n // Set up transport handlers\n this.port.onmessage = (event: MessageEvent) => {\n this.handleMessage(event.data as string);\n };\n this.port.onmessageerror = () => this.handleDisconnect();\n }\n\n handleMessage(message: string) {\n let data: object;\n try {\n data = JSON.parse(message);\n } catch {\n console.error(\"Invalid JSON received:\", message);\n return this.close();\n }\n\n let parsed: ClientMessage;\n try {\n parsed = parseClientMessage(data);\n } catch (error) {\n console.error(\"Invalid client message:\", error);\n return this.close();\n }\n\n this.handleClientMessage(parsed);\n }\n\n async handleClientMessage(message: ClientMessage) {\n switch (message.type) {\n case \"subscribe\": {\n const { id, name, args } = message;\n\n if (!(name in this.streamEndpoints)) {\n console.error(`Unknown stream: ${name}`);\n this.close();\n return;\n }\n\n const endpoint = this.streamEndpoints[name as keyof Defs[\"streams\"]];\n\n try {\n const source = await endpoint(\n args as Defs[\"streams\"][keyof Defs[\"streams\"]][\"args\"],\n this.context,\n );\n this.streams.set(id, source);\n this.sendMessage(ServerMessage.subscribed(id, source.Snapshot));\n console.log(`Client subscribed to \"${name}\" (${id})`);\n } catch (err) {\n console.error(`Error building stream ${name}:`, err);\n this.close();\n }\n break;\n }\n\n case \"unsubscribe\": {\n const { id } = message;\n this.streams.delete(id);\n console.log(`Client unsubscribed from ${id}`);\n break;\n }\n\n case \"call\": {\n const { id, name, args } = message;\n\n if (!(name in this.mutationEndpoints)) {\n console.error(`Unknown mutation: ${name}`);\n this.close();\n return;\n }\n\n const endpoint =\n this.mutationEndpoints[name as keyof Defs[\"mutations\"]];\n\n endpoint(\n args as Defs[\"mutations\"][keyof Defs[\"mutations\"]][\"args\"],\n this.context,\n )\n .then((result) => {\n if (result.success) {\n this.sendMessage(ServerMessage.resultSuccess(id, result.value));\n console.log(`Mutation \"${name}\" (${id}) completed successfully`);\n } else {\n this.sendMessage(ServerMessage.resultError(id, result.error));\n console.log(\n `Mutation \"${name}\" (${id}) returned error: ${result.error}`,\n );\n }\n })\n .catch((err) => {\n console.error(\n `Unhandled exception in mutation \"${name}\" (${id}):`,\n err,\n );\n this.close();\n });\n break;\n }\n\n case \"heartbeat\":\n break;\n\n case \"presence\": {\n if (!this.presenceHandler) {\n console.error(\"Presence not configured\");\n this.close();\n return;\n }\n\n const { data } = message;\n\n if (this.currentPresence !== undefined) {\n this.presenceHandler.update(this.currentPresence, data);\n } else {\n this.presenceHandler.add(data);\n }\n\n this.currentPresence = data;\n break;\n }\n }\n }\n\n handleStep() {\n if (this.closed) return;\n const changes: Record<number, unknown> = {};\n\n for (const [id, source] of this.streams) {\n const change = source.LastChange;\n if (change === null) continue;\n changes[id] = change;\n }\n\n if (Object.keys(changes).length > 0) {\n console.log(\n `[ClientHandler] Sending delta with ${Object.keys(changes).length} changes for streams: ${Object.keys(changes).join(\", \")}`,\n );\n this.sendMessage(ServerMessage.delta(changes));\n }\n }\n\n sendMessage(message: ServerMessage) {\n if (this.closed) return;\n this.port.postMessage(JSON.stringify(message));\n }\n\n private handleDisconnect() {\n this.close();\n }\n\n close() {\n if (this.closed) return;\n console.log(\"[ClientHandler] Closing client connection\");\n this.closed = true;\n\n if (this.presenceHandler && this.currentPresence) {\n this.presenceHandler.remove(this.currentPresence);\n }\n\n console.log(\n `[ClientHandler] Cleaning up ${this.streams.size} active streams`,\n );\n this.streams.clear();\n\n try {\n this.port.close();\n } catch {}\n }\n}\n","export default class WeakList<T extends object> implements Iterable<T> {\n private items: WeakRef<T>[] = [];\n\n add(value: T): void {\n this.items.push(new WeakRef(value));\n }\n\n *[Symbol.iterator](): Iterator<T> {\n const newItems: WeakRef<T>[] = [];\n\n for (const ref of this.items) {\n const value = ref.deref();\n if (value !== undefined) {\n yield value;\n newItems.push(ref);\n }\n }\n\n this.items = newItems;\n }\n}\n","import { Graph } from \"derivation\";\nimport { SharedWorkerClientHandler } from \"./shared-worker-client-handler.js\";\nimport WeakList from \"../weak-list.js\";\nimport {\n StreamEndpoints,\n MutationEndpoints,\n RPCDefinition,\n} from \"../stream-types.js\";\nimport { PresenceHandler } from \"../presence-manager.js\";\n\nexport type SharedWorkerServerOptions<\n Defs extends RPCDefinition,\n Ctx = void,\n> = {\n streams: StreamEndpoints<Defs[\"streams\"], Ctx>;\n mutations: MutationEndpoints<Defs[\"mutations\"], Ctx>;\n createContext: (port: MessagePort) => Ctx | Promise<Ctx>;\n presenceHandler?: PresenceHandler;\n};\n\n/**\n * Set up a SharedWorker server for RPC communication.\n * This creates a shared Graph that all connected tabs can interact with.\n *\n * @example\n * ```typescript\n * // worker.ts\n * const { graph } = setupSharedWorker({\n * streams: {\n * todos: async (args, ctx) => new ReactiveSourceAdapter(source, iso),\n * },\n * mutations: {\n * addTodo: async (args, ctx) => ({ success: true, value: newTodo }),\n * },\n * createContext: (port) => ({ portId: crypto.randomUUID() }),\n * });\n * ```\n */\nexport function setupSharedWorker<Defs extends RPCDefinition, Ctx = void>(\n options: SharedWorkerServerOptions<Defs, Ctx>,\n graph: Graph,\n) {\n const { streams, mutations, createContext, presenceHandler } = options;\n\n const clients = new WeakList<SharedWorkerClientHandler<Defs, Ctx>>();\n\n // After each graph step, broadcast deltas to all connected clients\n graph.afterStep(() => {\n console.log(\"[SharedWorker] Broadcasting deltas to clients\");\n for (const client of clients) {\n client.handleStep();\n }\n });\n\n // Handle SharedWorker connections\n const globalScope = self as unknown as SharedWorkerGlobalScope;\n globalScope.onconnect = (event: MessageEvent) => {\n console.log(\"[SharedWorker] New client connecting...\");\n const port = event.ports[0];\n const messageBuffer: string[] = [];\n let client: SharedWorkerClientHandler<Defs, Ctx> | null = null;\n\n // Set up temporary message handler to buffer messages\n const tempMessageHandler = (e: MessageEvent) => {\n console.log(\"[SharedWorker] Buffering message during setup:\", e.data);\n messageBuffer.push(e.data);\n };\n port.onmessage = tempMessageHandler;\n\n // Create context (handle both sync and async)\n Promise.resolve(createContext(port))\n .then((context) => {\n console.log(\"[SharedWorker] Context created, setting up client handler\");\n // Create client handler\n client = new SharedWorkerClientHandler<Defs, Ctx>(\n port,\n context,\n streams,\n mutations,\n presenceHandler,\n );\n clients.add(client);\n console.log(\"[SharedWorker] Client handler registered\");\n\n // Process buffered messages\n console.log(`[SharedWorker] Processing ${messageBuffer.length} buffered messages`);\n for (const msg of messageBuffer) {\n client.handleMessage(msg);\n }\n messageBuffer.length = 0;\n\n // Start the port\n port.start();\n console.log(\"[SharedWorker] Client connection ready\");\n })\n .catch((err) => {\n console.error(\"[SharedWorker] Error creating context:\", err);\n port.close();\n });\n };\n}\n"],"mappings":"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","names":["z","HeartbeatMessageSchema"]}
|
|
@@ -17,12 +17,12 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
17
|
};
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
|
|
20
|
-
// src/
|
|
21
|
-
var
|
|
22
|
-
__export(
|
|
23
|
-
|
|
20
|
+
// src/websocket/web-socket-client.ts
|
|
21
|
+
var web_socket_client_exports = {};
|
|
22
|
+
__export(web_socket_client_exports, {
|
|
23
|
+
WebSocketClient: () => WebSocketClient
|
|
24
24
|
});
|
|
25
|
-
module.exports = __toCommonJS(
|
|
25
|
+
module.exports = __toCommonJS(web_socket_client_exports);
|
|
26
26
|
|
|
27
27
|
// src/client-message.ts
|
|
28
28
|
var import_zod = require("zod");
|
|
@@ -82,7 +82,7 @@ var ClientMessage = {
|
|
|
82
82
|
})
|
|
83
83
|
};
|
|
84
84
|
|
|
85
|
-
// src/client.ts
|
|
85
|
+
// src/websocket/web-socket-client.ts
|
|
86
86
|
function changer(sink, input) {
|
|
87
87
|
return (change) => {
|
|
88
88
|
const i = input.deref();
|
|
@@ -91,9 +91,9 @@ function changer(sink, input) {
|
|
|
91
91
|
}
|
|
92
92
|
};
|
|
93
93
|
}
|
|
94
|
-
var
|
|
95
|
-
constructor(
|
|
96
|
-
this.
|
|
94
|
+
var WebSocketClient = class {
|
|
95
|
+
constructor(ws, sinks, graph) {
|
|
96
|
+
this.ws = ws;
|
|
97
97
|
this.sinks = sinks;
|
|
98
98
|
this.graph = graph;
|
|
99
99
|
this.nextId = 1;
|
|
@@ -107,10 +107,10 @@ var Client = class {
|
|
|
107
107
|
this.activeStreams.delete(id);
|
|
108
108
|
}
|
|
109
109
|
);
|
|
110
|
-
this.
|
|
111
|
-
const message = JSON.parse(data);
|
|
110
|
+
this.ws.onmessage = (event) => {
|
|
111
|
+
const message = JSON.parse(event.data);
|
|
112
112
|
this.handleMessage(message);
|
|
113
|
-
}
|
|
113
|
+
};
|
|
114
114
|
this.resetHeartbeat();
|
|
115
115
|
this.resetInactivity();
|
|
116
116
|
}
|
|
@@ -134,7 +134,7 @@ var Client = class {
|
|
|
134
134
|
this.resetInactivity();
|
|
135
135
|
switch (message.type) {
|
|
136
136
|
case "snapshot": {
|
|
137
|
-
console.log(`[
|
|
137
|
+
console.log(`[WebSocketClient] Received snapshot for stream ${message.id}`);
|
|
138
138
|
const resolve = this.pendingStreams.get(message.id);
|
|
139
139
|
if (resolve) {
|
|
140
140
|
resolve(message.snapshot);
|
|
@@ -144,7 +144,7 @@ var Client = class {
|
|
|
144
144
|
}
|
|
145
145
|
case "delta": {
|
|
146
146
|
const changeCount = Object.keys(message.changes).length;
|
|
147
|
-
console.log(`[
|
|
147
|
+
console.log(`[WebSocketClient] Received delta with ${changeCount} changes for streams: ${Object.keys(message.changes).join(", ")}`);
|
|
148
148
|
for (const [idStr, change] of Object.entries(message.changes)) {
|
|
149
149
|
const id = Number(idStr);
|
|
150
150
|
const sink = this.activeStreams.get(id);
|
|
@@ -156,12 +156,12 @@ var Client = class {
|
|
|
156
156
|
this.activeStreams.delete(id);
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
|
-
console.log("[
|
|
159
|
+
console.log("[WebSocketClient] Stepping graph");
|
|
160
160
|
this.graph.step();
|
|
161
161
|
break;
|
|
162
162
|
}
|
|
163
163
|
case "result": {
|
|
164
|
-
console.log(`[
|
|
164
|
+
console.log(`[WebSocketClient] Received mutation result for call ${message.id}:`, message.success ? "success" : "error");
|
|
165
165
|
const resolve = this.pendingMutations.get(message.id);
|
|
166
166
|
if (resolve) {
|
|
167
167
|
if (message.success) {
|
|
@@ -177,13 +177,13 @@ var Client = class {
|
|
|
177
177
|
break;
|
|
178
178
|
}
|
|
179
179
|
case "heartbeat":
|
|
180
|
-
console.log("[
|
|
180
|
+
console.log("[WebSocketClient] Received heartbeat");
|
|
181
181
|
break;
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
184
|
sendMessage(message) {
|
|
185
185
|
this.resetHeartbeat();
|
|
186
|
-
this.
|
|
186
|
+
this.ws.send(JSON.stringify(message));
|
|
187
187
|
}
|
|
188
188
|
async run(key, args) {
|
|
189
189
|
console.log(
|
|
@@ -222,7 +222,7 @@ var Client = class {
|
|
|
222
222
|
clearTimeout(this.heartbeatTimeout);
|
|
223
223
|
clearTimeout(this.inactivityTimeout);
|
|
224
224
|
try {
|
|
225
|
-
this.
|
|
225
|
+
this.ws.close();
|
|
226
226
|
} catch (e) {
|
|
227
227
|
}
|
|
228
228
|
}
|
|
@@ -230,42 +230,8 @@ var Client = class {
|
|
|
230
230
|
this.sendMessage(ClientMessage.presence(value));
|
|
231
231
|
}
|
|
232
232
|
};
|
|
233
|
-
|
|
234
|
-
// src/messageport-transport.ts
|
|
235
|
-
var MessagePortTransport = class {
|
|
236
|
-
constructor(port) {
|
|
237
|
-
this.port = port;
|
|
238
|
-
}
|
|
239
|
-
send(data) {
|
|
240
|
-
console.log("[MessagePortTransport] Sending:", data.substring(0, 100) + (data.length > 100 ? "..." : ""));
|
|
241
|
-
this.port.postMessage(data);
|
|
242
|
-
}
|
|
243
|
-
onMessage(handler) {
|
|
244
|
-
this.port.onmessage = (event) => {
|
|
245
|
-
console.log("[MessagePortTransport] Received:", event.data.substring(0, 100) + (event.data.length > 100 ? "..." : ""));
|
|
246
|
-
handler(event.data);
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
onClose(handler) {
|
|
250
|
-
this.port.onmessageerror = handler;
|
|
251
|
-
}
|
|
252
|
-
close() {
|
|
253
|
-
this.port.close();
|
|
254
|
-
}
|
|
255
|
-
// MessagePort doesn't provide bufferedAmount
|
|
256
|
-
get bufferedAmount() {
|
|
257
|
-
return void 0;
|
|
258
|
-
}
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
// src/shared-worker-client.ts
|
|
262
|
-
function createSharedWorkerClient(port, sinks, graph) {
|
|
263
|
-
const transport = new MessagePortTransport(port);
|
|
264
|
-
port.start();
|
|
265
|
-
return new Client(transport, sinks, graph);
|
|
266
|
-
}
|
|
267
233
|
// Annotate the CommonJS export names for ESM import in node:
|
|
268
234
|
0 && (module.exports = {
|
|
269
|
-
|
|
235
|
+
WebSocketClient
|
|
270
236
|
});
|
|
271
|
-
//# sourceMappingURL=
|
|
237
|
+
//# sourceMappingURL=websocket-client.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/websocket/web-socket-client.ts","../src/client-message.ts"],"sourcesContent":["import { ClientMessage } from \"../client-message.js\";\nimport { ServerMessage } from \"../server-message.js\";\nimport type { Graph } from \"derivation\";\nimport type {\n Sink,\n StreamSinks,\n RPCDefinition,\n MutationResult,\n} from \"../stream-types.js\";\n\nfunction changer<T extends object, I extends object>(\n sink: Sink<T, I>,\n input: WeakRef<I>,\n): (change: object) => void {\n return (change) => {\n const i = input.deref();\n if (i) {\n sink.apply(change, i);\n }\n };\n}\n\nexport class WebSocketClient<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 ws: globalThis.WebSocket,\n private sinks: StreamSinks<Defs[\"streams\"]>,\n private graph: Graph,\n ) {\n this.ws.onmessage = (event: MessageEvent) => {\n const message = JSON.parse(event.data as string) 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(`[WebSocketClient] 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(`[WebSocketClient] 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(\"[WebSocketClient] Stepping graph\");\n this.graph.step();\n break;\n }\n case \"result\": {\n console.log(`[WebSocketClient] 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(\"[WebSocketClient] Received heartbeat\");\n break;\n }\n }\n\n private sendMessage(message: ClientMessage) {\n this.resetHeartbeat();\n this.ws.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.ws.close();\n } catch {}\n }\n\n setPresence(value: Record<string, unknown>): void {\n this.sendMessage(ClientMessage.presence(value));\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"],"mappings":"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","names":[]}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { Graph } from 'derivation';
|
|
2
2
|
import { R as RPCDefinition, h as StreamSinks, d as MutationResult } from './stream-types-Q_EqNLtO.cjs';
|
|
3
|
-
import { Transport } from './transport.cjs';
|
|
4
3
|
|
|
5
|
-
declare class
|
|
6
|
-
private
|
|
4
|
+
declare class WebSocketClient<Defs extends RPCDefinition> {
|
|
5
|
+
private ws;
|
|
7
6
|
private sinks;
|
|
8
7
|
private graph;
|
|
9
8
|
private nextId;
|
|
@@ -15,7 +14,7 @@ declare class Client<Defs extends RPCDefinition> {
|
|
|
15
14
|
private registry;
|
|
16
15
|
private resetHeartbeat;
|
|
17
16
|
private resetInactivity;
|
|
18
|
-
constructor(
|
|
17
|
+
constructor(ws: globalThis.WebSocket, sinks: StreamSinks<Defs["streams"]>, graph: Graph);
|
|
19
18
|
private handleMessage;
|
|
20
19
|
private sendMessage;
|
|
21
20
|
run<Key extends keyof Defs["streams"]>(key: Key, args: Defs["streams"][Key]["args"]): Promise<Defs["streams"][Key]["returnType"]>;
|
|
@@ -24,4 +23,4 @@ declare class Client<Defs extends RPCDefinition> {
|
|
|
24
23
|
setPresence(value: Record<string, unknown>): void;
|
|
25
24
|
}
|
|
26
25
|
|
|
27
|
-
export {
|
|
26
|
+
export { WebSocketClient };
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { Graph } from 'derivation';
|
|
2
2
|
import { R as RPCDefinition, h as StreamSinks, d as MutationResult } from './stream-types-Q_EqNLtO.js';
|
|
3
|
-
import { Transport } from './transport.js';
|
|
4
3
|
|
|
5
|
-
declare class
|
|
6
|
-
private
|
|
4
|
+
declare class WebSocketClient<Defs extends RPCDefinition> {
|
|
5
|
+
private ws;
|
|
7
6
|
private sinks;
|
|
8
7
|
private graph;
|
|
9
8
|
private nextId;
|
|
@@ -15,7 +14,7 @@ declare class Client<Defs extends RPCDefinition> {
|
|
|
15
14
|
private registry;
|
|
16
15
|
private resetHeartbeat;
|
|
17
16
|
private resetInactivity;
|
|
18
|
-
constructor(
|
|
17
|
+
constructor(ws: globalThis.WebSocket, sinks: StreamSinks<Defs["streams"]>, graph: Graph);
|
|
19
18
|
private handleMessage;
|
|
20
19
|
private sendMessage;
|
|
21
20
|
run<Key extends keyof Defs["streams"]>(key: Key, args: Defs["streams"][Key]["args"]): Promise<Defs["streams"][Key]["returnType"]>;
|
|
@@ -24,4 +23,4 @@ declare class Client<Defs extends RPCDefinition> {
|
|
|
24
23
|
setPresence(value: Record<string, unknown>): void;
|
|
25
24
|
}
|
|
26
25
|
|
|
27
|
-
export {
|
|
26
|
+
export { WebSocketClient };
|