@powerhousedao/reactor-api 6.0.0-dev.43 → 6.0.0-dev.45

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 (35) hide show
  1. package/dist/src/graphql/reactor/factory.d.ts +11 -0
  2. package/dist/src/graphql/reactor/factory.d.ts.map +1 -1
  3. package/dist/src/graphql/reactor/gen/graphql.d.ts +103 -3
  4. package/dist/src/graphql/reactor/gen/graphql.d.ts.map +1 -1
  5. package/dist/src/graphql/reactor/gen/graphql.js +91 -0
  6. package/dist/src/graphql/reactor/gen/graphql.js.map +1 -1
  7. package/dist/src/graphql/reactor/operations.graphql +80 -0
  8. package/dist/src/graphql/reactor/requester.with-zod.d.ts.map +1 -1
  9. package/dist/src/graphql/reactor/requester.with-zod.js +4 -0
  10. package/dist/src/graphql/reactor/requester.with-zod.js.map +1 -1
  11. package/dist/src/graphql/reactor/resolvers.d.ts +7 -3
  12. package/dist/src/graphql/reactor/resolvers.d.ts.map +1 -1
  13. package/dist/src/graphql/reactor/resolvers.js +30 -20
  14. package/dist/src/graphql/reactor/resolvers.js.map +1 -1
  15. package/dist/src/graphql/reactor/schema.graphql +11 -1
  16. package/dist/src/graphql/reactor/subgraph.d.ts.map +1 -1
  17. package/dist/src/graphql/reactor/subgraph.js +6 -3
  18. package/dist/src/graphql/reactor/subgraph.js.map +1 -1
  19. package/dist/test/connect-switchboard-sync.test.d.ts +2 -0
  20. package/dist/test/connect-switchboard-sync.test.d.ts.map +1 -0
  21. package/dist/test/connect-switchboard-sync.test.js +561 -0
  22. package/dist/test/connect-switchboard-sync.test.js.map +1 -0
  23. package/dist/test/utils/gql-resolver-bridge.d.ts.map +1 -1
  24. package/dist/test/utils/gql-resolver-bridge.js +24 -2
  25. package/dist/test/utils/gql-resolver-bridge.js.map +1 -1
  26. package/dist/tsconfig.tsbuildinfo +1 -1
  27. package/package.json +16 -16
  28. package/dist/test/two-reactor-gql-catchup-duplicate.test.d.ts +0 -2
  29. package/dist/test/two-reactor-gql-catchup-duplicate.test.d.ts.map +0 -1
  30. package/dist/test/two-reactor-gql-catchup-duplicate.test.js +0 -264
  31. package/dist/test/two-reactor-gql-catchup-duplicate.test.js.map +0 -1
  32. package/dist/test/two-reactor-gql-sync.test.d.ts +0 -2
  33. package/dist/test/two-reactor-gql-sync.test.d.ts.map +0 -1
  34. package/dist/test/two-reactor-gql-sync.test.js +0 -335
  35. package/dist/test/two-reactor-gql-sync.test.js.map +0 -1
