@ibgib/core-gib 0.1.21 → 0.1.22

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 (113) hide show
  1. package/dist/sync/sync-conflict.respec.mjs +24 -22
  2. package/dist/sync/sync-conflict.respec.mjs.map +1 -1
  3. package/dist/sync/sync-constants.d.mts +8 -8
  4. package/dist/sync/sync-constants.d.mts.map +1 -1
  5. package/dist/sync/sync-constants.mjs +3 -3
  6. package/dist/sync/sync-constants.mjs.map +1 -1
  7. package/dist/sync/sync-helpers.d.mts +2 -0
  8. package/dist/sync/sync-helpers.d.mts.map +1 -1
  9. package/dist/sync/sync-helpers.mjs +11 -9
  10. package/dist/sync/sync-helpers.mjs.map +1 -1
  11. package/dist/sync/sync-innerspace-constants.respec.mjs +5 -1
  12. package/dist/sync/sync-innerspace-constants.respec.mjs.map +1 -1
  13. package/dist/sync/sync-innerspace-deep-updates.respec.mjs +5 -1
  14. package/dist/sync/sync-innerspace-deep-updates.respec.mjs.map +1 -1
  15. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs +8 -4
  16. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs.map +1 -1
  17. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs +5 -1
  18. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs.map +1 -1
  19. package/dist/sync/sync-innerspace-partial-update.respec.mjs +5 -1
  20. package/dist/sync/sync-innerspace-partial-update.respec.mjs.map +1 -1
  21. package/dist/sync/sync-innerspace.respec.mjs +5 -1
  22. package/dist/sync/sync-innerspace.respec.mjs.map +1 -1
  23. package/dist/sync/sync-peer/sync-peer-constants.d.mts +2 -0
  24. package/dist/sync/sync-peer/sync-peer-constants.d.mts.map +1 -0
  25. package/dist/sync/sync-peer/sync-peer-constants.mjs +2 -0
  26. package/dist/sync/sync-peer/sync-peer-constants.mjs.map +1 -0
  27. package/dist/sync/sync-peer/sync-peer-helpers.d.mts +2 -0
  28. package/dist/sync/sync-peer/sync-peer-helpers.d.mts.map +1 -0
  29. package/dist/sync/sync-peer/sync-peer-helpers.mjs +2 -0
  30. package/dist/sync/sync-peer/sync-peer-helpers.mjs.map +1 -0
  31. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.d.mts +8 -0
  32. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.d.mts.map +1 -0
  33. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs +8 -0
  34. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs.map +1 -0
  35. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-helpers.d.mts +18 -0
  36. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-helpers.d.mts.map +1 -0
  37. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-helpers.mjs +54 -0
  38. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-helpers.mjs.map +1 -0
  39. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.d.mts +80 -0
  40. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.d.mts.map +1 -0
  41. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.mjs +5 -0
  42. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.mjs.map +1 -0
  43. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts +43 -0
  44. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts.map +1 -0
  45. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs +229 -0
  46. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs.map +1 -0
  47. package/dist/sync/sync-peer/sync-peer-types.d.mts +12 -0
  48. package/dist/sync/sync-peer/sync-peer-types.d.mts.map +1 -1
  49. package/dist/sync/sync-peer/sync-peer-v1.d.mts +15 -7
  50. package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
  51. package/dist/sync/sync-peer/sync-peer-v1.mjs +105 -24
  52. package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
  53. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts +5 -8
  54. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts.map +1 -1
  55. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs +34 -18
  56. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs.map +1 -1
  57. package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts +26 -22
  58. package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts.map +1 -1
  59. package/dist/sync/sync-saga-context/sync-saga-context-types.mjs +1 -9
  60. package/dist/sync/sync-saga-context/sync-saga-context-types.mjs.map +1 -1
  61. package/dist/sync/sync-saga-coordinator.d.mts +23 -33
  62. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  63. package/dist/sync/sync-saga-coordinator.mjs +271 -163
  64. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  65. package/dist/sync/sync-types.d.mts +15 -3
  66. package/dist/sync/sync-types.d.mts.map +1 -1
  67. package/dist/witness/light-witness-base-v1.d.mts.map +1 -1
  68. package/dist/witness/light-witness-base-v1.mjs +2 -0
  69. package/dist/witness/light-witness-base-v1.mjs.map +1 -1
  70. package/dist/witness/space/inner-space/inner-space-v1.mjs +1 -1
  71. package/dist/witness/space/inner-space/inner-space-v1.mjs.map +1 -1
  72. package/package.json +1 -1
  73. package/src/sync/README.md +31 -22
  74. package/src/sync/sync-conflict.respec.mts +23 -19
  75. package/src/sync/sync-constants.mts +4 -5
  76. package/src/sync/sync-helpers.mts +11 -7
  77. package/src/sync/sync-innerspace-constants.respec.mts +5 -1
  78. package/src/sync/sync-innerspace-deep-updates.respec.mts +5 -1
  79. package/src/sync/sync-innerspace-dest-ahead.respec.mts +7 -3
  80. package/src/sync/sync-innerspace-multiple-timelines.respec.mts +5 -1
  81. package/src/sync/sync-innerspace-partial-update.respec.mts +8 -2
  82. package/src/sync/sync-innerspace.respec.mts +5 -1
  83. package/src/sync/sync-peer/sync-peer-constants.mts +0 -0
  84. package/src/sync/sync-peer/sync-peer-helpers.mts +0 -0
  85. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mts +8 -0
  86. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-helpers.mts +72 -0
  87. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.mts +87 -0
  88. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +242 -0
  89. package/src/sync/sync-peer/sync-peer-types.mts +13 -1
  90. package/src/sync/sync-peer/sync-peer-v1.mts +93 -27
  91. package/src/sync/sync-saga-context/sync-saga-context-helpers.mts +47 -29
  92. package/src/sync/sync-saga-context/sync-saga-context-types.mts +29 -30
  93. package/src/sync/sync-saga-coordinator.mts +280 -170
  94. package/src/sync/sync-types.mts +17 -3
  95. package/src/witness/light-witness-base-v1.mts +2 -1
  96. package/src/witness/space/inner-space/inner-space-v1.mts +1 -1
  97. package/test_output.log +0 -0
  98. package/tmp.md +62 -44
  99. package/dist/sync/sync-local-spaces.respec.d.mts +0 -2
  100. package/dist/sync/sync-local-spaces.respec.d.mts.map +0 -1
  101. package/dist/sync/sync-local-spaces.respec.mjs +0 -159
  102. package/dist/sync/sync-local-spaces.respec.mjs.map +0 -1
  103. package/dist/sync/sync-peer/sync-peer-innerspace-v1.d.mts +0 -42
  104. package/dist/sync/sync-peer/sync-peer-innerspace-v1.d.mts.map +0 -1
  105. package/dist/sync/sync-peer/sync-peer-innerspace-v1.mjs +0 -194
  106. package/dist/sync/sync-peer/sync-peer-innerspace-v1.mjs.map +0 -1
  107. package/dist/sync/sync-saga-coordinator.respec.d.mts +0 -2
  108. package/dist/sync/sync-saga-coordinator.respec.d.mts.map +0 -1
  109. package/dist/sync/sync-saga-coordinator.respec.mjs +0 -40
  110. package/dist/sync/sync-saga-coordinator.respec.mjs.map +0 -1
  111. package/src/sync/sync-local-spaces.respec.mts +0 -200
  112. package/src/sync/sync-peer/sync-peer-innerspace-v1.mts +0 -240
  113. package/src/sync/sync-saga-coordinator.respec.mts +0 -52
