@ibgib/core-gib 0.1.25 → 0.1.26

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 (38) hide show
  1. package/dist/common/other/ibgib-helper.d.mts +1 -1
  2. package/dist/common/other/ibgib-helper.d.mts.map +1 -1
  3. package/dist/common/other/ibgib-helper.mjs.map +1 -1
  4. package/dist/sync/sync-constants.d.mts +1 -0
  5. package/dist/sync/sync-constants.d.mts.map +1 -1
  6. package/dist/sync/sync-constants.mjs +1 -0
  7. package/dist/sync/sync-constants.mjs.map +1 -1
  8. package/dist/sync/sync-helpers.d.mts +5 -0
  9. package/dist/sync/sync-helpers.d.mts.map +1 -1
  10. package/dist/sync/sync-helpers.mjs +37 -1
  11. package/dist/sync/sync-helpers.mjs.map +1 -1
  12. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts +0 -2
  13. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts.map +1 -1
  14. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs +148 -62
  15. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs.map +1 -1
  16. package/dist/sync/sync-peer/sync-peer-v1.d.mts +13 -29
  17. package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
  18. package/dist/sync/sync-peer/sync-peer-v1.mjs +17 -57
  19. package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
  20. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts +15 -1
  21. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts.map +1 -1
  22. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs +60 -4
  23. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs.map +1 -1
  24. package/dist/sync/sync-saga-coordinator.d.mts +49 -3
  25. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  26. package/dist/sync/sync-saga-coordinator.mjs +180 -101
  27. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  28. package/dist/sync/sync-types.d.mts +1 -3
  29. package/dist/sync/sync-types.d.mts.map +1 -1
  30. package/package.json +1 -1
  31. package/src/common/other/ibgib-helper.mts +1 -1
  32. package/src/sync/sync-constants.mts +1 -0
  33. package/src/sync/sync-helpers.mts +41 -1
  34. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +147 -47
  35. package/src/sync/sync-peer/sync-peer-v1.mts +31 -74
  36. package/src/sync/sync-saga-context/sync-saga-context-helpers.mts +55 -7
  37. package/src/sync/sync-saga-coordinator.mts +232 -110
  38. package/src/sync/sync-types.mts +2 -2
@@ -142,6 +142,75 @@ export class SyncSagaCoordinator {
142
142
  done
143
143
  };
144
144
  }
