@powerhousedao/reactor-browser 6.2.0-dev.5 → 6.2.0-dev.50

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 (48) hide show
  1. package/dist/{client-CYhc2W1V.d.ts → client-09xv0Dq6.d.ts} +1 -1
  2. package/dist/{client-CYhc2W1V.d.ts.map → client-09xv0Dq6.d.ts.map} +1 -1
  3. package/dist/{client-CvgFU1Dv.js → client-_Gh2Uf0E.js} +1 -1
  4. package/dist/{client-CvgFU1Dv.js.map → client-_Gh2Uf0E.js.map} +1 -1
  5. package/dist/client-u13cr-Vg.js +51 -0
  6. package/dist/client-u13cr-Vg.js.map +1 -0
  7. package/dist/{document-by-id-BrIy0iHX.js → document-by-id-dLYFX-xz.js} +3 -3
  8. package/dist/{document-by-id-BrIy0iHX.js.map → document-by-id-dLYFX-xz.js.map} +1 -1
  9. package/dist/{index-Bz4MqX_j.d.ts → index-D3bV5rcl.d.ts} +1 -2
  10. package/dist/index-D3bV5rcl.d.ts.map +1 -0
  11. package/dist/{index-ZltD7u5Z.d.ts → index-DS4W07Y8.d.ts} +2 -45
  12. package/dist/index-DS4W07Y8.d.ts.map +1 -0
  13. package/dist/index.d.ts +43 -21
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +137 -131
  16. package/dist/index.js.map +1 -1
  17. package/dist/inspector-proxy-CvQDDxmT.d.ts +255 -0
  18. package/dist/inspector-proxy-CvQDDxmT.d.ts.map +1 -0
  19. package/dist/{make-ph-event-functions-DwiD1zH9.js → make-ph-event-functions-BHoLPif5.js} +2 -2
  20. package/dist/{make-ph-event-functions-DwiD1zH9.js.map → make-ph-event-functions-BHoLPif5.js.map} +1 -1
  21. package/dist/{relational-4_LVwp8p.js → relational-Dj06-YkI.js} +14 -2
  22. package/dist/relational-Dj06-YkI.js.map +1 -0
  23. package/dist/{renown-Dzmo1gJD.js → renown-D-1c_Bvx.js} +35 -48
  24. package/dist/renown-D-1c_Bvx.js.map +1 -0
  25. package/dist/src/analytics/index.d.ts +2 -2
  26. package/dist/src/analytics/index.js +2 -2
  27. package/dist/src/document-model.d.ts +8 -0
  28. package/dist/src/document-model.d.ts.map +1 -0
  29. package/dist/src/document-model.js +14 -0
  30. package/dist/src/document-model.js.map +1 -0
  31. package/dist/src/graphql/client.d.ts +1 -1
  32. package/dist/src/graphql/client.js +1 -1
  33. package/dist/src/relational/index.d.ts +46 -2
  34. package/dist/src/relational/index.d.ts.map +1 -0
  35. package/dist/src/relational/index.js +1 -1
  36. package/dist/src/renown/index.d.ts +1 -1
  37. package/dist/src/renown/index.js +1 -1
  38. package/dist/src/rpc/index.d.ts +240 -0
  39. package/dist/src/rpc/index.d.ts.map +1 -0
  40. package/dist/src/rpc/index.js +1250 -0
  41. package/dist/src/rpc/index.js.map +1 -0
  42. package/dist/{types-BmR60pPN.d.ts → types-CPV0Cnsy.d.ts} +1 -1
  43. package/dist/{types-BmR60pPN.d.ts.map → types-CPV0Cnsy.d.ts.map} +1 -1
  44. package/package.json +37 -11
  45. package/dist/index-Bz4MqX_j.d.ts.map +0 -1
  46. package/dist/index-ZltD7u5Z.d.ts.map +0 -1
  47. package/dist/relational-4_LVwp8p.js.map +0 -1
  48. package/dist/renown-Dzmo1gJD.js.map +0 -1