@@ -1,24 +1,27 @@
1
1
  import { extractErrorMsg, getUUID, // so our timestamp in ticks as a string are uniform
2
- pretty } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
2
+ pretty, } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
3
3
  import { getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
4
- import { splitPerTjpAndOrDna, getTimelinesGroupedByTjp } from "../common/other/ibgib-helper.mjs";
4
+ import { splitPerTjpAndOrDna, getTimelinesGroupedByTjp, isIbGib } from "../common/other/ibgib-helper.mjs";
5
5
  import { Factory_V1 } from "@ibgib/ts-gib/dist/V1/factory.mjs";
6
- import { GLOBAL_LOG_A_LOT } from "../core-constants.mjs";
7
6
  import { putInSpace, getLatestAddrs, getFromSpace } from "../witness/space/space-helper.mjs";
8
- import { SyncStage, SYNC_ATOM, SYNC_MSG_REL8N_NAME } from "./sync-constants.mjs";
7
+ import { SyncStage, SYNC_ATOM, SYNC_MSG_REL8N_NAME, SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN } from "./sync-constants.mjs";
9
8
  import { appendToTimeline, createTimeline } from "../timeline/timeline-api.mjs";
10
9
  import { SyncMode, } from "./sync-types.mjs";
11
10
  import { getSyncIb, isPastFrame } from "./sync-helpers.mjs";
12
- import { getSyncSagaDependencyGraph } from "./sync-helpers.mjs";
11
+ import { getSyncSagaDependencyGraph as getSyncSagaDependencyGraphForThisFrameOnly } from "./sync-helpers.mjs";
13
12
  import { getDependencyGraph } from "../common/other/graph-helper.mjs";
14
13
  import { getSyncSagaMessageIb } from "./sync-saga-message/sync-saga-message-helpers.mjs";
15
14
  import { SYNC_SAGA_MSG_ATOM } from "./sync-saga-message/sync-saga-message-constants.mjs";
16
- import { SyncSagaContextCmd } from "./sync-saga-context/sync-saga-context-types.mjs";
17
15
  import { createSyncSagaContext } from "./sync-saga-context/sync-saga-context-helpers.mjs";
18
- import { newupSubject } from "../common/pubsub/subject/subject-helper.mjs";
16
+ import { newupSubject, } from "../common/pubsub/subject/subject-helper.mjs";
19
17
  import { mergeDivergentTimelines } from "./strategies/conflict-optimistic.mjs";
20
18
  import { getSyncSagaMessageFromFrame } from "./sync-saga-message/sync-saga-message-helpers.mjs";
21
- const logalot = GLOBAL_LOG_A_LOT || true;
19
+ import { fnObs } from "../common/pubsub/observer/observer-helper.mjs";
20
+ import { SyncPeerInnerspace_V1 } from "./sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs";
21
+ // const logalot = GLOBAL_LOG_A_LOT || true;
22
+ const logalot = false;
23
+ const logalotControlDomain = true;
24
+ const lcControlDomain = '[ControlDomain]';
22
25
  /**
23
26
  * Orchestrates the synchronization process between two spaces (Source and Destination).
24
27
  *
@@ -115,6 +118,14 @@ export class SyncSagaCoordinator {
115
118
  conflictStrategy
116
119
  });
117
120
  // 4. EXECUTE SAGA LOOP (FSM)
121
+ // Inject tempSpace into peer so it can pull control payloads to the right place
122
+ // if ('opts' in peer && peer.opts) {
123
+ if (!peer.data) {
124
+ throw new Error(`(UNEXPECTED) peer.data falsy? (E: 8546a884c82ffb1999e95d9867da2826)`);
125
+ }
126
+ if (peer.data.classname === SyncPeerInnerspace_V1.name) {
127
+ // (peer as SyncPeerInnerspace_V1).senderTempSpace = tempSpace;
128
+ }
118
129
  const syncedIbGibs = await this.executeSagaLoop({
119
130
  initialFrame: initFrame,
120
131
  srcGraph,
@@ -207,74 +218,123 @@ export class SyncSagaCoordinator {
207
218
  // The current frame we just generated (e.g., Init or Delta Request)
208
219
  let currentFrame = initialFrame;
209
220
  // The payload we need to attach to the message (data we are sending)
210
- let nextPayloadIbGibs = [];
221
+ let nextDomainIbGibs = [];
211
222
  // Accumulator for all data we've successfully pulled from the remote
212
223
  const allReceivedIbGibs = [];
213
224
  while (currentFrame) {
214
225
  // A. Create Context (Request)
215
226
  // 1. Calculate Full Dependency Graph (including Ancestors/DNA)
216
- // We must do this BEFORE creating the Context so we can list them all in payloadAddrs.
217
- const allDeps = [];
227
+ // TODO: adjust this algorithm to only do the dependencies that the other end doesn't need (diff between tip and LCA)
228
+ // We must do this BEFORE creating the Context so we can list them
229
+ // all in payloadAddrsDomain and payloadAddrsControl.
230
+ // const depsDomainIbGibs: IbGib_V1[] = [];
231
+ // const depsControlIbGibs: IbGib_V1[] = [];
232
+ const payloadIbGibsControl = [];
233
+ const payloadIbGibsDomain = [];
218
234
  // A. Payload (Standard Deep Deps)
219
- for (const item of nextPayloadIbGibs) {
220
- let graph = await getDependencyGraph({ ibGib: item, space: localSpace });
221
- if (!graph) {
222
- graph = await getDependencyGraph({ ibGib: item, space: tempSpace });
235
+ for (const nextDomainIbGib of nextDomainIbGibs) {
236
+ let nextDomainIbGibGraph = await getDependencyGraph({ ibGib: nextDomainIbGib, space: localSpace });
237
+ if (!nextDomainIbGibGraph) {
238
+ nextDomainIbGibGraph = await getDependencyGraph({ ibGib: nextDomainIbGib, space: tempSpace });
223
239
  }
224
- if (graph) {
225
- allDeps.push(...Object.values(graph));
240
+ if (nextDomainIbGibGraph) {
241
+ payloadIbGibsDomain.push(...Object.values(nextDomainIbGibGraph));
226
242
  }
227
243
  else {
228
- allDeps.push(item);
244
+ throw new Error(`(UNEXPECTED) we couldn't get the graph for a known domain ibgib? nextDomainIbGib addr: ${getIbGibAddr({ ibGib: nextDomainIbGib })} (E: 01b3e4db8768b5b77db72e486f4f7826)`);
229
245
  }
230
246
  }
231
247
  if (logalot) {
232
- // console.log(`${lc} allDeps count: ${allDeps.length}`);
248
+ console.log(`${lc} payloadIbGibsDomain count: ${payloadIbGibsDomain.length} (I: 2beda8ca7dc5ac0f48ed9e25e704b826)`);
233
249
  }
234
250
  // B. Frames (Shallow Sync Deps)
235
251
  if (currentFrame) {
236
- const deps = await getSyncSagaDependencyGraph({ ibGib: currentFrame, space: tempSpace });
237
- if (deps)
238
- allDeps.push(...deps);
252
+ const depsCurrentFrame = await getSyncSagaDependencyGraphForThisFrameOnly({ ibGib: currentFrame, space: tempSpace });
253
+ if (depsCurrentFrame.length > 0) {
254
+ depsCurrentFrame.forEach(x => payloadIbGibsControl.push(x));
255
+ }
256
+ else {
257
+ throw new Error(`(UNEXPECTED) couldn't get deps for currentFrame? currentFrame: ${JSON.stringify(currentFrame)} (E: 06344d07adc80d80b809211171444d26)`);
258
+ }
239
259
  }
240
260
  // 2. Create Context (Envelope)
241
- // Use the FULL dependency list as the payload manifest
242
- const payloadAddrs = allDeps.map(p => getIbGibAddr({ ibGib: p }));
261
+ const domainPayloadsMap = new Map();
262
+ const sublc = `${lc}[peer.payloadIbGibsDomainReceived$]`;
263
+ let subscription;
264
+ if (peer && peer.payloadIbGibsDomainReceived$) {
265
+ // Subscribe to stream
266
+ subscription = await peer.payloadIbGibsDomainReceived$.subscribe(fnObs({
267
+ next: async (ibgib) => {
268
+ if (logalot) {
269
+ console.log(`${sublc} next fired. (I: 2b4bdf502a38a90ba33d9711e7cb7826)`);
270
+ }
271
+ const addr = getIbGibAddr({ ibGib: ibgib });
272
+ if (logalotControlDomain) {
273
+ console.log(`${lc}${lcControlDomain} DOMAIN STREAM RECEIVED <- observable: ${addr} (I: d69ee80fcaece272483ec33b2d289826)`);
274
+ }
275
+ domainPayloadsMap.set(addr, ibgib);
276
+ },
277
+ error: async (e) => {
278
+ if (isIbGib(e)) {
279
+ console.error(`${sublc} error fired. error: ${JSON.stringify(e.data)} (E: 01cc08ba05ad99682831174fd7c31a26)`);
280
+ }
281
+ else {
282
+ console.dir(e);
283
+ console.error(`${sublc} error fired. error: ${extractErrorMsg(e)} (E: 73d3d61464e8e4ce4cd6efd8b9675826)`);
284
+ }
285
+ },
286
+ complete: async () => {
287
+ if (logalot) {
288
+ console.log(`${sublc} complete fired. (I: a47218aa9e4433fdb97c068880a45826)`);
289
+ }
290
+ await subscription.unsubscribe();
291
+ },
292
+ }));
293
+ }
294
+ // 2b. Request Context
243
295
  const requestCtx = await createSyncSagaContext({
244
- cmd: SyncSagaContextCmd.process,
245
296
  sagaFrame: currentFrame,
246
297
  sessionKeystones: sessionIdentity ? [sessionIdentity] : undefined,
247
- payloadAddrs: payloadAddrs.length > 0 ? payloadAddrs : undefined,
298
+ payloadIbGibsDomain,
248
299
  });
249
- // Add Context Deps
250
- if (requestCtx) {
251
- const deps = await getSyncSagaDependencyGraph({ ibGib: requestCtx, space: tempSpace });
252
- if (deps)
253
- allDeps.push(...deps);
300
+ // Log what we're sending
301
+ if (logalotControlDomain) {
302
+ const controlAddrs = payloadIbGibsControl.map(p => getIbGibAddr({ ibGib: p }));
303
+ const domainAddrs = payloadIbGibsDomain.map(p => getIbGibAddr({ ibGib: p }));
304
+ console.log(`${lc}${lcControlDomain} SENDER TRANSMIT -> peer.witness (I: b3c4d5e6f7a8b9c0)`);
305
+ console.log(`${lc}${lcControlDomain} Context: ${getIbGibAddr({ ibGib: requestCtx })}`);
306
+ console.log(`${lc}${lcControlDomain} Frame: ${getIbGibAddr({ ibGib: currentFrame })}`);
307
+ console.log(`${lc}${lcControlDomain} CONTROL Payloads (${controlAddrs.length}): ${controlAddrs.join(', ') || '(none)'}`);
308
+ console.log(`${lc}${lcControlDomain} DOMAIN Payloads (${domainAddrs.length}): ${domainAddrs.join(', ') || '(none)'}`);
254
309
  }
310
+ // Add Context Deps
311
+ // do we need to add requestCtx to the payload ibgibs?
312
+ // if (requestCtx) {
313
+ // const deps = await getSyncSagaDependencyGraphForThisFrameOnly({ ibGib: requestCtx, space: tempSpace });
314
+ // if (deps) { deps.forEach(x => payloadIbGibsControl.push(x)); }
315
+ // }
255
316
  // 3. Identity (if exists)
256
317
  // Identity might be deep? Keystone? Usually self-contained or shallow references.
257
318
  if (sessionIdentity) {
258
- allDeps.push(sessionIdentity);
319
+ payloadIbGibsControl.push(sessionIdentity);
259
320
  }
260
- if (allDeps.length > 0) {
261
- await putInSpace({
262
- space: localSpace,
263
- ibGibs: allDeps
264
- });
321
+ // we only put the **CONTROL** payload ibgibs in localSpace. we
322
+ // don't put any domain ibgibs into this durable space until the
323
+ // final commit phase.
324
+ // The requestCtx envelope itself also goes to localSpace so transfer can find it.
325
+ await putInSpace({ space: localSpace, ibGib: requestCtx });
326
+ if (payloadIbGibsControl.length > 0) {
327
+ await putInSpace({ space: localSpace, ibGibs: payloadIbGibsControl });
265
328
  }
266
329
  // B. Transmit
267
330
  // if (logalot) { console.log(`${lc} transmitting... requestCtx: ${pretty(requestCtx)} (I: 8cf20817c66899abdb1e76df50356826)`); }
268
- updates$.next(requestCtx);
331
+ updates$.next(requestCtx); // spins off (don't remove this comment!)
269
332
  const responseCtx = await peer.witness(requestCtx);
270
333
  // C. Handle Response
271
334
  if (!responseCtx) {
272
- // Check if we just sent a Commit frame. If so, peer's silence is success/expected.
273
335
  if (currentFrame) {
336
+ // Check for Commit (Peer silence expected)
274
337
  const msg = await getSyncSagaMessageFromFrame({ frameIbGib: currentFrame, space: localSpace });
275
- if (logalot) {
276
- console.log(`${lc} Checking currentFrame stage: ${msg?.data?.stage} (Expected: ${SyncStage.commit})`);
277
- }
278
338
  if (msg?.data?.stage === SyncStage.commit) {
279
339
  if (logalot) {
280
340
  console.log(`${lc} Sender sent Commit. Peer returned no response. Saga Complete.`);
@@ -282,57 +342,85 @@ export class SyncSagaCoordinator {
282
342
  currentFrame = null;
283
343
  break;
284
344
  }
345
+ else {
346
+ throw new Error(`(UNEXPECTED) responseCtx falsy and currentFrame truthy, but we're not in the commit stage? This may be expected ultimately, but atow I am not seeing this as being expected. (E: cc34498962bd370deeff351fac939f26)`);
347
+ }
348
+ }
349
+ else {
350
+ throw new Error(`(UNEXPECTED) no response and currentFrame falsy? (E: 8d1085ea2f28cfc3f9c922649864a826)`);
285
351
  }
286
- throw new Error(`responseCtx falsy. Peer returned no response context (E: c099d8073b48d85e881f917835158f26)`);
287
- // console.warn(`${lc} Peer returned no response context. Ending loop.`);
288
- // currentFrame = null;
289
- // break;
290
352
  }
291
- if (logalot) {
292
- console.log(`${lc} received responseCtx: ${pretty(responseCtx)} (I: 8f35c8b7a9e886aa9743d38bee907826)`);
293
- }
294
- updates$.next(responseCtx);
295
- // D. Extract Remote Frame & React
296
- const remoteFrameAddr = responseCtx.rel8ns?.sagaFrame?.[0];
297
- if (!remoteFrameAddr) {
298
- // If the remote didn't send a saga frame, we can't continue the protocol.
299
- throw new Error(`${lc} Peer response has no sagaFrame. Ending loop. (E: 0224e84a83e1c7ee288aaed6bdc40826)`);
300
- }
301
- // We look in localSpace first (where Peer delivers), then tempSpace.
302
- let resRemoteFrame = await getFromSpace({ addr: remoteFrameAddr, space: localSpace });
303
- if (!resRemoteFrame.success || !resRemoteFrame.ibGibs?.length) {
304
- // Fallback to tempSpace just in case
305
- resRemoteFrame = await getFromSpace({ addr: remoteFrameAddr, space: tempSpace });
306
- }
307
- const remoteFrame = resRemoteFrame.ibGibs?.[0];
308
- if (!remoteFrame) {
309
- throw new Error(`Could not resolve remote frame: ${remoteFrameAddr}`);
310
- }
311
- // if (logalot) { console.log(`${lc} remoteFrame: ${pretty(remoteFrame)}`); } // leave this in for later use if needed
312
- // Ensure remote frame and its dependencies are in tempSpace
313
- // The Peer delivered them to localSpace, but handleSagaFrame works in tempSpace.
314
- const remoteDeps = await getSyncSagaDependencyGraph({ ibGib: remoteFrame, space: localSpace });
315
- if (remoteDeps && remoteDeps.length > 0) {
316
- await putInSpace({ space: tempSpace, ibGibs: remoteDeps });
317
- }
318
- // React (Reducer)
319
- // This processes the FRAME we just got from the peer.
320
- // i.e., We Sent Init -> Got Ack. This calls handleAckFrame.
321
- // i.e., We Sent Delta -> Got Delta. This calls handleDeltaFrame.
322
- const result = await this.handleSagaFrame({
323
- sagaIbGib: remoteFrame,
324
- srcGraph,
325
- destSpace: localSpace, // Query existing data from localSpace (Source)
326
- tempSpace: tempSpace, // Transaction space for saga frames
327
- identity: sessionIdentity,
328
- metaspace
329
- });
330
- currentFrame = result?.frame || null;
331
- nextPayloadIbGibs = result?.payloadIbGibs || []; // Payload to send in NEXT Ping
332
- if (result?.receivedPayloadIbGibs) {
333
- // Keep track of what we received for final merge
334
- allReceivedIbGibs.push(...result.receivedPayloadIbGibs);
353
+ // ---------------------------------------------------------------------
354
+ // 2d. HANDLE RESPONSE
355
+ // ---------------------------------------------------------------------
356
+ if (!responseCtx.data) {
357
+ throw new Error(`(UNEXPECTED) responseCtx.data falsy? (E: a969992bae53ab18a827ec58aec15826)`);
358
+ }
359
+ updates$.next(responseCtx); // spins off -- don't remove this comment!
360
+ // Extract expected domain addresses from response context
361
+ const responsePayloadAddrsDomain = responseCtx.data[SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN] || [];
362
+ // TODO: check if we are validating the responseCtx in sync peer. I'm thinking that we must, because we can't start the domain ibgibs until we know the response's control ibgibs are valid.
363
+ // Poll for them if needed
364
+ if (responsePayloadAddrsDomain.length > 0) {
365
+ await this.pollForDomainPayloads({
366
+ expectedAddrs: responsePayloadAddrsDomain,
367
+ domainPayloadsMap,
368
+ tempSpace,
369
+ });
335
370
  }
371
+ // Extract Response Frame
372
+ const responseFrameAddr = responseCtx.rel8ns?.sagaFrame?.[0];
373
+ if (!responseFrameAddr) {
374
+ throw new Error(`${lc} Peer response missing sagaFrame (E: 83a0)`);
375
+ }
376
+ // Log what we received back
377
+ if (logalotControlDomain) {
378
+ const responseControlAddrs = responseCtx.data?.['@payloadAddrsControl'] || [];
379
+ console.log(`${lc}${lcControlDomain} SENDER RECEIVED <- peer.witness (I: c4d5e6f7a8b9c0d1)`);
380
+ console.log(`${lc}${lcControlDomain} Response Context: ${getIbGibAddr({ ibGib: responseCtx })}`);
381
+ console.log(`${lc}${lcControlDomain} Response Frame: ${responseFrameAddr}`);
382
+ console.log(`${lc}${lcControlDomain} CONTROL Payloads (${responseControlAddrs.length}): ${responseControlAddrs.join(', ') || '(none)'}`);
383
+ console.log(`${lc}${lcControlDomain} DOMAIN Payloads (${responsePayloadAddrsDomain.length}): ${responsePayloadAddrsDomain.join(', ') || '(none)'}`);
384
+ }
385
+ // Get response frame from localSpace (SyncPeer puts it there)
386
+ let resResponseFrame = await getFromSpace({ space: localSpace, addr: responseFrameAddr });
387
+ if (!resResponseFrame.success || !resResponseFrame.ibGibs?.length) {
388
+ // Fallback to tempSpace
389
+ resResponseFrame = await getFromSpace({ space: tempSpace, addr: responseFrameAddr });
390
+ }
391
+ const responseFrame = resResponseFrame.ibGibs?.[0];
392
+ if (!responseFrame)
393
+ throw new Error(`${lc} Response frame not found (E: 7c2a)`);
394
+ // Handle Response Frame
395
+ const handleResult = await this.handleSagaFrame({
396
+ sagaIbGib: responseFrame,
397
+ srcGraph: {},
398
+ destSpace: localSpace,
399
+ tempSpace,
400
+ metaspace,
401
+ domainPayloadsMap,
402
+ expectedDomainAddrs: responsePayloadAddrsDomain,
403
+ });
404
+ if (!handleResult) {
405
+ if (logalot) {
406
+ console.log(`${lc} Handler returned null (Saga End).`);
407
+ }
408
+ break;
409
+ }
410
+ currentFrame = handleResult.frame;
411
+ // Collect next DOMAIN payloads for the NEXT request
412
+ // Control payloads are handled separately by ensureSagaFrameInBothSpaces
413
+ nextDomainIbGibs = [...(handleResult.payloadIbGibsDomain || [])];
414
+ // Log handler output for next iteration
415
+ if (logalotControlDomain) {
416
+ const handlerControlAddrs = (handleResult.payloadIbGibsControl || []).map(p => getIbGibAddr({ ibGib: p }));
417
+ const handlerDomainAddrs = nextDomainIbGibs.map(p => getIbGibAddr({ ibGib: p }));
418
+ console.log(`${lc}${lcControlDomain} HANDLER RESULT -> next iteration (I: d5e6f7a8b9c0d1e2)`);
419
+ console.log(`${lc}${lcControlDomain} Next Frame: ${getIbGibAddr({ ibGib: currentFrame })}`);
420
+ console.log(`${lc}${lcControlDomain} CONTROL for next (${handlerControlAddrs.length}): ${handlerControlAddrs.join(', ') || '(none)'} (saved via ensureSagaFrameInBothSpaces)`);
421
+ console.log(`${lc}${lcControlDomain} DOMAIN for next (${handlerDomainAddrs.length}): ${handlerDomainAddrs.join(', ') || '(none)'}`);
422
+ }
423
+ // Note: currentFrame is automatically added to dependencies at start of next loop via B. Frames logic.
336
424
  }
337
425
  return allReceivedIbGibs;
338
426
  }
@@ -346,7 +434,7 @@ export class SyncSagaCoordinator {
346
434
  if (logalot) {
347
435
  console.log(`${lc} starting... (I: e184f8a7818666febfbbd2d841ed3826)`);
348
436
  }
349
- console.dir(space);
437
+ // console.dir(space);
350
438
  if (!(domainIbGibs && domainIbGibs.length > 0) &&
351
439
  !(tjpAddrs && tjpAddrs.length > 0)) {
352
440
  throw new Error(`(UNEXPECTED) domainIbGibs and tjpAddrs falsy/empty? we need one or the other (E: f674285111c8648398cd79d8c08ec826)`);
@@ -361,23 +449,21 @@ export class SyncSagaCoordinator {
361
449
  }
362
450
  else if (domainIbGibs && domainIbGibs.length > 0) {
363
451
  // Extract TJPs from domain Ibgibs
364
- if (logalot) {
365
- console.log(`${lc} domainIbGibs (${domainIbGibs.length}) provided. (I: a378995a0658af1f086ac1f297486c26)`);
366
- }
452
+ // if (false) { console.log(`${lc} domainIbGibs (${domainIbGibs.length}) provided. (I: a378995a0658af1f086ac1f297486c26)`); }
367
453
  const { mapWithTjp_YesDna, mapWithTjp_NoDna } = splitPerTjpAndOrDna({ ibGibs: domainIbGibs });
368
- if (logalot) {
454
+ if (false) {
369
455
  console.log(`${lc}[TEST DEBUG] mapWithTjp_YesDna: ${JSON.stringify(mapWithTjp_YesDna)} (I: 287e22897148298e185712c8d50cfb26)`);
370
456
  }
371
- if (logalot) {
457
+ if (false) {
372
458
  console.log(`${lc}[TEST DEBUG] mapWithTjp_NoDna: ${JSON.stringify(mapWithTjp_NoDna)} (I: 1bdc62656294aed0f9df334647dc7326)`);
373
459
  }
374
460
  const allWithTjp = [...Object.values(mapWithTjp_YesDna), ...Object.values(mapWithTjp_NoDna)];
375
461
  const timelineMap = getTimelinesGroupedByTjp({ ibGibs: allWithTjp });
376
- if (logalot) {
462
+ if (false) {
377
463
  console.log(`${lc}[TEST DEBUG] timelineMap: ${JSON.stringify(timelineMap)} (I: 2cc04898e5f85179fb1ac7f827abc426)`);
378
464
  }
379
465
  tjps = Object.keys(timelineMap);
380
- if (logalot) {
466
+ if (false) {
381
467
  console.log(`${lc}[TEST DEBUG] tjps: ${tjps} (I: 3dd548667cbd967c68e57c88dc570826)`);
382
468
  }
383
469
  }
@@ -390,16 +476,14 @@ export class SyncSagaCoordinator {
390
476
  if (tjps.length === 0) {
391
477
  return {};
392
478
  }
393
- if (logalot) {
479
+ if (false) {
394
480
  console.log(`${lc} getting latest addrs for tjps: ${tjps} (I: d4e7080b8ba8187c583b82fd91ac0626)`);
395
481
  }
396
482
  const res = await getLatestAddrs({ space, tjpAddrs: tjps });
397
483
  if (!res.data || !res.data.latestAddrsMap) {
398
484
  throw new Error(`${lc} Failed to get latest addrs. (E: 7a8b9c0d)`);
399
485
  }
400
- if (logalot) {
401
- console.log(`${lc}[TEST DEBUG] res.data.latestAddrsMap: ${JSON.stringify(res.data.latestAddrsMap)} (I: a8e128bdf80898ac2e6d8021a5bff726)`);
402
- }
486
+ // if (false) { console.log(`${lc}[TEST DEBUG] res.data.latestAddrsMap: ${JSON.stringify(res.data.latestAddrsMap)} (I: a8e128bdf80898ac2e6d8021a5bff726)`); }
403
487
  return res.data.latestAddrsMap;
404
488
  }
405
489
  catch (error) {
@@ -503,18 +587,55 @@ export class SyncSagaCoordinator {
503
587
  }
504
588
  }
505
589
  /**
506
- * Reacts to an incoming saga frame and dispatches to appropriate handler.
507
- *
508
- * @remarks
509
- * **Execution Context**: **Universal (Both Sender and Receiver)**.
510
- *
511
- * This method acts as the "Reducer" for the Sync FSM. It determines the current stage
512
- * based on the incoming frame and delegates to the appropriate handler.
513
- *
514
- * * If running on **Receiver**: Handles `Init` (via `handleInitFrame`).
515
- * * If running on **Sender**: Handles `Ack` (via `handleAckFrame`).
516
- * * If running on **Either**: Handles `Delta` (via `handleDeltaFrame`) or `Commit`.
590
+ * Helper to poll for streaming domain payloads and put them in the
591
+ * local {@link tempSpace}.
517
592
  */
593
+ async pollForDomainPayloads({ expectedAddrs, domainPayloadsMap, tempSpace, }) {
594
+ const lc = `${this.lc}[${this.pollForDomainPayloads.name}]`;
595
+ try {
596
+ if (logalot) {
597
+ console.log(`${lc} starting... (I: 26dce86bfca572939885798802d6e926)`);
598
+ }
599
+ let pending = [...expectedAddrs];
600
+ const start = Date.now();
601
+ /**
602
+ * This needs
603
+ */
604
+ const timeoutMs = 5 * 60 * 1000; // 5 minutes...arbitrary at this point. This needs to be pulled out and improved eesh.
605
+ while (pending.length > 0) {
606
+ if (Date.now() - start > timeoutMs) {
607
+ throw new Error(`Timeout waiting for payloads: ${pending.join(', ')} (E: 46e1683c9578095261aaf798bd5e1826)`);
608
+ }
609
+ const stillPending = [];
610
+ const found = [];
611
+ for (const addr of pending) {
612
+ if (domainPayloadsMap.has(addr)) {
613
+ found.push(domainPayloadsMap.get(addr));
614
+ domainPayloadsMap.delete(addr);
615
+ }
616
+ else {
617
+ stillPending.push(addr);
618
+ }
619
+ }
620
+ if (found.length > 0) {
621
+ await putInSpace({ space: tempSpace, ibGibs: found });
622
+ }
623
+ pending = stillPending;
624
+ if (pending.length > 0) {
625
+ await new Promise(resolve => setTimeout(resolve, 50));
626
+ }
627
+ }
628
+ }
629
+ catch (error) {
630
+ console.error(`${lc} ${extractErrorMsg(error)}`);
631
+ throw error;
632
+ }
633
+ finally {
634
+ if (logalot) {
635
+ console.log(`${lc} complete.`);
636
+ }
637
+ }
638
+ }
518
639
  async handleSagaFrame({ sagaIbGib, srcGraph, destSpace, tempSpace, identity, identitySecret, metaspace, }) {
519
640
  const lc = `${this.lc}[${this.handleSagaFrame.name}]`;
520
641
  try {
@@ -838,7 +959,12 @@ export class SyncSagaCoordinator {
838
959
  // IMMEDIATELY persist to both spaces for audit trail (before any errors can occur)
839
960
  await this.ensureSagaFrameInBothSpaces({ frame: ackFrame, destSpace, tempSpace, metaspace });
840
961
  // if (logalot) { console.log(`${lc} ackFrame created: ${pretty(ackFrame)} (I: be24480592eec478086bb3da49286826)`); }
841
- return { frame: ackFrame };
962
+ // Build control payloads: frame + its dependencies (msg stone, identity)
963
+ const payloadIbGibsControl = [ackFrame, ackStone];
964
+ if (identity) {
965
+ payloadIbGibsControl.push(identity);
966
+ }
967
+ return { frame: ackFrame, payloadIbGibsControl };
842
968
  }
843
969
  /**
844
970
  * Handles the `Ack` frame.
@@ -938,50 +1064,7 @@ export class SyncSagaCoordinator {
938
1064
  // PULL these frames from Peer into Local Space
939
1065
  // (Validation: We trust peer for now / verification happens on put)
940
1066
  for (const addr of receiverOnlyAddrs) {
941
- // This 'pull' is a sync-peer method?
942
- // The Coordinator 'peer' passed in 'sync()' might be needed here?
943
- // Wait, `handleAckFrame` doesn't have reference to `peer`?
944
- // It only has `space`, `metaspace`.
945
- // The `peer` is held by the `executeSagaLoop`.
946
- // PROBLEM: `handleAckFrame` is pure logic on the Space/Data?
947
- // No, it's a method on Coordinator.
948
- // But `executeSagaLoop` calls it.
949
- // We might need to return "Requirements" to the loop?
950
- // Checking return type: `{ frame: SyncIbGib_V1, payloadIbGibs?: ... }`
951
- // It returns the NEXT frame (Delta).
952
- // If we need to fetch data, we are blocked.
953
- // We can't easily "Pull" here without the Peer reference.
954
- // OPTION A: Pass `peer` to `handleAckFrame`.
955
- // OPTION B: Return a strict list of "MissingDeps" and let Loop handle it.
956
- // Let's assume we can resolve this by adding `peer` to signature or using `metaspace` if it's a peer-witness?
957
- // No, Peer is ephemeral connection.
958
- // Let's add `peer` to `handleAckFrame` signature?
959
- // It breaks the pattern of just handling frame + space.
960
- // ALTERNATIVE: Use the `Delta` frame to request data?
961
- // `SyncSagaMessageDeltaData` has `requests?: string[]`.
962
- // Sender sends Delta Frame.
963
- // Does Receiver handle Delta Requests?
964
- // `handleDeltaFrame` (Receiver) -> checks `requests`.
965
- // YES.
966
- // So Sender puts `receiverOnlyAddrs` into `deltaFrame.requests`.
967
- // Receiver sees them, fetches them, and includes them in the Response (Commit?).
968
- // Wait, Init->Ack->Delta->Commit.
969
- // If Receiver sends data in Commit, that's "too late" for Sender to Merge in THIS saga round?
970
- // Unless Commit is not the end?
971
- // Or we do a "Delta 2" loop?
972
- // "Iterative Resolution Loop" from plan.
973
- // If we request data in Delta, Receiver sends it in Commit (or Delta-Response).
974
- // Sender gets Commit. Sees data. Merges.
975
- // Then Sender needs to Send the MERGE result.
976
- // Needs another Push/Delta.
977
- // REFINED FLOW:
978
- // 1. Sender sends Delta Frame with `requests: [receiverOnlyAddrs]`.
979
- // 2. Receiver responds (Commit? or Ack 2?) with Payload (Divergent Frames).
980
- // 3. Sender handles response -> Merges.
981
- // 4. Sender sends Commit (containing Merge Frame).
982
- // Issue: Current state machine is Init->Ack->Delta->Commit.
983
- // We need to keep Saga open.
984
- // If Sender sends Delta with requests, does it transition to Commit?
1067
+ console.error(`${lc} [CONFLICT DEBUG] NOT IMPLEMENTED (E: e6bf1a9d2758c469bb2f97514062d826)`);
985
1068
  }
986
1069
  // Compute DELTA dependencies for each receiver-only frame
987
1070
  // Find LCA to determine what dependencies we already have
@@ -1153,7 +1236,12 @@ export class SyncSagaCoordinator {
1153
1236
  if (logalot) {
1154
1237
  console.log(`${lc} Delta Frame created. Rel8ns: ${JSON.stringify(deltaFrame.rel8ns)}`);
1155
1238
  }
1156
- return { frame: deltaFrame, payloadIbGibs };
1239
+ // Build control payloads: frame + its dependencies (msg stone, identity)
1240
+ const payloadIbGibsControl = [deltaFrame, deltaStone];
1241
+ if (identity) {
1242
+ payloadIbGibsControl.push(identity);
1243
+ }
1244
+ return { frame: deltaFrame, payloadIbGibsControl, payloadIbGibsDomain: payloadIbGibs };
1157
1245
  }
1158
1246
  catch (error) {
1159
1247
  console.error(`${lc} ${extractErrorMsg(error)}`);
@@ -1378,7 +1466,12 @@ export class SyncSagaCoordinator {
1378
1466
  });
1379
1467
  // IMMEDIATELY persist to both spaces for audit trail
1380
1468
  await this.ensureSagaFrameInBothSpaces({ frame: deltaFrame, destSpace, tempSpace, metaspace });
1381
- return { frame: deltaFrame, payloadIbGibs: outgoingPayload, receivedPayloadIbGibs };
1469
+ // Build control payloads: frame + its dependencies (msg stone, identity)
1470
+ const payloadIbGibsControl = [deltaFrame, deltaStone];
1471
+ if (identity) {
1472
+ payloadIbGibsControl.push(identity);
1473
+ }
1474
+ return { frame: deltaFrame, payloadIbGibsControl, payloadIbGibsDomain: outgoingPayload };
1382
1475
  }
1383
1476
  else {
1384
1477
  // We have nothing to send.
@@ -1403,7 +1496,12 @@ export class SyncSagaCoordinator {
1403
1496
  });
1404
1497
  // IMMEDIATELY persist to both spaces for audit trail
1405
1498
  await this.ensureSagaFrameInBothSpaces({ frame: commitFrame, destSpace, tempSpace, metaspace });
1406
- return { frame: commitFrame, receivedPayloadIbGibs };
1499
+ // Build control payloads for commit
1500
+ const commitCtrlPayloads = [commitFrame, commitStone];
1501
+ if (identity) {
1502
+ commitCtrlPayloads.push(identity);
1503
+ }
1504
+ return { frame: commitFrame, payloadIbGibsControl: commitCtrlPayloads };
1407
1505
  }
1408
1506
  else {
1409
1507
  // peer did NOT propose commit (maybe they just sent data/requests and didn't ready flag).
@@ -1455,9 +1553,19 @@ export class SyncSagaCoordinator {
1455
1553
  });
1456
1554
  // IMMEDIATELY persist to both spaces for audit trail
1457
1555
  await this.ensureSagaFrameInBothSpaces({ frame: commitFrame, destSpace, tempSpace, metaspace });
1458
- return { frame: commitFrame, receivedPayloadIbGibs };
1556
+ // Build control payloads for commit
1557
+ const commitCtrlPayloads2 = [commitFrame, commitStone];
1558
+ if (identity) {
1559
+ commitCtrlPayloads2.push(identity);
1560
+ }
1561
+ return { frame: commitFrame, payloadIbGibsControl: commitCtrlPayloads2 };
1562
+ }
1563
+ // Build control payloads for delta propose
1564
+ const deltaCtrlPayloads = [deltaFrame, deltaStone];
1565
+ if (identity) {
1566
+ deltaCtrlPayloads.push(identity);
1459
1567
  }
1460
- return { frame: deltaFrame, receivedPayloadIbGibs };
1568
+ return { frame: deltaFrame, payloadIbGibsControl: deltaCtrlPayloads };
1461
1569
  }
1462
1570
  }
1463
1571
  }