145
+ /**
146
+ * This is what the receiving side of the sync calls to drive the FSM to the
147
+ * next stage.
148
+ *
149
+ * So whereas the sender executes a saga loop and drives the entire process,
150
+ * this is a reactive one-off that drives just the single step that the
151
+ * receiver does in that saga.
152
+ *
153
+ * @returns next context result if another round, else if commit returns
154
+ * null
155
+ */
156
+ async receiverContinueSync({ sagaContext, mySpace, myTempSpace, identity, identitySecret, metaspace, }) {
157
+ const lc = `${this.lc}[${this.receiverContinueSync.name}]`;
158
+ try {
159
+ if (logalot) {
160
+ console.log(`${lc} starting... (I: f64e08bf77d1425378601f380384ec26)`);
161
+ }
162
+ const contextResult = await this.handleResponseSagaContext({
163
+ sagaContext,
164
+ mySpace,
165
+ myTempSpace,
166
+ identity,
167
+ identitySecret,
168
+ metaspace,
169
+ });
170
+ if (!contextResult) {
171
+ if (logalot) {
172
+ console.log(`${lc} Handler returned null (Saga End). (I: 43da8bb6c846b1fe7766332643be0e26)`);
173
+ }
174
+ return null;
175
+ }
176
+ // #region error conditions throw
177
+ if (contextResult.errorMsg) {
178
+ throw new Error(`Couldn't handle response saga context. errorMsg: ${contextResult.errorMsg} (E: 7b41a183cf3cb58a5859c803800cf826)`);
179
+ }
180
+ else if (!contextResult.nextFrameInfo) {
181
+ throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo falsy? (E: 5740542f5eb8ccb41dfec188d87c1e26)`);
182
+ }
183
+ else if (contextResult.nextFrameInfo?.responseWasNull) {
184
+ throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo.responseWasNull? logic flow should not have gotten here. (E: ae06748d8c0c5e70c92322c8fb0cb426)`);
185
+ }
186
+ // #endregion error conditions throw
187
+ // create the return context
188
+ const { frame, payloadIbGibsDomain } = contextResult.nextFrameInfo;
189
+ const responseCtx = await createSyncSagaContext({
190
+ sagaFrame: frame,
191
+ localSpace: mySpace,
192
+ payloadIbGibsDomain,
193
+ // todo: we need to thoroughly go through the identity per each step after getting basic merging
194
+ sessionKeystones: identity ? [identity] : undefined, // ??
195
+ });
196
+ const immediateValidationErrors = await validateContextAndSagaFrame({
197
+ context: responseCtx,
198
+ });
199
+ if (immediateValidationErrors.length > 0) {
200
+ throw new Error(`(UNEXPECTED) just created sync saga context () and there were immediateValidationErrors? immediateValidationErrors: ${immediateValidationErrors} (E: c120e8e0aa98673d685267a8a36e5826)`);
201
+ }
202
+ return responseCtx;
203
+ }
204
+ catch (error) {
205
+ console.error(`${lc} ${extractErrorMsg(error)}`);
206
+ throw error;
207
+ }
208
+ finally {
209
+ if (logalot) {
210
+ console.log(`${lc} complete.`);
211
+ }
212
+ }
213
+ }
145
214
  async getSessionIdentity({ sagaId, metaspace, tempSpace, }) {
146
215
  const lc = `${this.lc}[${this.getSessionIdentity.name}]`;
147
216
  try {
@@ -292,8 +361,12 @@ export class SyncSagaCoordinator {
292
361
  throw new Error(`(UNEXPECTED) responseCtx.data falsy? (E: a969992bae53ab18a827ec58aec15826)`);
293
362
  }
294
363
  updates$.next(responseCtx); // spins off for saga UI updating
295
- // validate context
296
- await validateContextAndSagaFrame;
364
+ // immediately validate context/saga frame (but not payloads because
365
+ // we may not have those yet)
366
+ const contextAndSagaFrameValidationErrors = await validateContextAndSagaFrame({ context: responseCtx });
367
+ if (contextAndSagaFrameValidationErrors.length > 0) {
368
+ throw new Error(`contextAndSagaFrameValidationErrors: ${contextAndSagaFrameValidationErrors} (E: 6eebe8e7fa437c00a8cde3ada3c66826)`);
369
+ }
297
370
  // Extract expected domain addresses from response context
298
371
  const responsePayloadAddrsDomain = responseCtx.data[SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN] || [];
299
372
  // Poll for them if needed. see above jsdocs for domainPayloadsMap
@@ -326,6 +399,7 @@ export class SyncSagaCoordinator {
326
399
  // finished/errored out.
327
400
  const contextResult = await this.handleResponseSagaContext({
328
401
  sagaContext: responseCtx,
402
+ initDomainGraph,
329
403
  mySpace: localSpace,
330
404
  myTempSpace: tempSpace,
331
405
  metaspace,
@@ -584,6 +658,7 @@ export class SyncSagaCoordinator {
584
658
  }
585
659
  /**
586
660
  * This is the heart of the "ping pong" transaction, where we send a context
661
+ *
587
662
  * and receive a context. IOW, this drives the FSM of the sync saga ibgib as
588
663
  * a whole.
589
664
  *
@@ -602,7 +677,7 @@ export class SyncSagaCoordinator {
602
677
  *
603
678
  * This is a one-off on the receiver.
604
679
  */
605
- async handleResponseSagaContext({ sagaContext, mySpace, myTempSpace, identity, identitySecret, metaspace, }) {
680
+ async handleResponseSagaContext({ sagaContext, initDomainGraph, mySpace, myTempSpace, identity, identitySecret, metaspace, }) {
606
681
  const lc = `${this.lc}[${this.handleResponseSagaContext.name}]`;
607
682
  try {
608
683
  if (logalot) {
@@ -638,7 +713,18 @@ export class SyncSagaCoordinator {
638
713
  });
639
714
  break;
640
715
  case SyncStage.ack:
641
- nextFrameInfo = await this.handleAckFrame({ sagaIbGib, srcGraph, metaspace, destSpace: mySpace, tempSpace: myTempSpace, identity });
716
+ if (!initDomainGraph) {
717
+ throw new Error(`(UNEXPECTED) initDomainGraph falsy on the sender? (E: a3d758ad954829aba88663188eafc826)`);
718
+ }
719
+ nextFrameInfo = await this.handleAckFrame({
720
+ sagaIbGib,
721
+ srcGraph,
722
+ initDomainGraph,
723
+ metaspace,
724
+ destSpace: mySpace,
725
+ tempSpace: myTempSpace,
726
+ identity,
727
+ });
642
728
  break;
643
729
  case SyncStage.delta:
644
730
  nextFrameInfo = await this.handleDeltaFrame({ sagaIbGib, srcGraph, metaspace, destSpace: mySpace, tempSpace: myTempSpace, identity, });
@@ -928,7 +1014,6 @@ export class SyncSagaCoordinator {
928
1014
  * we want to push ibgibs to the remote/sender if we have push
929
1015
  * offers. an ack frame's payloads, if any, are those push offers
930
1016
  */
931
- // let payloadIbGibsDomain: IbGib_V1[] | undefined = await getPushOffers
932
1017
  let payloadIbGibsDomain;
933
1018
  if (pushOfferInfos.length > 0) {
934
1019
  const searchSecondSpaceAddrs = [];
@@ -985,12 +1070,10 @@ export class SyncSagaCoordinator {
985
1070
  }
986
1071
  // we have now populated payloadIbGibsDomain
987
1072
  }
988
- throw new Error(`not implemented (E: ed3f98abb0988c5ae8038bb8d741fb26)`);
989
- // return {
990
- // frame: ackFrame,
991
- // // conflictInfos,
992
- // payloadIbGibsDomain,
993
- // };
1073
+ return {
1074
+ frame: ackFrame,
1075
+ payloadIbGibsDomain,
1076
+ };
994
1077
  }
995
1078
  catch (error) {
996
1079
  console.error(`${lc} ${extractErrorMsg(error)}`);
@@ -1014,7 +1097,7 @@ export class SyncSagaCoordinator {
1014
1097
  *
1015
1098
  * Returns a `Delta` frame.
1016
1099
  */
1017
- async handleAckFrame({ sagaIbGib, srcGraph, destSpace, tempSpace, metaspace, identity, }) {
1100
+ async handleAckFrame({ sagaIbGib, srcGraph, initDomainGraph, destSpace, tempSpace, metaspace, identity, }) {
1018
1101
  const lc = `${this.lc}[${this.handleAckFrame.name}]`;
1019
1102
  try {
1020
1103
  if (logalot) {
@@ -1044,10 +1127,10 @@ export class SyncSagaCoordinator {
1044
1127
  // For now, throw to trigger abort.
1045
1128
  throw new Error(`${lc} Peer reported terminal conflicts. (E: 23a0096ee05a2ccfa89334e8f156b426)`);
1046
1129
  }
1047
- const optimisticConflicts = conflicts.filter(c => !c.terminal);
1130
+ // at this point, if we have conflicts, they are non-terminal
1048
1131
  const mergeDeltaReqs = []; // Additional requests for merging
1049
- if (optimisticConflicts.length > 0) {
1050
- console.log(`${lc} [CONFLICT DEBUG] Processing ${optimisticConflicts.length} optimistic conflicts`);
1132
+ if (conflicts.length > 0) {
1133
+ console.log(`${lc} [CONFLICT DEBUG] Processing ${conflicts.length} non-terminal conflicts`);
1051
1134
  // We need to resolve these.
1052
1135
  // Strategy:
1053
1136
  // 1. Analyze Divergence (Sender vs Receiver)
@@ -1073,93 +1156,89 @@ export class SyncSagaCoordinator {
1073
1156
  // `peer.pull(addr)`?
1074
1157
  // Yes! The Coordinator has the `peer`.
1075
1158
  // Let's analyze and pull immediately.
1076
- for (const conflict of optimisticConflicts) {
1077
- const { timelineAddrs, localAddr: receiverTip, remoteAddr: senderTip } = conflict;
1078
- // Sender History
1079
- // We need our own history for this timeline.
1080
- // We know the 'senderTip' (remoteAddr in Ack).
1081
- // Sender should verify it has this tip.
1082
- // Compute Diffs
1083
- // We need to find `receiverOnly` addrs.
1084
- // Receiver sent us `timelineAddrs` (Full History).
1085
- const receiverHistorySet = new Set(timelineAddrs);
1086
- // We need our execution context's history for this senderTip.
1087
- // We can fetch valid 'past' from space.
1088
- const resSenderTip = await getFromSpace({ space: destSpace, addr: senderTip });
1089
- const senderTipIbGib = resSenderTip.ibGibs?.[0];
1090
- if (!senderTipIbGib) {
1091
- throw new Error(`${lc} Sender missing its own tip? ${senderTip} (E: 832f3804645878869ee3c13714366726)`);
1092
- }
1093
- // Basic Diff: Find what Receiver has that we don't.
1094
- // Actually, we need to traverse OUR past to find commonality.
1095
- const senderHistory = [senderTip, ...(senderTipIbGib.rel8ns?.past || [])];
1096
- const receiverOnlyAddrs = timelineAddrs.filter(addr => !senderHistory.includes(addr));
1097
- if (receiverOnlyAddrs.length > 0) {
1098
- console.log(`${lc} [CONFLICT DEBUG] Found ${receiverOnlyAddrs.length} receiver-only frames - need to pull for merge`);
1099
- console.log(`${lc} [CONFLICT DEBUG] Receiver-only addrs:`, receiverOnlyAddrs);
1100
- // PULL these frames from Peer into Local Space
1101
- // (Validation: We trust peer for now / verification happens on put)
1102
- for (const addr of receiverOnlyAddrs) {
1103
- console.error(`${lc} [CONFLICT DEBUG] NOT IMPLEMENTED (E: e6bf1a9d2758c469bb2f97514062d826)`);
1104
- }
1105
- // Compute DELTA dependencies for each receiver-only frame
1106
- // Find LCA to determine what dependencies we already have
1107
- const lcaAddr = timelineAddrs.find(addr => senderHistory.includes(addr));
1108
- console.log(`${lc} [CONFLICT DEBUG] LCA: ${lcaAddr || 'NONE'}`);
1109
- const skipAddrsSet = new Set();
1110
- if (lcaAddr) {
1111
- try {
1112
- const lcaRes = await getFromSpace({ addr: lcaAddr, space: destSpace });
1113
- const lcaIbGib = lcaRes.ibGibs?.[0];
1114
- if (lcaIbGib) {
1115
- const lcaDeps = await getDependencyGraph({ ibGib: lcaIbGib, space: destSpace });
1116
- if (lcaDeps)
1117
- Object.keys(lcaDeps).forEach(a => skipAddrsSet.add(a));
1118
- console.log(`${lc} [CONFLICT DEBUG] LCA deps to skip: ${skipAddrsSet.size}`);
1119
- }
1120
- }
1121
- catch (e) {
1122
- console.warn(`${lc} Error getting LCA deps: ${extractErrorMsg(e)}`);
1123
- }
1124
- }
1125
- // For each receiver-only frame, get its DELTA dependency graph (minus LCA deps)
1126
- for (const addr of receiverOnlyAddrs) {
1127
- // Add the frame itself first
1128
- if (!mergeDeltaReqs.includes(addr)) {
1129
- mergeDeltaReqs.push(addr);
1130
- }
1131
- // Get the frame's delta dependencies (skip LCA's deps)
1132
- try {
1133
- const frameRes = await getFromSpace({ addr, space: destSpace });
1134
- const frameIbGib = frameRes.ibGibs?.[0];
1135
- if (frameIbGib) {
1136
- // Get dependency graph, skipping all LCA dependencies
1137
- const frameDeltaDeps = await getDependencyGraph({
1138
- ibGib: frameIbGib,
1139
- space: destSpace,
1140
- skipAddrs: Array.from(skipAddrsSet), // Skip entire LCA dep graph
1141
- });
1142
- if (frameDeltaDeps) {
1143
- // Add all delta dependencies (Object.keys gives us the addresses)
1144
- Object.keys(frameDeltaDeps).forEach(depAddr => {
1145
- if (!mergeDeltaReqs.includes(depAddr) && !skipAddrsSet.has(depAddr)) {
1146
- mergeDeltaReqs.push(depAddr);
1147
- }
1148
- });
1149
- }
1150
- }
1151
- }
1152
- catch (depError) {
1153
- console.warn(`${lc} [CONFLICT DEBUG] Error getting delta deps for ${addr}: ${extractErrorMsg(depError)}`);
1154
- }
1155
- }
1156
- console.log(`${lc} [CONFLICT DEBUG] Total merge requests (frames + delta deps): ${mergeDeltaReqs.length}`);
1157
- }
1158
- else {
1159
- console.log(`${lc} [CONFLICT DEBUG] No receiver-only frames found for this conflict`);
1160
- }
1159
+ for (const conflict of conflicts) {
1160
+ // todo: integrate conflict strategies into this point...this whole block needs to be redone, but I want to check the fast-forward/backward simpler case tests first
1161
+ throw new Error(`conflicts not (re)implemented yet (E: 3b7d0819f83842a6de3ae988819bc826)`);
1162
+ // const { timelineAddrs, localAddr: receiverTip, remoteAddr: senderTip } = conflict;
1163
+ // // Sender History
1164
+ // // We need our own history for this timeline.
1165
+ // // We know the 'senderTip' (remoteAddr in Ack).
1166
+ // // Sender should verify it has this tip.
1167
+ // // Compute Diffs
1168
+ // // We need to find `receiverOnly` addrs.
1169
+ // // Receiver sent us `timelineAddrs` (Full History).
1170
+ // const receiverHistorySet = new Set(timelineAddrs);
1171
+ // // We need our execution context's history for this senderTip.
1172
+ // // We can fetch valid 'past' from space.
1173
+ // const resSenderTip = await getFromSpace({ space: destSpace, addr: senderTip });
1174
+ // const senderTipIbGib = resSenderTip.ibGibs?.[0];
1175
+ // if (!senderTipIbGib) { throw new Error(`${lc} Sender missing its own tip? ${senderTip} (E: 832f3804645878869ee3c13714366726)`); }
1176
+ // // Basic Diff: Find what Receiver has that we don't.
1177
+ // // Actually, we need to traverse OUR past to find commonality.
1178
+ // const senderHistory = [senderTip, ...(senderTipIbGib.rel8ns?.past || [])];
1179
+ // const receiverOnlyAddrs = timelineAddrs.filter(addr => !senderHistory.includes(addr));
1180
+ // if (receiverOnlyAddrs.length > 0) {
1181
+ // console.log(`${lc} [CONFLICT DEBUG] Found ${receiverOnlyAddrs.length} receiver-only frames - need to pull for merge`);
1182
+ // console.log(`${lc} [CONFLICT DEBUG] Receiver-only addrs:`, receiverOnlyAddrs);
1183
+ // // PULL these frames from Peer into Local Space
1184
+ // // (Validation: We trust peer for now / verification happens on put)
1185
+ // for (const addr of receiverOnlyAddrs) {
1186
+ // console.error(`${lc} [CONFLICT DEBUG] NOT IMPLEMENTED (E: e6bf1a9d2758c469bb2f97514062d826)`);
1187
+ // }
1188
+ // // Compute DELTA dependencies for each receiver-only frame
1189
+ // // Find LCA to determine what dependencies we already have
1190
+ // const lcaAddr = timelineAddrs.find(addr => senderHistory.includes(addr));
1191
+ // console.log(`${lc} [CONFLICT DEBUG] LCA: ${lcaAddr || 'NONE'}`);
1192
+ // const skipAddrsSet = new Set<string>();
1193
+ // if (lcaAddr) {
1194
+ // try {
1195
+ // const lcaRes = await getFromSpace({ addr: lcaAddr, space: destSpace });
1196
+ // const lcaIbGib = lcaRes.ibGibs?.[0];
1197
+ // if (lcaIbGib) {
1198
+ // const lcaDeps = await getDependencyGraph({ ibGib: lcaIbGib, space: destSpace });
1199
+ // if (lcaDeps) Object.keys(lcaDeps).forEach(a => skipAddrsSet.add(a));
1200
+ // console.log(`${lc} [CONFLICT DEBUG] LCA deps to skip: ${skipAddrsSet.size}`);
1201
+ // }
1202
+ // } catch (e) {
1203
+ // console.warn(`${lc} Error getting LCA deps: ${extractErrorMsg(e)}`);
1204
+ // }
1205
+ // }
1206
+ // // For each receiver-only frame, get its DELTA dependency graph (minus LCA deps)
1207
+ // for (const addr of receiverOnlyAddrs) {
1208
+ // // Add the frame itself first
1209
+ // if (!mergeDeltaReqs.includes(addr)) {
1210
+ // mergeDeltaReqs.push(addr);
1211
+ // }
1212
+ // // Get the frame's delta dependencies (skip LCA's deps)
1213
+ // try {
1214
+ // const frameRes = await getFromSpace({ addr, space: destSpace });
1215
+ // const frameIbGib = frameRes.ibGibs?.[0];
1216
+ // if (frameIbGib) {
1217
+ // // Get dependency graph, skipping all LCA dependencies
1218
+ // const frameDeltaDeps = await getDependencyGraph({
1219
+ // ibGib: frameIbGib,
1220
+ // space: destSpace,
1221
+ // skipAddrs: Array.from(skipAddrsSet), // Skip entire LCA dep graph
1222
+ // });
1223
+ // if (frameDeltaDeps) {
1224
+ // // Add all delta dependencies (Object.keys gives us the addresses)
1225
+ // Object.keys(frameDeltaDeps).forEach(depAddr => {
1226
+ // if (!mergeDeltaReqs.includes(depAddr) && !skipAddrsSet.has(depAddr)) {
1227
+ // mergeDeltaReqs.push(depAddr);
1228
+ // }
1229
+ // });
1230
+ // }
1231
+ // }
1232
+ // } catch (depError) {
1233
+ // console.warn(`${lc} [CONFLICT DEBUG] Error getting delta deps for ${addr}: ${extractErrorMsg(depError)}`);
1234
+ // }
1235
+ // }
1236
+ // console.log(`${lc} [CONFLICT DEBUG] Total merge requests (frames + delta deps): ${mergeDeltaReqs.length}`);
1237
+ // } else {
1238
+ // console.log(`${lc} [CONFLICT DEBUG] No receiver-only frames found for this conflict`);
1239
+ // }
1161
1240
  }
1162
- console.log(`${lc} [CONFLICT DEBUG] Finished processing ${optimisticConflicts.length} conflicts. mergeDeltaReqs: ${mergeDeltaReqs.length}`);
1241
+ console.log(`${lc} [CONFLICT DEBUG] Finished processing ${conflicts.length} conflicts. mergeDeltaReqs: ${mergeDeltaReqs.length}`);
1163
1242
  }
1164
1243
  else {
1165
1244
  console.log(`${lc} [CONFLICT DEBUG] No optimistic conflicts to process`);