@@ -0,0 +1,1250 @@
1
+ import { t as RegistryClient } from "../../client-u13cr-Vg.js";
2
+ import { DriveCollectionId, ReactorEventTypes, SyncEventTypes } from "@powerhousedao/reactor";
3
+ //#region src/rpc/listeners.ts
4
+ var KeyedListeners = class {
5
+ map = /* @__PURE__ */ new Map();
6
+ add(key, fn) {
7
+ let set = this.map.get(key);
8
+ if (!set) {
9
+ set = /* @__PURE__ */ new Set();
10
+ this.map.set(key, set);
11
+ }
12
+ set.add(fn);
13
+ return () => {
14
+ const current = this.map.get(key);
15
+ if (!current) return;
16
+ current.delete(fn);
17
+ if (current.size === 0) this.map.delete(key);
18
+ };
19
+ }
20
+ emit(key, ...a) {
21
+ const set = this.map.get(key);
22
+ if (!set) return;
23
+ for (const fn of [...set]) fn(...a);
24
+ }
25
+ emitAll(...a) {
26
+ for (const set of [...this.map.values()]) for (const fn of [...set]) fn(...a);
27
+ }
28
+ };
29
+ var Listeners = class {
30
+ keyed = new KeyedListeners();
31
+ add(fn) {
32
+ return this.keyed.add(null, fn);
33
+ }
34
+ emit(...a) {
35
+ this.keyed.emit(null, ...a);
36
+ }
37
+ };
38
+ //#endregion
39
+ //#region src/rpc/op-channel.ts
40
+ const RPC_DEFAULT_TIMEOUT_MS = 3e4;
41
+ function toVoid(promise) {
42
+ return promise.then(() => void 0);
43
+ }
44
+ function opChannel(router, kind, timeoutMs = RPC_DEFAULT_TIMEOUT_MS) {
45
+ const call = (method, args = []) => router.request((id) => ({
46
+ k: kind,
47
+ id,
48
+ method,
49
+ args
50
+ }), { timeoutMs });
51
+ return {
52
+ call,
53
+ callVoid: (method, args) => toVoid(call(method, args))
54
+ };
55
+ }
56
+ //#endregion
57
+ //#region src/rpc/admin-client.ts
58
+ /** Worker lifecycle channel (info/restart/clearStorage/migrate) over the shared router. */
59
+ function createWorkerAdminClient(router) {
60
+ let migrationState = { status: "idle" };
61
+ const migrationListeners = new Listeners();
62
+ router.on("migration", (msg) => {
63
+ migrationState = msg.state;
64
+ migrationListeners.emit();
65
+ });
66
+ const send = (method) => router.request((id) => ({
67
+ k: "admin",
68
+ id,
69
+ method
70
+ }), { timeoutMs: RPC_DEFAULT_TIMEOUT_MS });
71
+ return {
72
+ info: () => send("info"),
73
+ restart: () => toVoid(send("restart")),
74
+ clearStorage: () => toVoid(send("clearStorage")),
75
+ migrate: () => toVoid(send("migrate")),
76
+ getMigrationState: () => migrationState,
77
+ subscribeMigration: (callback) => migrationListeners.add(callback)
78
+ };
79
+ }
80
+ //#endregion
81
+ //#region src/rpc/error-info.ts
82
+ const MAX_STACK_LENGTH = 8 * 1024;
83
+ const MAX_CAUSE_DEPTH = 8;
84
+ function toErrorInfo(err, depth = 0) {
85
+ if (depth > MAX_CAUSE_DEPTH) return {
86
+ name: "Error",
87
+ message: "cause chain truncated"
88
+ };
89
+ if (err instanceof Error) {
90
+ const info = {
91
+ name: err.name || "Error",
92
+ message: err.message
93
+ };
94
+ if (typeof err.stack === "string") info.stack = err.stack.length > MAX_STACK_LENGTH ? err.stack.slice(0, MAX_STACK_LENGTH) : err.stack;
95
+ if (err.cause !== void 0) info.cause = toErrorInfo(err.cause, depth + 1);
96
+ return info;
97
+ }
98
+ if (typeof err === "string") return {
99
+ name: "Error",
100
+ message: err
101
+ };
102
+ if (err && typeof err === "object") {
103
+ const record = err;
104
+ return {
105
+ name: typeof record.name === "string" ? record.name : "Error",
106
+ message: typeof record.message === "string" ? record.message : safeStringify(err)
107
+ };
108
+ }
109
+ return {
110
+ name: "Error",
111
+ message: safeStringify(err)
112
+ };
113
+ }
114
+ function safeStringify(value) {
115
+ if (value === null || value === void 0) return String(value);
116
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return String(value);
117
+ try {
118
+ return JSON.stringify(value);
119
+ } catch {
120
+ return "[unserializable]";
121
+ }
122
+ }
123
+ function fromErrorInfo(info) {
124
+ const err = new Error(info.message);
125
+ Object.defineProperty(err, "name", {
126
+ value: info.name,
127
+ configurable: true,
128
+ writable: true
129
+ });
130
+ if (info.stack !== void 0) err.stack = info.stack;
131
+ if (info.cause !== void 0) Object.defineProperty(err, "cause", {
132
+ value: fromErrorInfo(info.cause),
133
+ configurable: true,
134
+ writable: true
135
+ });
136
+ return err;
137
+ }
138
+ //#endregion
139
+ //#region src/rpc/paging.ts
140
+ function isPageableResult(value) {
141
+ return value !== null && typeof value === "object" && typeof value.next === "function";
142
+ }
143
+ function hasNextToken(value) {
144
+ return value !== null && typeof value === "object" && typeof value.nextToken === "string";
145
+ }
146
+ function dehydratePage(value, registerCursor) {
147
+ if (!isPageableResult(value)) return value;
148
+ const { next, ...rest } = value;
149
+ return {
150
+ ...rest,
151
+ nextToken: registerCursor(next)
152
+ };
153
+ }
154
+ function rehydratePage(value, fetchPage) {
155
+ if (!hasNextToken(value)) return value;
156
+ const { nextToken, ...rest } = value;
157
+ return {
158
+ ...rest,
159
+ next: () => fetchPage(nextToken)
160
+ };
161
+ }
162
+ //#endregion
163
+ //#region src/rpc/subscription.ts
164
+ var SubscriptionStore = class {
165
+ map = /* @__PURE__ */ new Map();
166
+ set(id, unsubscribe) {
167
+ this.map.set(id, unsubscribe);
168
+ }
169
+ get(id) {
170
+ return this.map.get(id);
171
+ }
172
+ delete(id) {
173
+ this.map.delete(id);
174
+ }
175
+ end(id) {
176
+ const unsubscribe = this.map.get(id);
177
+ if (unsubscribe) {
178
+ this.map.delete(id);
179
+ unsubscribe();
180
+ }
181
+ }
182
+ drain() {
183
+ for (const unsubscribe of this.map.values()) unsubscribe();
184
+ this.map.clear();
185
+ }
186
+ };
187
+ function createCorrelatedSubscriptions(router, config) {
188
+ let counter = 0;
189
+ const subs = /* @__PURE__ */ new Map();
190
+ router.on(config.eventKind, (message) => {
191
+ const sub = subs.get(message.id);
192
+ if (sub) config.onEvent(sub, message);
193
+ });
194
+ router.on(config.errKind, (message) => {
195
+ const id = message.id;
196
+ const sub = subs.get(id);
197
+ if (sub) {
198
+ subs.delete(id);
199
+ router.post(config.close(id));
200
+ config.onError(sub, message);
201
+ }
202
+ });
203
+ return { subscribe(sub, open) {
204
+ const id = `${config.idPrefix}${++counter}`;
205
+ subs.set(id, sub);
206
+ router.post(open(id));
207
+ return () => {
208
+ subs.delete(id);
209
+ router.post(config.close(id));
210
+ };
211
+ } };
212
+ }
213
+ //#endregion
214
+ //#region src/rpc/client-proxy.ts
215
+ function isAbortSignal(value) {
216
+ return typeof value === "object" && value !== null && typeof value.aborted === "boolean" && typeof value.addEventListener === "function" && typeof value.removeEventListener === "function";
217
+ }
218
+ function createReactorClientProxy(router, options = {}) {
219
+ const registry = options.registry;
220
+ function fetchPage(token) {
221
+ return router.request((id) => ({
222
+ k: "page",
223
+ id,
224
+ token
225
+ }), { transform: rehydrate });
226
+ }
227
+ function rehydrate(value) {
228
+ return rehydratePage(value, fetchPage);
229
+ }
230
+ const changeSubs = createCorrelatedSubscriptions(router, {
231
+ idPrefix: "sub",
232
+ eventKind: "event",
233
+ errKind: "sub-err",
234
+ onEvent: (callback, msg) => callback(msg.change),
235
+ onError: (_callback, msg) => console.error("Reactor subscription failed:", fromErrorInfo(msg.error)),
236
+ close: (id) => ({
237
+ k: "unsub",
238
+ id
239
+ })
240
+ });
241
+ router.on("reload", (msg) => {
242
+ options.onReload?.(msg.reason, msg.workerGen);
243
+ });
244
+ const call = (method, args) => {
245
+ let abortAt;
246
+ for (let i = 0; i < args.length; i++) if (isAbortSignal(args[i])) abortAt = i;
247
+ let wire = args;
248
+ if (abortAt !== void 0) {
249
+ wire = args.slice();
250
+ wire[abortAt] = void 0;
251
+ }
252
+ return router.request((id) => ({
253
+ k: "req",
254
+ id,
255
+ method,
256
+ args: wire,
257
+ abortAt
258
+ }), {
259
+ transform: rehydrate,
260
+ setup: (id) => {
261
+ if (abortAt === void 0) return;
262
+ const signal = args[abortAt];
263
+ const sendAbort = () => router.post({
264
+ k: "abort",
265
+ targetId: id
266
+ });
267
+ if (signal.aborted) {
268
+ sendAbort();
269
+ return;
270
+ }
271
+ signal.addEventListener("abort", sendAbort, { once: true });
272
+ return () => signal.removeEventListener("abort", sendAbort);
273
+ }
274
+ });
275
+ };
276
+ const subscribe = (search, callback, view) => changeSubs.subscribe(callback, (id) => ({
277
+ k: "sub",
278
+ id,
279
+ search,
280
+ view
281
+ }));
282
+ const forwarders = /* @__PURE__ */ new Map();
283
+ const forwarder = (method) => {
284
+ let fn = forwarders.get(method);
285
+ if (!fn) {
286
+ fn = (...args) => call(method, args);
287
+ forwarders.set(method, fn);
288
+ }
289
+ return fn;
290
+ };
291
+ const drives = new Proxy({}, { get: (_target, prop) => typeof prop === "string" ? forwarder(`drives.${prop}`) : void 0 });
292
+ return new Proxy({}, { get(_target, prop) {
293
+ if (typeof prop !== "string" || prop === "then") return;
294
+ if (prop === "drives") return drives;
295
+ if (prop === "subscribe") return subscribe;
296
+ if (registry) {
297
+ if (prop === "getDocumentModelModule") return (documentType) => Promise.resolve().then(() => registry.getModule(documentType));
298
+ if (prop === "getDocumentModelModules") return (_namespace, paging) => Promise.resolve({
299
+ results: registry.getAllModules(),
300
+ options: paging ?? {
301
+ cursor: "",
302
+ limit: Number.MAX_SAFE_INTEGER
303
+ }
304
+ });
305
+ }
306
+ return forwarder(prop);
307
+ } });
308
+ }
309
+ //#endregion
310
+ //#region src/rpc/inspector-proxy.ts
311
+ function createInspectorProxy(router) {
312
+ const ops = opChannel(router, "inspector-op");
313
+ return {
314
+ getQueueState: () => ops.call("queue.getState"),
315
+ pauseQueue: () => ops.callVoid("queue.pause"),
316
+ resumeQueue: () => ops.callVoid("queue.resume"),
317
+ getProcessors: () => ops.call("processors.getAll"),
318
+ retryProcessor: (processorId) => ops.callVoid("processors.retry", [processorId]),
319
+ validateDocument: (documentId, branch) => ops.call("integrity.validate", [documentId, branch]),
320
+ rebuildKeyframes: (documentId, branch) => ops.call("integrity.rebuildKeyframes", [documentId, branch]),
321
+ rebuildSnapshots: (documentId, branch) => ops.call("integrity.rebuildSnapshots", [documentId, branch]),
322
+ queryReactorDb: (sql, params) => ops.call("db.query", [sql, params ?? []])
323
+ };
324
+ }
325
+ //#endregion
326
+ //#region src/rpc/protocol.ts
327
+ const RPC_PROTOCOL_VERSION = 2;
328
+ /** Error reply kind for a client message kind, so it reaches the right registry. */
329
+ function responseErrorKind(k) {
330
+ if (k === "sub") return "sub-err";
331
+ if (k === "sub-live") return "live-err";
332
+ return "err";
333
+ }
334
+ //#endregion
335
+ //#region src/rpc/host-reply.ts
336
+ const defaultOk = () => ({ ok: true });
337
+ function hostResponder(transport) {
338
+ const ok = (id, value = { ok: true }) => {
339
+ transport.post({
340
+ k: "res",
341
+ id,
342
+ value
343
+ });
344
+ };
345
+ const err = (id, error) => {
346
+ transport.post({
347
+ k: "err",
348
+ id,
349
+ error: toErrorInfo(error)
350
+ });
351
+ };
352
+ return {
353
+ ok,
354
+ err,
355
+ errForKind(message, error) {
356
+ if (!("id" in message)) return;
357
+ transport.post({
358
+ k: responseErrorKind(message.k),
359
+ id: message.id,
360
+ error: toErrorInfo(error)
361
+ });
362
+ },
363
+ async run(id, body, mapOk = defaultOk) {
364
+ try {
365
+ ok(id, mapOk(await body()));
366
+ } catch (error) {
367
+ err(id, error);
368
+ }
369
+ }
370
+ };
371
+ }
372
+ //#endregion
373
+ //#region src/rpc/live-query-proxy.ts
374
+ function createLiveQueryProxy(router) {
375
+ const subs = createCorrelatedSubscriptions(router, {
376
+ idPrefix: "live",
377
+ eventKind: "event-live",
378
+ errKind: "live-err",
379
+ onEvent: (sub, msg) => sub.onResults(msg.results),
380
+ onError: (sub, msg) => sub.onError?.(fromErrorInfo(msg.error)),
381
+ close: (id) => ({
382
+ k: "unsub-live",
383
+ id
384
+ })
385
+ });
386
+ return { query(sql, params, onResults, onError) {
387
+ return subs.subscribe({
388
+ onResults,
389
+ onError
390
+ }, (id) => ({
391
+ k: "sub-live",
392
+ id,
393
+ sql,
394
+ params
395
+ }));
396
+ } };
397
+ }
398
+ //#endregion
399
+ //#region src/rpc/relational-db-proxy.ts
400
+ function createRelationalPgliteProxy(router) {
401
+ const ops = opChannel(router, "db-op");
402
+ const liveProxy = createLiveQueryProxy(router);
403
+ return {
404
+ query: async (sql, params) => {
405
+ return { rows: await ops.call("query", [sql, params ?? []]) };
406
+ },
407
+ live: { query: (sql, params, callback) => new Promise((resolve, reject) => {
408
+ let settled = false;
409
+ const unsubscribe = liveProxy.query(sql, params ?? [], (results) => {
410
+ if (!settled) {
411
+ settled = true;
412
+ resolve({ unsubscribe });
413
+ }
414
+ callback?.(results);
415
+ }, (error) => {
416
+ if (!settled) {
417
+ settled = true;
418
+ reject(error instanceof Error ? error : new Error(String(error)));
419
+ }
420
+ });
421
+ }) }
422
+ };
423
+ }
424
+ //#endregion
425
+ //#region src/rpc/sync-manager-proxy.ts
426
+ const SYNC_STATUS_CHANGED_EVENT = 90001;
427
+ const SEED_MAX_ATTEMPTS = 3;
428
+ const SEED_RETRY_DELAY_MS = 500;
429
+ const DEFAULT_SNAPSHOT = {
430
+ state: "connecting",
431
+ failureCount: 0,
432
+ lastSuccessUtcMs: 0,
433
+ lastFailureUtcMs: 0,
434
+ pushBlocked: false,
435
+ pushFailureCount: 0,
436
+ receivingPages: false,
437
+ requiresAuth: false
438
+ };
439
+ var NoopMailbox = class {
440
+ get items() {
441
+ return [];
442
+ }
443
+ get ackOrdinal() {
444
+ return 0;
445
+ }
446
+ get latestOrdinal() {
447
+ return 0;
448
+ }
449
+ init() {}
450
+ advanceOrdinal() {}
451
+ get() {}
452
+ add() {}
453
+ remove() {}
454
+ onAdded() {}
455
+ onRemoved() {}
456
+ pause() {}
457
+ resume() {}
458
+ flush() {}
459
+ isPaused() {
460
+ return false;
461
+ }
462
+ };
463
+ const NOOP_MAILBOX = new NoopMailbox();
464
+ function rehydrateMeta(wire) {
465
+ return {
466
+ id: wire.id,
467
+ name: wire.name,
468
+ collectionId: DriveCollectionId.forDrive(wire.collectionId.driveId, wire.collectionId.branch),
469
+ channelConfig: wire.channelConfig,
470
+ filter: wire.filter,
471
+ options: wire.options
472
+ };
473
+ }
474
+ function channelUrl(meta) {
475
+ const url = meta.channelConfig.parameters.url;
476
+ return typeof url === "string" ? url : void 0;
477
+ }
478
+ var SyncManagerProxy = class {
479
+ ops;
480
+ connectionStates = /* @__PURE__ */ new Map();
481
+ connectionListeners = new KeyedListeners();
482
+ syncStatuses = /* @__PURE__ */ new Map();
483
+ syncStatusListeners = new Listeners();
484
+ remotes = [];
485
+ seedPromise = null;
486
+ constructor(router, busProxy) {
487
+ this.ops = opChannel(router, "sync-op");
488
+ busProxy.subscribe(SyncEventTypes.CONNECTION_STATE_CHANGED, (_type, event) => {
489
+ const e = event;
490
+ this.connectionStates.set(e.remoteName, e.snapshot);
491
+ this.notifyConnection(e.remoteName);
492
+ });
493
+ busProxy.subscribe(SYNC_STATUS_CHANGED_EVENT, (_type, event) => {
494
+ const e = event;
495
+ this.syncStatuses.set(e.documentId, e.status);
496
+ this.syncStatusListeners.emit(e.documentId, e.status);
497
+ });
498
+ this.ensureSeeded();
499
+ }
500
+ async startup() {
501
+ let lastError;
502
+ for (let attempt = 0; attempt < SEED_MAX_ATTEMPTS; attempt++) try {
503
+ await this.ensureSeeded();
504
+ return;
505
+ } catch (error) {
506
+ lastError = error;
507
+ if (attempt < SEED_MAX_ATTEMPTS - 1) await new Promise((resolve) => setTimeout(resolve, SEED_RETRY_DELAY_MS));
508
+ }
509
+ throw lastError;
510
+ }
511
+ shutdown() {
512
+ return {
513
+ isShutdown: true,
514
+ completed: Promise.resolve()
515
+ };
516
+ }
517
+ getByName(name) {
518
+ const remote = this.remotes.find((r) => r.meta.name === name);
519
+ if (!remote) throw new Error(`Unknown remote: ${name}`);
520
+ return remote;
521
+ }
522
+ getById(id) {
523
+ const remote = this.remotes.find((r) => r.meta.id === id);
524
+ if (!remote) throw new Error(`Unknown remote id: ${id}`);
525
+ return remote;
526
+ }
527
+ async add(name, collectionId, channelConfig, filter, options) {
528
+ await this.callSyncOp("add", [
529
+ name,
530
+ collectionId.key,
531
+ channelConfig,
532
+ filter,
533
+ options
534
+ ]);
535
+ await this.refreshRemotes();
536
+ return this.getByName(name);
537
+ }
538
+ triggerPull(name) {
539
+ this.callSyncOp("triggerPull", [name]).catch((error) => {
540
+ console.error(`triggerPull failed for remote "${name}":`, error);
541
+ });
542
+ }
543
+ async remove(name) {
544
+ await this.callSyncOp("remove", [name]);
545
+ await this.refreshRemotes();
546
+ }
547
+ list() {
548
+ return [...this.remotes];
549
+ }
550
+ waitForSync() {
551
+ return Promise.reject(/* @__PURE__ */ new Error("waitForSync is not supported over the worker RPC boundary"));
552
+ }
553
+ getSyncStatus(documentId) {
554
+ return this.syncStatuses.get(documentId);
555
+ }
556
+ onSyncStatusChange(callback) {
557
+ return this.syncStatusListeners.add(callback);
558
+ }
559
+ callSyncOp(method, args) {
560
+ return this.ops.call(method, args);
561
+ }
562
+ notifyConnection(remoteName) {
563
+ if (remoteName !== void 0) {
564
+ this.connectionListeners.emit(remoteName);
565
+ return;
566
+ }
567
+ this.connectionListeners.emitAll();
568
+ }
569
+ makeChannel(remoteName, url) {
570
+ return {
571
+ inbox: NOOP_MAILBOX,
572
+ outbox: NOOP_MAILBOX,
573
+ deadLetter: NOOP_MAILBOX,
574
+ init: () => Promise.resolve(),
575
+ shutdown: () => Promise.resolve(),
576
+ getConnectionState: () => this.connectionStates.get(remoteName) ?? DEFAULT_SNAPSHOT,
577
+ onConnectionStateChange: (callback) => {
578
+ const listener = () => callback(this.connectionStates.get(remoteName) ?? DEFAULT_SNAPSHOT);
579
+ return this.connectionListeners.add(remoteName, listener);
580
+ },
581
+ triggerPull: () => {
582
+ this.callSyncOp("triggerPull", [remoteName]).catch((error) => {
583
+ console.error(`triggerPull failed for remote "${remoteName}":`, error);
584
+ });
585
+ },
586
+ config: { url }
587
+ };
588
+ }
589
+ async refreshRemotes() {
590
+ const wire = await this.callSyncOp("list", []);
591
+ const names = /* @__PURE__ */ new Set();
592
+ this.remotes = wire.map((w) => {
593
+ const meta = rehydrateMeta(w.meta);
594
+ names.add(meta.name);
595
+ if (!this.connectionStates.has(meta.name)) this.connectionStates.set(meta.name, w.connectionState);
596
+ return {
597
+ meta,
598
+ channel: this.makeChannel(meta.name, channelUrl(meta))
599
+ };
600
+ });
601
+ for (const name of [...this.connectionStates.keys()]) if (!names.has(name)) this.connectionStates.delete(name);
602
+ this.notifyConnection();
603
+ }
604
+ ensureSeeded() {
605
+ if (!this.seedPromise) {
606
+ const pending = this.refreshRemotes();
607
+ this.seedPromise = pending;
608
+ pending.catch(() => {
609
+ if (this.seedPromise === pending) this.seedPromise = null;
610
+ });
611
+ }
612
+ return this.seedPromise;
613
+ }
614
+ };
615
+ function createSyncManagerProxy(router, busProxy) {
616
+ return new SyncManagerProxy(router, busProxy);
617
+ }
618
+ //#endregion
619
+ //#region src/rpc/forwarded-events.ts
620
+ const FORWARDED_EVENT_TYPES = [
621
+ SyncEventTypes.SYNC_PENDING,
622
+ SyncEventTypes.SYNC_SUCCEEDED,
623
+ SyncEventTypes.SYNC_FAILED,
624
+ SyncEventTypes.DEAD_LETTER_ADDED,
625
+ SyncEventTypes.CONNECTION_STATE_CHANGED,
626
+ ReactorEventTypes.MODEL_LOADED
627
+ ];
628
+ const FORWARDED_BUS_EVENT_TYPES = [...FORWARDED_EVENT_TYPES, SYNC_STATUS_CHANGED_EVENT];
629
+ //#endregion
630
+ //#region src/rpc/event-bus-proxy.ts
631
+ /** Tab-side IEventBus over bus-event; emit() is unsupported (the worker emits). */
632
+ var ReactorEventBusProxy = class {
633
+ forwardedTypes = new Set(FORWARDED_BUS_EVENT_TYPES);
634
+ subscribers = new KeyedListeners();
635
+ constructor(router) {
636
+ router.on("bus-event", (msg) => {
637
+ this.subscribers.emit(msg.eventType, msg.eventType, msg.event);
638
+ });
639
+ }
640
+ subscribe(type, subscriber) {
641
+ if (!this.forwardedTypes.has(type)) throw new Error(`ReactorEventBusProxy cannot subscribe to event type ${type}: the worker forwards only [${[...this.forwardedTypes].join(", ")}]`);
642
+ const entry = subscriber;
643
+ return this.subscribers.add(type, entry);
644
+ }
645
+ emit() {
646
+ return Promise.reject(/* @__PURE__ */ new Error("EventBus.emit is not supported tab-side; the reactor graph emits in the worker"));
647
+ }
648
+ };
649
+ function createReactorEventBusProxy(router) {
650
+ return new ReactorEventBusProxy(router);
651
+ }
652
+ //#endregion
653
+ //#region src/rpc/connect-reactor.ts
654
+ function connectReactorClient(router, hello, onReload, registry) {
655
+ const client = createReactorClientProxy(router, {
656
+ onReload,
657
+ registry
658
+ });
659
+ router.post({
660
+ k: "hello",
661
+ id: "hello",
662
+ version: hello.version,
663
+ construct: hello.construct,
664
+ packages: hello.packages
665
+ });
666
+ return client;
667
+ }
668
+ function postReactorIdentity(router, user) {
669
+ router.post({
670
+ k: "identity",
671
+ user
672
+ });
673
+ }
674
+ //#endregion
675
+ //#region src/rpc/host-server.ts
676
+ const MAX_PENDING_PAGES = 1e3;
677
+ var ReactorHostServer = class {
678
+ client;
679
+ transport;
680
+ reply;
681
+ aborters = /* @__PURE__ */ new Map();
682
+ subscriptions = new SubscriptionStore();
683
+ pages = /* @__PURE__ */ new Map();
684
+ pageCounter = 0;
685
+ detach = () => {};
686
+ constructor(client, transport) {
687
+ this.client = client;
688
+ this.transport = transport;
689
+ this.reply = hostResponder(transport);
690
+ }
691
+ start() {
692
+ this.detach = this.transport.onMessage((message) => {
693
+ this.handleMessage(message);
694
+ });
695
+ }
696
+ stop() {
697
+ this.detach();
698
+ this.subscriptions.drain();
699
+ this.aborters.clear();
700
+ this.pages.clear();
701
+ }
702
+ async handleMessage(message) {
703
+ try {
704
+ switch (message.k) {
705
+ case "req":
706
+ await this.handleRequest(message);
707
+ return;
708
+ case "page":
709
+ await this.handlePage(message);
710
+ return;
711
+ case "abort":
712
+ this.aborters.get(message.targetId)?.abort();
713
+ return;
714
+ case "sub":
715
+ this.handleSubscribe(message);
716
+ return;
717
+ case "unsub":
718
+ this.subscriptions.end(message.id);
719
+ return;
720
+ }
721
+ } catch (error) {
722
+ this.reply.errForKind(message, error);
723
+ }
724
+ }
725
+ async handleRequest(message) {
726
+ let args = message.args;
727
+ let controller;
728
+ if (message.abortAt !== void 0) {
729
+ controller = new AbortController();
730
+ this.aborters.set(message.id, controller);
731
+ args = message.args.slice();
732
+ args[message.abortAt] = controller.signal;
733
+ }
734
+ try {
735
+ const value = await this.resolveMethod(message.method)(...args);
736
+ this.reply.ok(message.id, this.prepareResult(value));
737
+ } catch (error) {
738
+ this.reply.err(message.id, error);
739
+ } finally {
740
+ if (controller) this.aborters.delete(message.id);
741
+ }
742
+ }
743
+ async handlePage(message) {
744
+ const next = this.pages.get(message.token);
745
+ this.pages.delete(message.token);
746
+ if (!next) {
747
+ this.reply.err(message.id, /* @__PURE__ */ new Error("Paged cursor already consumed or expired"));
748
+ return;
749
+ }
750
+ try {
751
+ const value = await next();
752
+ this.reply.ok(message.id, this.prepareResult(value));
753
+ } catch (error) {
754
+ this.reply.err(message.id, error);
755
+ }
756
+ }
757
+ handleSubscribe(message) {
758
+ const unsubscribe = this.client.subscribe(message.search, (change) => this.transport.post({
759
+ k: "event",
760
+ id: message.id,
761
+ change
762
+ }), message.view);
763
+ this.subscriptions.set(message.id, unsubscribe);
764
+ }
765
+ prepareResult(value) {
766
+ return dehydratePage(value, (next) => {
767
+ const token = `p${++this.pageCounter}`;
768
+ this.pages.set(token, next);
769
+ if (this.pages.size > MAX_PENDING_PAGES) {
770
+ const oldest = this.pages.keys().next().value;
771
+ if (oldest !== void 0) this.pages.delete(oldest);
772
+ }
773
+ return token;
774
+ });
775
+ }
776
+ resolveMethod(path) {
777
+ if (path.startsWith("drives.")) {
778
+ const name = path.slice(7);
779
+ const fn = this.client.drives[name];
780
+ if (typeof fn !== "function") throw new Error(`Unknown drive method: ${name}`);
781
+ return fn.bind(this.client.drives);
782
+ }
783
+ const fn = this.client[path];
784
+ if (typeof fn !== "function") throw new Error(`Unknown reactor method: ${path}`);
785
+ return fn.bind(this.client);
786
+ }
787
+ };
788
+ //#endregion
789
+ //#region src/rpc/transport.ts
790
+ function createPortTransport(port) {
791
+ port.start();
792
+ port.addEventListener("messageerror", (event) => {
793
+ console.error("[rpc transport] failed to deserialize message", event);
794
+ });
795
+ return {
796
+ post(message) {
797
+ port.postMessage(message);
798
+ },
799
+ onMessage(listener) {
800
+ const handler = (event) => {
801
+ listener(event.data);
802
+ };
803
+ port.addEventListener("message", handler);
804
+ return () => port.removeEventListener("message", handler);
805
+ },
806
+ close() {
807
+ port.close();
808
+ }
809
+ };
810
+ }
811
+ //#endregion
812
+ //#region src/rpc/reactor-host.ts
813
+ function isDataMessage(msg) {
814
+ return msg.k === "req" || msg.k === "sub" || msg.k === "page" || msg.k === "sync-op" || msg.k === "db-op" || msg.k === "inspector-op" || msg.k === "sub-live";
815
+ }
816
+ function versionsCompatible(a, b) {
817
+ return a.appBuildId === b.appBuildId && a.rpcProtocolVersion === b.rpcProtocolVersion;
818
+ }
819
+ function workerGenForVersion(version) {
820
+ return `v${version.rpcProtocolVersion}-${version.appBuildId}`;
821
+ }
822
+ var ReactorHost = class {
823
+ options;
824
+ disposers = /* @__PURE__ */ new Set();
825
+ clients = /* @__PURE__ */ new Set();
826
+ clientPromise = null;
827
+ baseline = null;
828
+ ownerId;
829
+ bootedAtMs;
830
+ migrationState = null;
831
+ constructor(options) {
832
+ this.options = options;
833
+ this.ownerId = options.ownerId ?? crypto.randomUUID();
834
+ this.bootedAtMs = options.bootedAtMs ?? Date.now();
835
+ if (options.client) this.clientPromise = Promise.resolve(options.client);
836
+ }
837
+ connect(transport) {
838
+ let server = null;
839
+ let ready = false;
840
+ const buffer = [];
841
+ const liveSubs = new SubscriptionStore();
842
+ const reply = hostResponder(transport);
843
+ const ensureServer = async (construct) => {
844
+ if (server) return;
845
+ server = new ReactorHostServer(await this.resolveClient(construct), transport);
846
+ };
847
+ const drainBuffer = async () => {
848
+ while (buffer.length > 0) {
849
+ const message = buffer.shift();
850
+ await server.handleMessage(message);
851
+ }
852
+ ready = true;
853
+ };
854
+ const detach = transport.onMessage((message) => {
855
+ const msg = message;
856
+ if (msg.k === "ping") {
857
+ transport.post({
858
+ k: "pong",
859
+ id: msg.id,
860
+ ownerId: this.ownerId,
861
+ bootedAtMs: this.bootedAtMs
862
+ });
863
+ return;
864
+ }
865
+ if (this.migrationState?.status === "migrating" && isDataMessage(msg)) {
866
+ reply.errForKind(msg, /* @__PURE__ */ new Error("migration in progress"));
867
+ return;
868
+ }
869
+ if (msg.k === "hello") {
870
+ this.handleHello(msg, transport, reply, ensureServer, drainBuffer);
871
+ return;
872
+ }
873
+ if (msg.k === "register-packages") {
874
+ this.handleRegister(msg, reply);
875
+ return;
876
+ }
877
+ if (msg.k === "unregister-packages") {
878
+ this.handleUnregister(msg, reply);
879
+ return;
880
+ }
881
+ if (msg.k === "identity") {
882
+ this.options.onIdentity?.(msg.user);
883
+ return;
884
+ }
885
+ if (msg.k === "sync-op") {
886
+ this.handleOp(msg, this.options.onSyncOp, "sync", reply);
887
+ return;
888
+ }
889
+ if (msg.k === "db-op") {
890
+ this.handleOp(msg, this.options.onDbOp, "db", reply);
891
+ return;
892
+ }
893
+ if (msg.k === "inspector-op") {
894
+ this.handleOp(msg, this.options.onInspectorOp, "inspector", reply);
895
+ return;
896
+ }
897
+ if (msg.k === "sub-live") {
898
+ this.handleLiveSubscribe(msg, transport, reply, liveSubs);
899
+ return;
900
+ }
901
+ if (msg.k === "unsub-live") {
902
+ liveSubs.end(msg.id);
903
+ return;
904
+ }
905
+ if (msg.k === "admin") {
906
+ this.handleAdmin(msg, reply);
907
+ return;
908
+ }
909
+ if (ready && server) server.handleMessage(msg);
910
+ else buffer.push(msg);
911
+ });
912
+ this.clients.add(transport);
913
+ if (this.migrationState) transport.post({
914
+ k: "migration",
915
+ state: this.migrationState
916
+ });
917
+ if (this.options.client) ensureServer().then(drainBuffer).catch((error) => {
918
+ console.error("ReactorHost buffer drain failed", error);
919
+ });
920
+ const dispose = () => {
921
+ server?.stop();
922
+ detach();
923
+ liveSubs.drain();
924
+ this.clients.delete(transport);
925
+ this.disposers.delete(dispose);
926
+ };
927
+ this.disposers.add(dispose);
928
+ return dispose;
929
+ }
930
+ connectPort(port) {
931
+ return this.connect(createPortTransport(port));
932
+ }
933
+ broadcastBusEvent(eventType, event) {
934
+ for (const transport of this.clients) transport.post({
935
+ k: "bus-event",
936
+ eventType,
937
+ event
938
+ });
939
+ }
940
+ broadcastReload(reason, workerGen) {
941
+ for (const transport of this.clients) transport.post({
942
+ k: "reload",
943
+ reason,
944
+ workerGen
945
+ });
946
+ }
947
+ setMigrationState(state) {
948
+ this.migrationState = state;
949
+ for (const transport of this.clients) transport.post({
950
+ k: "migration",
951
+ state
952
+ });
953
+ }
954
+ get connectionCount() {
955
+ return this.disposers.size;
956
+ }
957
+ handleAdmin(message, reply) {
958
+ if (message.method === "restart") {
959
+ this.options.onAdminRestart?.();
960
+ reply.ok(message.id);
961
+ return;
962
+ }
963
+ if (message.method === "clearStorage") {
964
+ this.handleAdminAsync(this.options.onAdminClearStorage, message, reply);
965
+ return;
966
+ }
967
+ if (message.method === "migrate") {
968
+ this.handleAdminAsync(this.options.onAdminMigrate, message, reply);
969
+ return;
970
+ }
971
+ const info = {
972
+ namespace: this.options.namespace ?? "",
973
+ ownerId: this.ownerId,
974
+ bootedAtMs: this.bootedAtMs,
975
+ connectedClients: this.connectionCount,
976
+ appBuildId: this.baseline?.appBuildId ?? this.options.appBuildId ?? "unknown",
977
+ rpcProtocolVersion: this.baseline?.rpcProtocolVersion ?? 2
978
+ };
979
+ reply.ok(message.id, info);
980
+ }
981
+ async handleAdminAsync(handler, message, reply) {
982
+ await reply.run(message.id, async () => {
983
+ await handler?.();
984
+ });
985
+ }
986
+ resolveClient(construct) {
987
+ if (!this.clientPromise) {
988
+ const build = this.options.build;
989
+ if (!build) return Promise.reject(/* @__PURE__ */ new Error("ReactorHost has no client or builder"));
990
+ const pending = build(construct);
991
+ this.clientPromise = pending;
992
+ pending.catch(() => {
993
+ if (this.clientPromise === pending) this.clientPromise = null;
994
+ });
995
+ }
996
+ return this.clientPromise;
997
+ }
998
+ async awaitClientReady() {
999
+ if (this.clientPromise) await this.clientPromise;
1000
+ }
1001
+ requireHandler(handler, message, reply, label) {
1002
+ if (handler) return true;
1003
+ reply.errForKind(message, /* @__PURE__ */ new Error(`ReactorHost has no ${label} handler`));
1004
+ return false;
1005
+ }
1006
+ async handleHello(message, transport, reply, ensureServer, drainBuffer) {
1007
+ if (this.baseline) {
1008
+ if (!versionsCompatible(this.baseline, message.version)) {
1009
+ transport.post({
1010
+ k: "reload",
1011
+ reason: "reactor version mismatch",
1012
+ workerGen: workerGenForVersion(message.version)
1013
+ });
1014
+ reply.ok(message.id, { ok: false });
1015
+ return;
1016
+ }
1017
+ } else this.baseline = message.version;
1018
+ await reply.run(message.id, async () => {
1019
+ await ensureServer(message.construct);
1020
+ if (message.packages && message.packages.length > 0) await this.options.registerPackages?.(message.packages);
1021
+ await drainBuffer();
1022
+ });
1023
+ }
1024
+ async handleRegister(message, reply) {
1025
+ await reply.run(message.id, async () => {
1026
+ await this.options.registerPackages?.(message.specs);
1027
+ });
1028
+ }
1029
+ async handleUnregister(message, reply) {
1030
+ await reply.run(message.id, async () => {
1031
+ await this.options.unregisterPackages?.(message.names);
1032
+ });
1033
+ }
1034
+ async handleOp(message, handler, label, reply) {
1035
+ if (!this.requireHandler(handler, message, reply, label)) return;
1036
+ await reply.run(message.id, async () => {
1037
+ await this.awaitClientReady();
1038
+ return handler(message.method, message.args);
1039
+ }, (value) => value);
1040
+ }
1041
+ async handleLiveSubscribe(message, transport, reply, liveSubs) {
1042
+ const handler = this.options.onLiveQuery;
1043
+ if (!this.requireHandler(handler, message, reply, "live-query")) return;
1044
+ const placeholder = () => void 0;
1045
+ liveSubs.set(message.id, placeholder);
1046
+ try {
1047
+ await this.awaitClientReady();
1048
+ const unsubscribe = await handler(message.sql, message.params, (results) => {
1049
+ transport.post({
1050
+ k: "event-live",
1051
+ id: message.id,
1052
+ results
1053
+ });
1054
+ });
1055
+ if (liveSubs.get(message.id) !== placeholder) {
1056
+ unsubscribe();
1057
+ return;
1058
+ }
1059
+ liveSubs.set(message.id, unsubscribe);
1060
+ } catch (error) {
1061
+ if (liveSubs.get(message.id) === placeholder) liveSubs.delete(message.id);
1062
+ reply.errForKind(message, error);
1063
+ }
1064
+ }
1065
+ };
1066
+ //#endregion
1067
+ //#region src/rpc/worker-package-loader.ts
1068
+ function packageName(spec) {
1069
+ const at = spec.lastIndexOf("@");
1070
+ return at > 0 ? spec.slice(0, at) : spec;
1071
+ }
1072
+ function isDocumentModelModule(value) {
1073
+ if (typeof value !== "object" || value === null) return false;
1074
+ const candidate = value;
1075
+ return typeof candidate.reducer === "function" && typeof candidate.documentModel?.global?.id === "string";
1076
+ }
1077
+ var WorkerPackageLoader = class {
1078
+ cdnUrl;
1079
+ importPackage;
1080
+ resolvePackages;
1081
+ modulesByType = /* @__PURE__ */ new Map();
1082
+ loadedSpecs = /* @__PURE__ */ new Set();
1083
+ failures = [];
1084
+ constructor(options) {
1085
+ this.cdnUrl = options.cdnUrl.replace(/\/$/, "");
1086
+ this.importPackage = options.importPackage;
1087
+ const registryClient = new RegistryClient(options.cdnUrl);
1088
+ this.resolvePackages = options.resolvePackages ?? ((documentType) => registryClient.getPackagesByDocumentType(documentType));
1089
+ }
1090
+ async loadPackages(specs) {
1091
+ await Promise.all([...new Set(specs)].map((spec) => this.loadPackage(spec)));
1092
+ return this.models;
1093
+ }
1094
+ async load(documentType) {
1095
+ const existing = this.modulesByType.get(documentType);
1096
+ if (existing) return existing;
1097
+ const packageNames = await this.resolvePackages(documentType);
1098
+ const failuresBefore = this.failures.length;
1099
+ await Promise.all([...new Set(packageNames)].map((name) => this.loadPackage(name)));
1100
+ const loaded = this.modulesByType.get(documentType);
1101
+ if (loaded) return loaded;
1102
+ throw this.notLoadedError(documentType, packageNames, this.failures.slice(failuresBefore));
1103
+ }
1104
+ get models() {
1105
+ return [...new Set(this.modulesByType.values())];
1106
+ }
1107
+ get loadFailures() {
1108
+ return [...this.failures];
1109
+ }
1110
+ notLoadedError(documentType, packageNames, failures) {
1111
+ if (packageNames.length === 0) return /* @__PURE__ */ new Error(`No package found for document model: ${documentType}`);
1112
+ if (failures.length === 0) return /* @__PURE__ */ new Error(`Imported [${packageNames.join(", ")}] but document model not found: ${documentType}`);
1113
+ const cause = failures.length === 1 ? failures[0].error : new AggregateError(failures.map((failure) => failure.error));
1114
+ return new Error(`Failed to import package(s) [${packageNames.join(", ")}] for document model: ${documentType}`, { cause });
1115
+ }
1116
+ async loadPackage(spec) {
1117
+ if (this.loadedSpecs.has(spec)) return;
1118
+ const name = packageName(spec);
1119
+ const url = `${this.cdnUrl}/${name}/browser/document-models/index.js`;
1120
+ try {
1121
+ const namespace = await this.importPackage(url);
1122
+ for (const value of Object.values(namespace)) if (isDocumentModelModule(value)) this.modulesByType.set(value.documentModel.global.id, value);
1123
+ this.loadedSpecs.add(spec);
1124
+ } catch (error) {
1125
+ this.failures.push({
1126
+ name,
1127
+ url,
1128
+ error
1129
+ });
1130
+ }
1131
+ }
1132
+ };
1133
+ //#endregion
1134
+ //#region src/rpc/rpc-correlator.ts
1135
+ /**
1136
+ * Request/response correlation shared by every RPC proxy: one pending map,
1137
+ * res/err settlement, and per-request timeout/transform/cleanup.
1138
+ */
1139
+ var RpcCorrelator = class {
1140
+ counter = 0;
1141
+ pending = /* @__PURE__ */ new Map();
1142
+ constructor(poster, prefix = "r") {
1143
+ this.poster = poster;
1144
+ this.prefix = prefix;
1145
+ }
1146
+ nextId() {
1147
+ return `${this.prefix}${++this.counter}`;
1148
+ }
1149
+ /** Settle the pending request a res/err refers to; a missing id is a no-op. */
1150
+ handleMessage(message) {
1151
+ if (message.k !== "res" && message.k !== "err") return;
1152
+ const entry = this.pending.get(message.id);
1153
+ if (!entry) return;
1154
+ this.pending.delete(message.id);
1155
+ if (entry.timer) clearTimeout(entry.timer);
1156
+ entry.cleanup?.();
1157
+ if (message.k === "res") entry.resolve(entry.transform ? entry.transform(message.value) : message.value);
1158
+ else entry.reject(fromErrorInfo(message.error));
1159
+ }
1160
+ /** Send a request, resolving on its res/err. `build` stamps the generated id. */
1161
+ request(build, options = {}) {
1162
+ const id = this.nextId();
1163
+ const message = build(id);
1164
+ const method = message.method;
1165
+ const label = typeof method === "string" ? `${message.k} "${method}"` : message.k;
1166
+ const promise = new Promise((resolve, reject) => {
1167
+ let timer;
1168
+ if (options.timeoutMs !== void 0) {
1169
+ const timeoutMs = options.timeoutMs;
1170
+ timer = setTimeout(() => {
1171
+ const entry = this.pending.get(id);
1172
+ if (entry) {
1173
+ this.pending.delete(id);
1174
+ entry.cleanup?.();
1175
+ reject(/* @__PURE__ */ new Error(`Reactor worker did not respond to ${label} within ${timeoutMs}ms; the worker may have failed to load`));
1176
+ }
1177
+ }, timeoutMs);
1178
+ }
1179
+ this.pending.set(id, {
1180
+ resolve,
1181
+ reject,
1182
+ timer,
1183
+ transform: options.transform
1184
+ });
1185
+ });
1186
+ this.poster.post(message);
1187
+ const cleanup = options.setup?.(id);
1188
+ if (cleanup) {
1189
+ const entry = this.pending.get(id);
1190
+ if (entry) entry.cleanup = cleanup;
1191
+ else cleanup();
1192
+ }
1193
+ return promise;
1194
+ }
1195
+ };
1196
+ //#endregion
1197
+ //#region src/rpc/message-router.ts
1198
+ /**
1199
+ * Owns the single transport.onMessage and dispatches each message to the one
1200
+ * consumer that owns its kind. Composes the shared RpcCorrelator (res/err) and
1201
+ * exposes request/nextId; attach/detach swap the transport for reconnect.
1202
+ */
1203
+ var MessageRouter = class {
1204
+ handlers = /* @__PURE__ */ new Map();
1205
+ correlator;
1206
+ transport = null;
1207
+ detachTransport = () => {};
1208
+ constructor(prefix = "r") {
1209
+ this.correlator = new RpcCorrelator(this, prefix);
1210
+ const settle = (message) => this.correlator.handleMessage(message);
1211
+ this.handlers.set("res", settle);
1212
+ this.handlers.set("err", settle);
1213
+ }
1214
+ attach(transport) {
1215
+ this.detachTransport();
1216
+ this.transport = transport;
1217
+ this.detachTransport = transport.onMessage((message) => {
1218
+ const msg = message;
1219
+ this.handlers.get(msg.k)?.(msg);
1220
+ });
1221
+ }
1222
+ detach() {
1223
+ this.detachTransport();
1224
+ this.detachTransport = () => {};
1225
+ this.transport = null;
1226
+ }
1227
+ post(message) {
1228
+ if (!this.transport) throw new Error("MessageRouter.post called before attach");
1229
+ this.transport.post(message);
1230
+ }
1231
+ /** Register the sole owner of a message kind; throws on a duplicate. */
1232
+ on(kind, handler) {
1233
+ if (this.handlers.has(kind)) throw new Error(`MessageRouter already has a handler for "${kind}"`);
1234
+ const route = handler;
1235
+ this.handlers.set(kind, route);
1236
+ return () => {
1237
+ if (this.handlers.get(kind) === route) this.handlers.delete(kind);
1238
+ };
1239
+ }
1240
+ request(build, options) {
1241
+ return this.correlator.request(build, options);
1242
+ }
1243
+ nextId() {
1244
+ return this.correlator.nextId();
1245
+ }
1246
+ };
1247
+ //#endregion
1248
+ export { FORWARDED_BUS_EVENT_TYPES, FORWARDED_EVENT_TYPES, KeyedListeners, Listeners, MessageRouter, RPC_DEFAULT_TIMEOUT_MS, RPC_PROTOCOL_VERSION, ReactorEventBusProxy, ReactorHost, ReactorHostServer, RpcCorrelator, SYNC_STATUS_CHANGED_EVENT, SubscriptionStore, SyncManagerProxy, WorkerPackageLoader, connectReactorClient, createCorrelatedSubscriptions, createInspectorProxy, createLiveQueryProxy, createPortTransport, createReactorClientProxy, createReactorEventBusProxy, createRelationalPgliteProxy, createSyncManagerProxy, createWorkerAdminClient, fromErrorInfo, hostResponder, opChannel, postReactorIdentity, toErrorInfo, toVoid };
1249
+
1250
+ //# sourceMappingURL=index.js.map