@@ -0,0 +1,561 @@
1
+ import { CompositeChannelFactory, ConsoleLogger, driveCollectionId, EventBus, JobStatus, ReactorBuilder, ReactorEventTypes, SyncBuilder, } from "@powerhousedao/reactor";
2
+ import { driveDocumentModelModule } from "document-drive";
3
+ import { afterEach, describe, expect, it } from "vitest";
4
+ import { createResolverBridge } from "./utils/gql-resolver-bridge.js";
5
+ async function setupConnectSwitchboard() {
6
+ const syncManagerRegistry = new Map();
7
+ const resolverBridge = createResolverBridge(syncManagerRegistry);
8
+ const logger = new ConsoleLogger(["test"]);
9
+ const connectEventBus = new EventBus();
10
+ const switchboardEventBus = new EventBus();
11
+ const connectModule = await new ReactorBuilder()
12
+ .withEventBus(connectEventBus)
13
+ .withDocumentModels([
14
+ driveDocumentModelModule,
15
+ ])
16
+ .withSync(new SyncBuilder().withChannelFactory(new CompositeChannelFactory(logger)))
17
+ .buildModule();
18
+ const switchboardModule = await new ReactorBuilder()
19
+ .withEventBus(switchboardEventBus)
20
+ .withDocumentModels([
21
+ driveDocumentModelModule,
22
+ ])
23
+ .withSync(new SyncBuilder().withChannelFactory(new CompositeChannelFactory(logger)))
24
+ .buildModule();
25
+ const switchboardSyncManager = switchboardModule.syncModule.syncManager;
26
+ syncManagerRegistry.set("switchboard", switchboardSyncManager);
27
+ const connectSyncManager = connectModule.syncModule.syncManager;
28
+ syncManagerRegistry.set("connect", connectSyncManager);
29
+ return {
30
+ connectReactor: connectModule.reactor,
31
+ switchboardReactor: switchboardModule.reactor,
32
+ connectModule,
33
+ switchboardModule,
34
+ connectEventBus,
35
+ switchboardEventBus,
36
+ connectSyncManager,
37
+ switchboardSyncManager,
38
+ resolverBridge,
39
+ };
40
+ }
41
+ async function setupSyncForDrive(connectSyncManager, driveId, resolverBridge) {
42
+ const collectionId = driveCollectionId("main", driveId);
43
+ await connectSyncManager.add(`switchboard-${driveId}`, collectionId, {
44
+ type: "gql",
45
+ parameters: {
46
+ url: "http://switchboard/graphql",
47
+ pollIntervalMs: 100,
48
+ maxFailures: 10,
49
+ retryBaseDelayMs: 50,
50
+ fetchFn: resolverBridge,
51
+ },
52
+ }, {
53
+ documentId: [],
54
+ scope: [],
55
+ branch: "main",
56
+ });
57
+ }
58
+ async function waitForJobCompletion(reactor, jobId, timeoutMs = 10000) {
59
+ const start = Date.now();
60
+ while (Date.now() - start < timeoutMs) {
61
+ const status = await reactor.getJobStatus(jobId);
62
+ if (status.status === JobStatus.READ_READY ||
63
+ status.status === JobStatus.FAILED) {
64
+ if (status.status === JobStatus.FAILED) {
65
+ throw new Error(`Job ${jobId} failed: ${status.error?.message ?? "unknown"}`);
66
+ }
67
+ return;
68
+ }
69
+ await new Promise((resolve) => setTimeout(resolve, 50));
70
+ }
71
+ throw new Error(`Timed out waiting for job ${jobId}`);
72
+ }
73
+ function waitForOperationsReady(eventBus, documentId, timeoutMs = 15000) {
74
+ return new Promise((resolve, reject) => {
75
+ let unsubscribe;
76
+ const timer = setTimeout(() => {
77
+ unsubscribe?.();
78
+ reject(new Error(`Timed out waiting for operations on document ${documentId}`));
79
+ }, timeoutMs);
80
+ unsubscribe = eventBus.subscribe(ReactorEventTypes.JOB_READ_READY, (_type, event) => {
81
+ const matchesDocument = event.operations.some((op) => op.context.documentId === documentId);
82
+ if (matchesDocument) {
83
+ clearTimeout(timer);
84
+ unsubscribe?.();
85
+ resolve();
86
+ }
87
+ });
88
+ });
89
+ }
90
+ async function setupSyncForDriveOnSwitchboard(switchboardSyncManager, driveId, resolverBridge) {
91
+ const collectionId = driveCollectionId("main", driveId);
92
+ await switchboardSyncManager.add(`connect-${driveId}`, collectionId, {
93
+ type: "gql",
94
+ parameters: {
95
+ url: "http://connect/graphql",
96
+ pollIntervalMs: 100,
97
+ maxFailures: 10,
98
+ retryBaseDelayMs: 50,
99
+ fetchFn: resolverBridge,
100
+ },
101
+ }, { documentId: [], scope: [], branch: "main" });
102
+ }
103
+ function waitForSyncStabilization(eventBuses, quietPeriodMs = 500, timeoutMs = 15000) {
104
+ return new Promise((resolve, reject) => {
105
+ let lastActivityTime = Date.now();
106
+ const unsubscribes = [];
107
+ const timer = setTimeout(() => {
108
+ cleanup();
109
+ reject(new Error("Timed out waiting for sync stabilization"));
110
+ }, timeoutMs);
111
+ const checkQuiet = setInterval(() => {
112
+ if (Date.now() - lastActivityTime >= quietPeriodMs) {
113
+ cleanup();
114
+ resolve();
115
+ }
116
+ }, 50);
117
+ function cleanup() {
118
+ clearTimeout(timer);
119
+ clearInterval(checkQuiet);
120
+ for (const unsub of unsubscribes)
121
+ unsub();
122
+ }
123
+ for (const bus of eventBuses) {
124
+ const unsub = bus.subscribe(ReactorEventTypes.JOB_READ_READY, () => {
125
+ lastActivityTime = Date.now();
126
+ });
127
+ unsubscribes.push(unsub);
128
+ }
129
+ });
130
+ }
131
+ describe("Connect-Switchboard Sync", () => {
132
+ let connectReactor;
133
+ let switchboardReactor;
134
+ let connectModule;
135
+ let switchboardModule;
136
+ let connectEventBus;
137
+ let switchboardEventBus;
138
+ let connectSyncManager;
139
+ let switchboardSyncManager;
140
+ let resolverBridge;
141
+ afterEach(() => {
142
+ connectReactor.kill();
143
+ switchboardReactor.kill();
144
+ });
145
+ it("should sync operation from Connect to Switchboard", async () => {
146
+ const setup = await setupConnectSwitchboard();
147
+ connectReactor = setup.connectReactor;
148
+ switchboardReactor = setup.switchboardReactor;
149
+ connectModule = setup.connectModule;
150
+ switchboardModule = setup.switchboardModule;
151
+ connectEventBus = setup.connectEventBus;
152
+ switchboardEventBus = setup.switchboardEventBus;
153
+ connectSyncManager = setup.connectSyncManager;
154
+ switchboardSyncManager = setup.switchboardSyncManager;
155
+ resolverBridge = setup.resolverBridge;
156
+ const document = driveDocumentModelModule.utils.createDocument({
157
+ global: {
158
+ name: "Test Drive???",
159
+ icon: null,
160
+ nodes: [],
161
+ },
162
+ });
163
+ const documentId = document.header.id;
164
+ await setupSyncForDrive(connectSyncManager, documentId, resolverBridge);
165
+ const readyOnSwitchboard = waitForOperationsReady(switchboardEventBus, documentId);
166
+ const jobInfo = await connectReactor.create(document);
167
+ await waitForJobCompletion(connectReactor, jobInfo.id);
168
+ await readyOnSwitchboard;
169
+ const connectOps = await connectReactor.getOperations(documentId, {
170
+ branch: "main",
171
+ });
172
+ const switchboardOps = await switchboardReactor.getOperations(documentId, {
173
+ branch: "main",
174
+ });
175
+ const connectOpsList = Object.values(connectOps).flatMap((scope) => scope.results);
176
+ const switchboardOpsList = Object.values(switchboardOps).flatMap((scope) => scope.results);
177
+ expect(connectOpsList.length).toBeGreaterThan(0);
178
+ expect(switchboardOpsList.length).toBe(connectOpsList.length);
179
+ for (let i = 0; i < connectOpsList.length; i++) {
180
+ expect(switchboardOpsList[i]).toEqual(connectOpsList[i]);
181
+ }
182
+ const connectDoc = await connectReactor.get(documentId, {
183
+ branch: "main",
184
+ });
185
+ const switchboardDoc = await switchboardReactor.get(documentId, {
186
+ branch: "main",
187
+ });
188
+ expect(connectDoc.state).toEqual(switchboardDoc.state);
189
+ }, 30000);
190
+ it("should sync operation from Switchboard to Connect", async () => {
191
+ const setup = await setupConnectSwitchboard();
192
+ connectReactor = setup.connectReactor;
193
+ switchboardReactor = setup.switchboardReactor;
194
+ connectModule = setup.connectModule;
195
+ switchboardModule = setup.switchboardModule;
196
+ connectEventBus = setup.connectEventBus;
197
+ switchboardEventBus = setup.switchboardEventBus;
198
+ connectSyncManager = setup.connectSyncManager;
199
+ switchboardSyncManager = setup.switchboardSyncManager;
200
+ resolverBridge = setup.resolverBridge;
201
+ const document = driveDocumentModelModule.utils.createDocument({
202
+ global: {
203
+ name: "Test Drive???",
204
+ icon: null,
205
+ nodes: [],
206
+ },
207
+ });
208
+ const documentId = document.header.id;
209
+ // Need a document on Connect first to set up the sync channel
210
+ await setupSyncForDrive(connectSyncManager, documentId, resolverBridge);
211
+ // Create document on Switchboard
212
+ const readyOnConnect = waitForOperationsReady(connectEventBus, documentId);
213
+ const jobInfo = await switchboardReactor.create(document);
214
+ await waitForJobCompletion(switchboardReactor, jobInfo.id);
215
+ // Connect polls Switchboard's outbox
216
+ await readyOnConnect;
217
+ const connectOps = await connectReactor.getOperations(documentId, {
218
+ branch: "main",
219
+ });
220
+ const switchboardOps = await switchboardReactor.getOperations(documentId, {
221
+ branch: "main",
222
+ });
223
+ const connectOpsList = Object.values(connectOps).flatMap((scope) => scope.results);
224
+ const switchboardOpsList = Object.values(switchboardOps).flatMap((scope) => scope.results);
225
+ expect(switchboardOpsList.length).toBeGreaterThan(0);
226
+ expect(connectOpsList.length).toBe(switchboardOpsList.length);
227
+ for (let i = 0; i < switchboardOpsList.length; i++) {
228
+ expect(connectOpsList[i]).toEqual(switchboardOpsList[i]);
229
+ }
230
+ const connectDoc = await connectReactor.get(documentId, {
231
+ branch: "main",
232
+ });
233
+ const switchboardDoc = await switchboardReactor.get(documentId, {
234
+ branch: "main",
235
+ });
236
+ expect(connectDoc.state).toEqual(switchboardDoc.state);
237
+ }, 30000);
238
+ it("should sync mutations from Connect to Switchboard", async () => {
239
+ const setup = await setupConnectSwitchboard();
240
+ connectReactor = setup.connectReactor;
241
+ switchboardReactor = setup.switchboardReactor;
242
+ connectModule = setup.connectModule;
243
+ switchboardModule = setup.switchboardModule;
244
+ connectEventBus = setup.connectEventBus;
245
+ switchboardEventBus = setup.switchboardEventBus;
246
+ connectSyncManager = setup.connectSyncManager;
247
+ switchboardSyncManager = setup.switchboardSyncManager;
248
+ resolverBridge = setup.resolverBridge;
249
+ const document = driveDocumentModelModule.utils.createDocument();
250
+ const documentId = document.header.id;
251
+ await setupSyncForDrive(connectSyncManager, documentId, resolverBridge);
252
+ // Step 1: Create document on Connect, sync to Switchboard
253
+ const createReady = waitForOperationsReady(switchboardEventBus, documentId);
254
+ const createJob = await connectReactor.create(document);
255
+ await waitForJobCompletion(connectReactor, createJob.id);
256
+ await createReady;
257
+ // Step 2: Mutate on Connect
258
+ const mutationReady = waitForOperationsReady(switchboardEventBus, documentId);
259
+ const mutateJob = await connectReactor.execute(documentId, "main", [
260
+ driveDocumentModelModule.actions.setDriveName({ name: "Synced Drive" }),
261
+ ]);
262
+ await waitForJobCompletion(connectReactor, mutateJob.id);
263
+ await mutationReady;
264
+ // Step 3: Verify
265
+ const connectDoc = await connectReactor.get(documentId, {
266
+ branch: "main",
267
+ });
268
+ const switchboardDoc = await switchboardReactor.get(documentId, {
269
+ branch: "main",
270
+ });
271
+ expect(connectDoc.state).toEqual(switchboardDoc.state);
272
+ const state = connectDoc.state;
273
+ expect(state.global.name).toBe("Synced Drive");
274
+ }, 30000);
275
+ describe("sourceRemote echo prevention", () => {
276
+ it("local mutations always have sourceRemote=''", async () => {
277
+ const setup = await setupConnectSwitchboard();
278
+ connectReactor = setup.connectReactor;
279
+ switchboardReactor = setup.switchboardReactor;
280
+ connectModule = setup.connectModule;
281
+ switchboardModule = setup.switchboardModule;
282
+ connectEventBus = setup.connectEventBus;
283
+ switchboardEventBus = setup.switchboardEventBus;
284
+ connectSyncManager = setup.connectSyncManager;
285
+ switchboardSyncManager = setup.switchboardSyncManager;
286
+ resolverBridge = setup.resolverBridge;
287
+ const document = driveDocumentModelModule.utils.createDocument({
288
+ global: { name: "Local Test", icon: null, nodes: [] },
289
+ });
290
+ const documentId = document.header.id;
291
+ const createJob = await connectReactor.create(document);
292
+ await waitForJobCompletion(connectReactor, createJob.id);
293
+ const mutateJob = await connectReactor.execute(documentId, "main", [
294
+ driveDocumentModelModule.actions.setDriveName({
295
+ name: "Local Mutation",
296
+ }),
297
+ ]);
298
+ await waitForJobCompletion(connectReactor, mutateJob.id);
299
+ const indexResult = await connectModule.operationIndex.get(documentId);
300
+ const entries = indexResult.results;
301
+ expect(entries.length).toBeGreaterThan(0);
302
+ for (const entry of entries) {
303
+ expect(entry.sourceRemote).toBe("");
304
+ }
305
+ }, 30000);
306
+ it("trivial append operations are not echoed back to source", async () => {
307
+ const setup = await setupConnectSwitchboard();
308
+ connectReactor = setup.connectReactor;
309
+ switchboardReactor = setup.switchboardReactor;
310
+ connectModule = setup.connectModule;
311
+ switchboardModule = setup.switchboardModule;
312
+ connectEventBus = setup.connectEventBus;
313
+ switchboardEventBus = setup.switchboardEventBus;
314
+ connectSyncManager = setup.connectSyncManager;
315
+ switchboardSyncManager = setup.switchboardSyncManager;
316
+ resolverBridge = setup.resolverBridge;
317
+ const document = driveDocumentModelModule.utils.createDocument({
318
+ global: { name: "Echo Test", icon: null, nodes: [] },
319
+ });
320
+ const documentId = document.header.id;
321
+ await setupSyncForDrive(connectSyncManager, documentId, resolverBridge);
322
+ await setupSyncForDriveOnSwitchboard(switchboardSyncManager, documentId, resolverBridge);
323
+ const createOnSwitchboard = waitForOperationsReady(switchboardEventBus, documentId);
324
+ const createJob = await connectReactor.create(document);
325
+ await waitForJobCompletion(connectReactor, createJob.id);
326
+ await createOnSwitchboard;
327
+ const mutationOnSwitchboard = waitForOperationsReady(switchboardEventBus, documentId);
328
+ const mutateJob = await connectReactor.execute(documentId, "main", [
329
+ driveDocumentModelModule.actions.setDriveName({ name: "No Echo" }),
330
+ ]);
331
+ await waitForJobCompletion(connectReactor, mutateJob.id);
332
+ await mutationOnSwitchboard;
333
+ // Inspect Switchboard's sourceRemote values to understand the mechanism
334
+ const switchboardIndex = await switchboardModule.operationIndex.get(documentId);
335
+ const switchboardEntries = switchboardIndex.results;
336
+ const remoteEntries = switchboardEntries.filter((e) => e.sourceRemote !== "");
337
+ expect(remoteEntries.length).toBeGreaterThan(0);
338
+ // Verify the sourceRemote value on Switchboard.
339
+ // Push-delivered ops get sourceRemote from the touchChannel resolver,
340
+ // which uses the sender's remote name (e.g., "switchboard-{driveId}").
341
+ // The outbox filters by excludeSourceRemote = remote.name
342
+ // (e.g., "connect-{driveId}"). These don't match for push-delivered
343
+ // ops, so echo prevention relies on dedup rather than outbox filtering.
344
+ const sourceRemoteValues = [
345
+ ...new Set(remoteEntries.map((e) => e.sourceRemote)),
346
+ ];
347
+ const connectRemoteName = `connect-${documentId}`;
348
+ const pushSourceRemoteMatchesOutboxFilter = sourceRemoteValues.every((v) => v === connectRemoteName);
349
+ // Verify the outbox filter behavior: query with the actual
350
+ // excludeSourceRemote used by Switchboard's connect-{driveId} remote
351
+ const collectionId = driveCollectionId("main", documentId);
352
+ const filteredIndex = await switchboardModule.operationIndex.find(collectionId, 0, { excludeSourceRemote: connectRemoteName });
353
+ if (!pushSourceRemoteMatchesOutboxFilter) {
354
+ // Known issue: push-delivered ops have a different sourceRemote
355
+ // than the outbox filter expects. The outbox filter does NOT
356
+ // catch these ops; echo prevention relies on dedup instead.
357
+ // The filtered result will include remote ops that should have
358
+ // been filtered out.
359
+ expect(filteredIndex.results.length).toBeGreaterThan(0);
360
+ }
361
+ const connectIndexBefore = await connectModule.operationIndex.get(documentId);
362
+ const connectCountBefore = connectIndexBefore.results.length;
363
+ await waitForSyncStabilization([connectEventBus, switchboardEventBus]);
364
+ const connectIndexAfter = await connectModule.operationIndex.get(documentId);
365
+ const connectCountAfter = connectIndexAfter.results.length;
366
+ expect(connectCountAfter).toBe(connectCountBefore);
367
+ const connectEntries = connectIndexAfter.results;
368
+ for (const entry of connectEntries) {
369
+ expect(entry.sourceRemote).toBe("");
370
+ }
371
+ const connectDoc = await connectReactor.get(documentId, {
372
+ branch: "main",
373
+ });
374
+ const switchboardDoc = await switchboardReactor.get(documentId, {
375
+ branch: "main",
376
+ });
377
+ expect(connectDoc.state).toEqual(switchboardDoc.state);
378
+ }, 30000);
379
+ it("all-duplicate load job completes without wedging the queue", async () => {
380
+ const setup = await setupConnectSwitchboard();
381
+ connectReactor = setup.connectReactor;
382
+ switchboardReactor = setup.switchboardReactor;
383
+ connectModule = setup.connectModule;
384
+ switchboardModule = setup.switchboardModule;
385
+ connectEventBus = setup.connectEventBus;
386
+ switchboardEventBus = setup.switchboardEventBus;
387
+ connectSyncManager = setup.connectSyncManager;
388
+ switchboardSyncManager = setup.switchboardSyncManager;
389
+ resolverBridge = setup.resolverBridge;
390
+ const document = driveDocumentModelModule.utils.createDocument({
391
+ global: { name: "Wedge Test", icon: null, nodes: [] },
392
+ });
393
+ const documentId = document.header.id;
394
+ // Unidirectional sync: Connect -> Switchboard
395
+ await setupSyncForDrive(connectSyncManager, documentId, resolverBridge);
396
+ const createOnSwitchboard = waitForOperationsReady(switchboardEventBus, documentId);
397
+ const createJob = await connectReactor.create(document);
398
+ await waitForJobCompletion(connectReactor, createJob.id);
399
+ await createOnSwitchboard;
400
+ // Mutate on Connect, sync mutation to Switchboard (produces global-scope ops)
401
+ const mutationOnSwitchboard = waitForOperationsReady(switchboardEventBus, documentId);
402
+ const mutateJob = await connectReactor.execute(documentId, "main", [
403
+ driveDocumentModelModule.actions.setDriveName({
404
+ name: "Wedge Mutated",
405
+ }),
406
+ ]);
407
+ await waitForJobCompletion(connectReactor, mutateJob.id);
408
+ await mutationOnSwitchboard;
409
+ // Record Switchboard's index count
410
+ const indexBefore = await switchboardModule.operationIndex.get(documentId);
411
+ const countBefore = indexBefore.results.length;
412
+ expect(countBefore).toBeGreaterThan(0);
413
+ // Get Switchboard's global-scope operations (already stored)
414
+ const switchboardOps = await switchboardReactor.getOperations(documentId, { branch: "main" });
415
+ const globalOps = switchboardOps["global"]?.results ?? [];
416
+ expect(globalOps.length).toBeGreaterThan(0);
417
+ // Load exact duplicates into Switchboard via reactor.load().
418
+ // All ops already exist, so executor dedup filters them all out.
419
+ // Before the P0 fix, the load job would hang forever because
420
+ // JOB_WRITE_READY was not emitted for empty operationsWithContext.
421
+ const loadJob = await switchboardReactor.load(documentId, "main", globalOps);
422
+ await waitForJobCompletion(switchboardReactor, loadJob.id);
423
+ // Verify the job reached READ_READY (not stuck at RUNNING)
424
+ const jobStatus = await switchboardReactor.getJobStatus(loadJob.id);
425
+ expect(jobStatus.status).toBe(JobStatus.READ_READY);
426
+ // Verify no new index entries were created
427
+ const indexAfter = await switchboardModule.operationIndex.get(documentId);
428
+ expect(indexAfter.results.length).toBe(countBefore);
429
+ }, 30000);
430
+ it("executor-level dedup rejects duplicate operations via load", async () => {
431
+ const setup = await setupConnectSwitchboard();
432
+ connectReactor = setup.connectReactor;
433
+ switchboardReactor = setup.switchboardReactor;
434
+ connectModule = setup.connectModule;
435
+ switchboardModule = setup.switchboardModule;
436
+ connectEventBus = setup.connectEventBus;
437
+ switchboardEventBus = setup.switchboardEventBus;
438
+ connectSyncManager = setup.connectSyncManager;
439
+ switchboardSyncManager = setup.switchboardSyncManager;
440
+ resolverBridge = setup.resolverBridge;
441
+ const document = driveDocumentModelModule.utils.createDocument({
442
+ global: { name: "Dedup Test", icon: null, nodes: [] },
443
+ });
444
+ const documentId = document.header.id;
445
+ // Unidirectional sync: Connect -> Switchboard
446
+ await setupSyncForDrive(connectSyncManager, documentId, resolverBridge);
447
+ const createOnSwitchboard = waitForOperationsReady(switchboardEventBus, documentId);
448
+ const createJob = await connectReactor.create(document);
449
+ await waitForJobCompletion(connectReactor, createJob.id);
450
+ await createOnSwitchboard;
451
+ // Mutate on Connect, sync mutation to Switchboard
452
+ const mutationOnSwitchboard = waitForOperationsReady(switchboardEventBus, documentId);
453
+ const mutateJob = await connectReactor.execute(documentId, "main", [
454
+ driveDocumentModelModule.actions.setDriveName({ name: "Dedup" }),
455
+ ]);
456
+ await waitForJobCompletion(connectReactor, mutateJob.id);
457
+ await mutationOnSwitchboard;
458
+ // Verify ops are synced
459
+ const switchboardOps = await switchboardReactor.getOperations(documentId, { branch: "main" });
460
+ const globalOps = switchboardOps["global"]?.results ?? [];
461
+ expect(globalOps.length).toBeGreaterThan(0);
462
+ // Record Switchboard's index count
463
+ const indexBefore = await switchboardModule.operationIndex.get(documentId);
464
+ const countBefore = indexBefore.results.length;
465
+ expect(countBefore).toBeGreaterThan(0);
466
+ // Load exact same operations again via reactor.load().
467
+ // This exercises the executor's existingActionIds.has(op.action.id) dedup,
468
+ // NOT cursor advancement (which only trims the outbox on subsequent polls).
469
+ const loadJob = await switchboardReactor.load(documentId, "main", globalOps);
470
+ await waitForJobCompletion(switchboardReactor, loadJob.id);
471
+ // Verify job completed
472
+ const jobStatus = await switchboardReactor.getJobStatus(loadJob.id);
473
+ expect(jobStatus.status).toBe(JobStatus.READ_READY);
474
+ // Verify index count unchanged (executor dedup rejected all ops)
475
+ const indexAfter = await switchboardModule.operationIndex.get(documentId);
476
+ expect(indexAfter.results.length).toBe(countBefore);
477
+ }, 30000);
478
+ it("reshuffle operations converge and terminate", async () => {
479
+ const setup = await setupConnectSwitchboard();
480
+ connectReactor = setup.connectReactor;
481
+ switchboardReactor = setup.switchboardReactor;
482
+ connectModule = setup.connectModule;
483
+ switchboardModule = setup.switchboardModule;
484
+ connectEventBus = setup.connectEventBus;
485
+ switchboardEventBus = setup.switchboardEventBus;
486
+ connectSyncManager = setup.connectSyncManager;
487
+ switchboardSyncManager = setup.switchboardSyncManager;
488
+ resolverBridge = setup.resolverBridge;
489
+ const document = driveDocumentModelModule.utils.createDocument();
490
+ const documentId = document.header.id;
491
+ // Unidirectional sync first: Connect -> Switchboard
492
+ await setupSyncForDrive(connectSyncManager, documentId, resolverBridge);
493
+ // Create document on Connect, sync to Switchboard
494
+ const createOnSwitchboard = waitForOperationsReady(switchboardEventBus, documentId);
495
+ const createJob = await connectReactor.create(document);
496
+ await waitForJobCompletion(connectReactor, createJob.id);
497
+ await createOnSwitchboard;
498
+ // Remove sync to prevent polling from loading T1 as a trivial append
499
+ // (preserving sourceRemote) before Connect creates T2.
500
+ await connectSyncManager.remove(`switchboard-${documentId}`);
501
+ // Mutate on Switchboard first (earlier timestamp T1)
502
+ const switchboardMutateJob = await switchboardReactor.execute(documentId, "main", [
503
+ driveDocumentModelModule.actions.setDriveName({
504
+ name: "Switchboard Mutation",
505
+ }),
506
+ ]);
507
+ await waitForJobCompletion(switchboardReactor, switchboardMutateJob.id);
508
+ // Wait to ensure Connect's mutation gets a later timestamp T2
509
+ await new Promise((r) => setTimeout(r, 10));
510
+ // Mutate on Connect (later timestamp T2 > T1)
511
+ const connectMutateJob = await connectReactor.execute(documentId, "main", [
512
+ driveDocumentModelModule.actions.setDriveName({
513
+ name: "Connect Mutation",
514
+ }),
515
+ ]);
516
+ await waitForJobCompletion(connectReactor, connectMutateJob.id);
517
+ // Get Switchboard's global-scope operations
518
+ const switchboardOps = await switchboardReactor.getOperations(documentId, { branch: "main" });
519
+ const switchboardGlobalOps = switchboardOps["global"]?.results ?? [];
520
+ // Load Switchboard's ops into Connect via reactor.load().
521
+ // Switchboard's T1 mutation triggers getConflicting() which finds
522
+ // Connect's T2 operation -> skipCount > 0 -> reshuffle deterministically.
523
+ const loadJob = await connectReactor.load(documentId, "main", switchboardGlobalOps);
524
+ await waitForJobCompletion(connectReactor, loadJob.id);
525
+ // After reshuffle, all Connect index entries should have sourceRemote=""
526
+ // (reshuffle sets effectiveSourceRemote="" to broadcast to all remotes)
527
+ const connectIndex = await connectModule.operationIndex.get(documentId);
528
+ const connectEntries = connectIndex.results;
529
+ for (const entry of connectEntries) {
530
+ expect(entry.sourceRemote).toBe("");
531
+ }
532
+ // Verify Connect's state reflects the reshuffle result
533
+ const connectDoc = await connectReactor.get(documentId, {
534
+ branch: "main",
535
+ });
536
+ expect(connectDoc.state).toBeDefined();
537
+ // Re-establish Connect->Switchboard sync for bidirectional convergence test
538
+ await setupSyncForDrive(connectSyncManager, documentId, resolverBridge);
539
+ // Now set up bidirectional sync and verify echo termination
540
+ await setupSyncForDriveOnSwitchboard(switchboardSyncManager, documentId, resolverBridge);
541
+ await waitForSyncStabilization([connectEventBus, switchboardEventBus], 1000, 20000);
542
+ // States should converge
543
+ const connectDocFinal = await connectReactor.get(documentId, {
544
+ branch: "main",
545
+ });
546
+ const switchboardDocFinal = await switchboardReactor.get(documentId, {
547
+ branch: "main",
548
+ });
549
+ expect(connectDocFinal.state).toEqual(switchboardDocFinal.state);
550
+ // Verify operation counts stabilized (echo terminated)
551
+ const connectCountAfterSync = (await connectModule.operationIndex.get(documentId)).results.length;
552
+ const switchboardCountAfterSync = (await switchboardModule.operationIndex.get(documentId)).results.length;
553
+ await new Promise((r) => setTimeout(r, 1000));
554
+ const connectCountFinal = (await connectModule.operationIndex.get(documentId)).results.length;
555
+ const switchboardCountFinal = (await switchboardModule.operationIndex.get(documentId)).results.length;
556
+ expect(connectCountFinal).toBe(connectCountAfterSync);
557
+ expect(switchboardCountFinal).toBe(switchboardCountAfterSync);
558
+ }, 30000);
559
+ });
560
+ });
561
+ //# sourceMappingURL=connect-switchboard-sync.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect-switchboard-sync.test.js","sourceRoot":"","sources":["../../test/connect-switchboard-sync.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"gql-resolver-bridge.d.ts","sourceRoot":"","sources":["../../../test/utils/gql-resolver-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAO3D,KAAK,mBAAmB,GAAG,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AA8BrD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,mBAAmB,GAChC,OAAO,KAAK,CAmFd"}
1
+ {"version":3,"file":"gql-resolver-bridge.d.ts","sourceRoot":"","sources":["../../../test/utils/gql-resolver-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAO3D,KAAK,mBAAmB,GAAG,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AA8BrD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,mBAAmB,GAChC,OAAO,KAAK,CAyHd"}
@@ -41,17 +41,39 @@ export function createResolverBridge(syncManagers) {
41
41
  const syncManager = extractSyncManagerFromUrl(url, syncManagers);
42
42
  if (body.query.includes("pollSyncEnvelopes")) {
43
43
  const variables = body.variables;
44
- const result = await pollSyncEnvelopes(syncManager, variables);
45
- return createMockResponse({ pollSyncEnvelopes: result });
44
+ const result = pollSyncEnvelopes(syncManager, variables);
45
+ if (result.envelopes.length > 0) {
46
+ console.log(`[BRIDGE] pollSyncEnvelopes: ${result.envelopes.length} envelopes for channel ${variables.channelId}`);
47
+ }
48
+ // Normalize envelopes for GqlRequestChannel compatibility:
49
+ // 1. Lowercase type ("OPERATIONS" -> "operations")
50
+ // 2. Filter empty dependency strings (outbox can have "" as initial prevJobId)
51
+ const normalizedEnvelopes = result.envelopes.map((env) => ({
52
+ ...env,
53
+ type: env.type.toLowerCase(),
54
+ dependsOn: Array.isArray(env.dependsOn)
55
+ ? env.dependsOn.filter(Boolean)
56
+ : env.dependsOn,
57
+ }));
58
+ return createMockResponse({
59
+ pollSyncEnvelopes: {
60
+ envelopes: normalizedEnvelopes,
61
+ ackOrdinal: result.ackOrdinal,
62
+ },
63
+ });
46
64
  }
47
65
  if (body.query.includes("pushSyncEnvelopes")) {
48
66
  const variables = body.variables;
67
+ const envelopeOps = variables.envelopes.flatMap((e) => (e.operations ?? []).map((op) => op.context.documentId));
68
+ console.log(`[BRIDGE] pushSyncEnvelopes: ${variables.envelopes.length} envelopes, docs: ${[...new Set(envelopeOps)].join(",")}`);
49
69
  const result = await pushSyncEnvelopes(syncManager, variables);
50
70
  return createMockResponse({ pushSyncEnvelopes: result });
51
71
  }
52
72
  if (body.query.includes("touchChannel")) {
53
73
  const variables = body.variables;
74
+ console.log(`[BRIDGE] touchChannel: id=${variables.input.id} collection=${variables.input.collectionId}`);
54
75
  const result = await touchChannel(syncManager, variables);
76
+ console.log(`[BRIDGE] touchChannel result: ${result}`);
55
77
  return createMockResponse({ touchChannel: result });
56
78
  }
57
79
  throw new Error(`Unknown GraphQL operation in query: ${body.query}`);