@ibgib/core-gib 0.1.27 → 0.1.28

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.
@@ -6,7 +6,7 @@ import { putInSpace, getLatestAddrs, getFromSpace } from "../witness/space/space
6
6
  import { SyncStage, SYNC_ATOM, SYNC_MSG_REL8N_NAME, SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN, } from "./sync-constants.mjs";
7
7
  import { appendToTimeline, createTimeline } from "../timeline/timeline-api.mjs";
8
8
  import { SyncConflictStrategy, SyncMode, SYNC_CONFLICT_STRATEGY_VALID_VALUES, } from "./sync-types.mjs";
9
- import { getSyncIb, getTempSpaceName, isPastFrame } from "./sync-helpers.mjs";
9
+ import { getFullSyncSagaHistory, getSyncIb, getTempSpaceName, isPastFrame, putInSpace_dnasThenNonDnas, validateFullSyncSagaHistory } from "./sync-helpers.mjs";
10
10
  import { getDeltaDependencyGraph, getDependencyGraph, toFlatGraph } from "../common/other/graph-helper.mjs";
11
11
  import { getSyncSagaMessageIb } from "./sync-saga-message/sync-saga-message-helpers.mjs";
12
12
  import { SYNC_SAGA_MSG_ATOM } from "./sync-saga-message/sync-saga-message-constants.mjs";
@@ -171,7 +171,12 @@ export class SyncSagaCoordinator {
171
171
  if (logalot) {
172
172
  console.log(`${lc} Handler returned null (Saga End). (I: 43da8bb6c846b1fe7766332643be0e26)`);
173
173
  }
174
- return null;
174
+ // does this ever hit now?
175
+ return null; /* <<<< returns early */
176
+ }
177
+ else if (contextResult.nextFrameInfo?.sagaComplete) {
178
+ // this is the current proper workflow I believe as of 01/22/2026
179
+ return null; /* <<<< returns early */
175
180
  }
176
181
  // #region error conditions throw
177
182
  if (contextResult.errorMsg) {
@@ -180,9 +185,6 @@ export class SyncSagaCoordinator {
180
185
  else if (!contextResult.nextFrameInfo) {
181
186
  throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo falsy? (E: 5740542f5eb8ccb41dfec188d87c1e26)`);
182
187
  }
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
188
  // #endregion error conditions throw
187
189
  // create the return context
188
190
  const { frame, payloadIbGibsDomain } = contextResult.nextFrameInfo;
@@ -417,8 +419,8 @@ export class SyncSagaCoordinator {
417
419
  else if (!contextResult.nextFrameInfo) {
418
420
  throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo falsy? (E: c287a82e823e662a77923278e2418826)`);
419
421
  }
420
- else if (contextResult.nextFrameInfo?.responseWasNull) {
421
- throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo.responseWasNull? logic flow should not have gotten here. (E: 104a32381db816b7183435e805b3d626)`);
422
+ else if (contextResult.nextFrameInfo?.sagaComplete) {
423
+ throw new Error(`(UNEXPECTED) contextResult.nextFrameInfo.sagaComplete? logic flow should not have gotten here. (E: 104a32381db816b7183435e805b3d626)`);
422
424
  }
423
425
  // #endregion error conditions throw
424
426
  // we have another frame to process and send out, with possibly
@@ -1333,69 +1335,6 @@ export class SyncSagaCoordinator {
1333
1335
  }
1334
1336
  }
1335
1337
  }
1336
- async getPayloadsForRequestedInfos({ deltaRequestAddrInfos, mySpace, }) {
1337
- const lc = `${this.lc}[${this.getPayloadsForRequestedInfos.name}]`;
1338
- try {
1339
- if (logalot) {
1340
- console.log(`${lc} starting... (I: 4fe13d0d80050f20a8b74ba80cee5826)`);
1341
- }
1342
- /**
1343
- * graph of ibgibs we will send to the receiver. addr-based, so will
1344
- * already be unique (no need to call `unique` on the domains
1345
- * ibgibs)
1346
- */
1347
- const outgoingPayloadIbGibsDomainGraph = {};
1348
- for (const { addr, latestAddrAlreadyHave } of deltaRequestAddrInfos) {
1349
- let deltaDepGraph;
1350
- if (latestAddrAlreadyHave) {
1351
- // already has some, so only get the delta
1352
- // remember: if we didn't have the other's latest addr, then
1353
- // this would be in the conflicts not requested addrs
1354
- deltaDepGraph = await getDeltaDependencyGraph({
1355
- ibGibAddr: addr,
1356
- latestCommonFrameAddr: latestAddrAlreadyHave,
1357
- space: mySpace,
1358
- live: true,
1359
- });
1360
- }
1361
- else {
1362
- // doesn't have anything, so get the entire dependency graph
1363
- // INEFFICIENT: we've already gotten all of the domain
1364
- // dependencies in initDomainGraph, but getDependencyGraph
1365
- // only works against a space so we are going to rerun this.
1366
- // an optimization would be to adapt/create a new
1367
- // getDependencyGraph to work against an existing flat ibgib
1368
- // map.
1369
- deltaDepGraph = await getDependencyGraph({
1370
- ibGibAddr: addr,
1371
- space: mySpace,
1372
- live: true,
1373
- });
1374
- }
1375
- const depGraphSize = Object.keys(deltaDepGraph).length;
1376
- if (depGraphSize === 0) {
1377
- throw new Error(`(UNEXPECTED) couldn't get requested addrs in mySpace (${mySpace.ib})? How did the receiver know to ask for these addrs if they weren't in our original graph? (E: 281eaebcdf77dd73e8245b2872100826)`);
1378
- }
1379
- else {
1380
- // we have dependencies!
1381
- Object.values(deltaDepGraph).forEach(x => {
1382
- outgoingPayloadIbGibsDomainGraph[getIbGibAddr({ ibGib: x })] = x;
1383
- });
1384
- }
1385
- }
1386
- const result = Object.values(outgoingPayloadIbGibsDomainGraph);
1387
- return result;
1388
- }
1389
- catch (error) {
1390
- console.error(`${lc} ${extractErrorMsg(error)}`);
1391
- throw error;
1392
- }
1393
- finally {
1394
- if (logalot) {
1395
- console.log(`${lc} complete.`);
1396
- }
1397
- }
1398
- }
1399
1338
  /**
1400
1339
  * Handles the `Delta` frame.
1401
1340
  *
@@ -1451,25 +1390,33 @@ export class SyncSagaCoordinator {
1451
1390
  // V1 timelines carry full history in `past`.
1452
1391
  const pastAddrs = sagaIbGib.rel8ns?.past || [];
1453
1392
  console.log(`${lc} [TEST DEBUG] pastAddrs count: ${pastAddrs.length}`);
1454
- let ackData;
1455
- if (pastAddrs.length > 0) {
1456
- // Batch fetch all past frames
1457
- const resPast = await getFromSpace({ addrs: pastAddrs, space: myTempSpace });
1458
- if (resPast.success && resPast.ibGibs) {
1459
- // Iterate backwards (most recent first) to find the latest Ack
1460
- for (let i = resPast.ibGibs.length - 1; i >= 0; i--) {
1461
- const pastFrame = resPast.ibGibs[i];
1462
- const messageStone = await getSyncSagaMessageFromFrame({
1463
- frameIbGib: pastFrame,
1464
- space: myTempSpace
1465
- });
1466
- if (messageStone?.data?.stage === SyncStage.ack) {
1467
- ackData = messageStone.data;
1468
- console.log(`${lc} [TEST DEBUG] Found Ack Frame. Conflicts: ${ackData.conflicts?.length || 0}`);
1469
- break;
1470
- }
1471
- }
1472
- }
1393
+ const sagaHistory = await getFullSyncSagaHistory({
1394
+ sagaIbGib,
1395
+ space: mySpace,
1396
+ });
1397
+ // #region validate/sanity sagaHistory
1398
+ if (sagaHistory.length === 0) {
1399
+ throw new Error(`(UNEXPECTED) sagaHistory.length is 0? We're in handleDeltaFrame. So we should have at least init and ack. (E: 815735c9cf756b275719bf434f180826)`);
1400
+ }
1401
+ if (sagaHistory.length === 1) {
1402
+ throw new Error(`(UNEXPECTED) sagaHistory.length is 1? We're in handleDeltaFrame. So we should have at least init and ack. (E: 0e4ef8e3ed088e83b2cdcd18ecea9826)`);
1403
+ }
1404
+ // #endregion validate/sanity sagaHistory
1405
+ const ackGraphs = sagaHistory.filter(x => x.msgStones.at(0).data.stage === SyncStage.ack);
1406
+ // #region validate/sanity ackGraphs
1407
+ if (ackGraphs.length > 1) {
1408
+ throw new Error(`(UNEXPECTED) more than one ack stage found in sagaHistory? we're expecting exactly one. (E: 7150983bb3a841caf8acd60826ba4f26)`);
1409
+ }
1410
+ else if (ackGraphs.length === 0) {
1411
+ throw new Error(`(UNEXPECTED) couldn't find ack stage in sagaHistory? (E: 7d2da859196b86de28e7c8183af1e826)`);
1412
+ }
1413
+ if (ackGraphs[0].msgStones.length !== 1) {
1414
+ throw new Error(`(UNEXPECTED) ackGraph has more than one msg stone? only one expected right now. (E: f07d388abff8d26f98cbf6e8d3932826)`);
1415
+ }
1416
+ // #endregion validate/sanity ackGraphs
1417
+ const ackData = ackGraphs[0].msgStones[0].data;
1418
+ if (!ackData) {
1419
+ throw new Error(`(UNEXPECTED) ackData falsy? (E: f9af88427f66a8db1ba868b810e8b826)`);
1473
1420
  }
1474
1421
  if (ackData && ackData.conflicts) {
1475
1422
  const optimisticConflicts = ackData.conflicts.filter(c => !c.terminal);
@@ -1529,17 +1476,7 @@ export class SyncSagaCoordinator {
1529
1476
  stage: SyncStage.delta,
1530
1477
  payloadAddrs: outgoingPayload.map(p => getIbGibAddr({ ibGib: p })),
1531
1478
  requests: hasMyRequests ? myRequests : undefined,
1532
- proposeCommit: !hasMyRequests // If we are sending data but have no requests, we VALIDATE PROPOSAL?
1533
- // Wait. If we send data, we are NOT committing yet.
1534
- // We are sending data. The OTHER side must ingest it.
1535
- // So proposeCommit = true?
1536
- // "Here is the data. I'm done. If you are good, let's commit."
1537
- // Yes.
1538
1479
  };
1539
- // BUT if `peerProposesCommit` was true, and we are sending data, we are effectively rejecting/delaying it.
1540
- // We just send the Delta. Peer receives it, ingests, sees ProposeCommit=True (from us), and then Commits.
1541
- // So yes, proposeCommit = true.
1542
- responseDeltaData.proposeCommit = true;
1543
1480
  const deltaStone = await this.createSyncMsgStone({
1544
1481
  data: responseDeltaData,
1545
1482
  localSpace: mySpace,
@@ -1552,41 +1489,43 @@ export class SyncSagaCoordinator {
1552
1489
  localSpace: mySpace,
1553
1490
  metaspace,
1554
1491
  });
1555
- // Build control payloads: frame + its dependencies (msg stone, identity)
1556
- const payloadIbGibsControl = [deltaFrame, deltaStone];
1557
- if (identity) {
1558
- payloadIbGibsControl.push(identity);
1559
- }
1560
- // return { frame: deltaFrame, payloadIbGibsControl, payloadIbGibsDomain: outgoingPayload };
1561
1492
  return { frame: deltaFrame, payloadIbGibsDomain: outgoingPayload };
1562
- // throw new Error(`not implemented (E: 2b38a8afb6d84efcee5ab51673387826)`);
1563
1493
  }
1564
1494
  else {
1565
1495
  // We have nothing to send.
1566
1496
  if (peerProposesCommit) {
1567
1497
  // Peer is done. We are done. -> Commit.
1568
- const commitData = {
1569
- sagaId: deltaData.sagaId,
1570
- stage: SyncStage.commit,
1571
- success: true,
1572
- };
1573
- const commitStone = await this.createSyncMsgStone({
1574
- data: commitData,
1575
- localSpace: mySpace,
1576
- metaspace
1498
+ // one last validate entire history?
1499
+ const history = await getFullSyncSagaHistory({
1500
+ sagaIbGib,
1501
+ space: mySpace,
1577
1502
  });
1578
- const commitFrame = await this.evolveSyncSagaIbGib({
1579
- prevSagaIbGib: sagaIbGib,
1580
- msgStones: [commitStone],
1581
- sessionIdentity: identity,
1582
- localSpace: mySpace,
1583
- metaspace
1503
+ const validationErrors = await validateFullSyncSagaHistory({
1504
+ history,
1584
1505
  });
1585
- // Build control payloads for commit
1586
- const commitCtrlPayloads = [commitFrame, commitStone];
1587
- if (identity) {
1588
- commitCtrlPayloads.push(identity);
1506
+ if (validationErrors.length > 0) {
1507
+ const errorCommitFrame = await this.createCommitFrame({
1508
+ sagaIbGib,
1509
+ errors: validationErrors,
1510
+ metaspace, mySpace,
1511
+ identity,
1512
+ });
1513
+ return { frame: errorCommitFrame, }; /* <<<< returns early */
1589
1514
  }
1515
+ await this.executeLocalCommit({
1516
+ sagaHistory: history,
1517
+ deltaFrame: sagaIbGib,
1518
+ localTempSpace: myTempSpace,
1519
+ localSpace: mySpace,
1520
+ metaspace,
1521
+ });
1522
+ const commitFrame = await this.createCommitFrame({
1523
+ sagaIbGib,
1524
+ errors: undefined,
1525
+ metaspace,
1526
+ mySpace,
1527
+ identity,
1528
+ });
1590
1529
  return { frame: commitFrame, };
1591
1530
  }
1592
1531
  else {
@@ -1660,28 +1599,219 @@ export class SyncSagaCoordinator {
1660
1599
  }
1661
1600
  }
1662
1601
  }
1602
+ /**
1603
+ * should throw if fails
1604
+ */
1605
+ async executeLocalCommit({ deltaFrame, sagaHistory, metaspace, localSpace, localTempSpace, identity, }) {
1606
+ const lc = `${this.lc}[${this.executeLocalCommit.name}]`;
1607
+ try {
1608
+ if (logalot) {
1609
+ console.log(`${lc} starting... (I: 6734980446b86a63c1af6e2e206de826)`);
1610
+ }
1611
+ // #region validate/sanity
1612
+ if (!deltaFrame.data) {
1613
+ throw new Error(`(UNEXPECTED) deltaFrame.data falsy? (E: a8be68d48668d93d992d793834823826)`);
1614
+ }
1615
+ // #endregion validate/sanity
1616
+ // * move all payload addrs from temp space to local space
1617
+ // * register each and every iteration of each timeline (including
1618
+ // stones, which are like their own sealed timeline of length 1)
1619
+ const allPayloadAddrsDomainTransferred = [];
1620
+ const fnAddPayloadAddr = (addr) => {
1621
+ if (!allPayloadAddrsDomainTransferred.includes(addr)) {
1622
+ allPayloadAddrsDomainTransferred.push(addr);
1623
+ }
1624
+ };
1625
+ sagaHistory.forEach(x => {
1626
+ if (!x.sagaIbGib.data) {
1627
+ throw new Error(`(UNEXPECTED) sagaIbGib.data falsy? (E: 34d7f8cdee14717ce828878d98f89826)`);
1628
+ }
1629
+ x.msgStones.forEach(msgStone => {
1630
+ if (!msgStone.data) {
1631
+ throw new Error(`(UNEXPECTED) msgStone.data falsy? (E: 21406101f91847514cc759c8a7382f26)`);
1632
+ }
1633
+ if (msgStone.data.stage === SyncStage.ack) {
1634
+ const ackData = msgStone.data;
1635
+ if (ackData.pushOfferInfos && ackData.pushOfferInfos.length > 0) {
1636
+ ackData.pushOfferInfos.forEach(info => {
1637
+ info.addrs.forEach(addr => fnAddPayloadAddr(addr));
1638
+ });
1639
+ }
1640
+ }
1641
+ else if (msgStone.data.stage === SyncStage.delta) {
1642
+ const deltaData = msgStone.data;
1643
+ if (deltaData.payloadAddrsDomain && deltaData.payloadAddrsDomain.length > 0) {
1644
+ deltaData.payloadAddrsDomain.forEach(addr => fnAddPayloadAddr(addr));
1645
+ }
1646
+ }
1647
+ });
1648
+ });
1649
+ // at this point, we have a list of ALL payload addrs retrieved.
1650
+ let allPayloadIbGibsDomainTransferred = [];
1651
+ const resGetAllTransferred = await getFromSpace({ addrs: allPayloadAddrsDomainTransferred, space: localTempSpace });
1652
+ if (resGetAllTransferred.success && resGetAllTransferred.ibGibs && resGetAllTransferred.ibGibs.length === allPayloadAddrsDomainTransferred.length) {
1653
+ allPayloadIbGibsDomainTransferred = resGetAllTransferred.ibGibs.concat();
1654
+ }
1655
+ else {
1656
+ // errored out, gather info
1657
+ if (!resGetAllTransferred.rawResultIbGib) {
1658
+ throw new Error(`(UNEXPECTED) !resGetAllTransferred.rawResultIbGib falsy? (E: dc6cf8729668f4fbe8c024f887d97a26)`);
1659
+ }
1660
+ const { addrsNotFound, addrsErrored, errors } = resGetAllTransferred.rawResultIbGib.data;
1661
+ throw new Error(`(UNEXPECTED) we couldn't get all addrs transferred throughout the saga from the tempspace (${localTempSpace.ib})? addrsNotFound: ${addrsNotFound ?? []}. addrsErrored: ${addrsErrored ?? []}. errors: ${errors ?? []}(E: 222e341e634862b4d88ae7282584d826)`);
1662
+ }
1663
+ // now we have all ibgibs transferred, first put them all the local space
1664
+ const { payload_Dnas, payload_NonDnas } = await putInSpace_dnasThenNonDnas({
1665
+ ibGibs: allPayloadIbGibsDomainTransferred,
1666
+ space: localSpace
1667
+ });
1668
+ const { mapWithTjp_NoDna, mapWithTjp_YesDna, mapWithoutTjps } = splitPerTjpAndOrDna({ ibGibs: payload_NonDnas, filterPrimitives: true });
1669
+ // first register all non-tjp stones
1670
+ const nontjps = Object.values(mapWithoutTjps);
1671
+ for (const nontjp of nontjps) {
1672
+ await metaspace.registerNewIbGib({
1673
+ ibGib: nontjp,
1674
+ space: localSpace,
1675
+ });
1676
+ }
1677
+ // next register each timeline in order...
1678
+ // ...first the ones without dna...
1679
+ const timelinesByTjpAddr_NoDna = getTimelinesGroupedByTjp({ ibGibs: Object.values(mapWithTjp_NoDna) });
1680
+ const tjpAddrs_NoDna = Object.keys(timelinesByTjpAddr_NoDna);
1681
+ for (const tjpAddr_NoDna of tjpAddrs_NoDna) {
1682
+ const timelineIbGibs = timelinesByTjpAddr_NoDna[tjpAddr_NoDna];
1683
+ for (const ibGib of timelineIbGibs) {
1684
+ await metaspace.registerNewIbGib({
1685
+ ibGib,
1686
+ space: localSpace,
1687
+ });
1688
+ }
1689
+ }
1690
+ // ...then the ones WITH dna.
1691
+ const timelinesByTjpAddr_YesDna = getTimelinesGroupedByTjp({ ibGibs: Object.values(mapWithTjp_YesDna) });
1692
+ const tjpAddrs_YesDna = Object.keys(timelinesByTjpAddr_YesDna);
1693
+ for (const tjpAddr_YesDna of tjpAddrs_YesDna) {
1694
+ const timelineIbGibs = timelinesByTjpAddr_YesDna[tjpAddr_YesDna];
1695
+ for (const ibGib of timelineIbGibs) {
1696
+ await metaspace.registerNewIbGib({
1697
+ ibGib,
1698
+ space: localSpace,
1699
+ });
1700
+ }
1701
+ }
1702
+ }
1703
+ catch (error) {
1704
+ console.error(`${lc} ${extractErrorMsg(error)}`);
1705
+ throw error;
1706
+ }
1707
+ finally {
1708
+ if (logalot) {
1709
+ console.log(`${lc} complete.`);
1710
+ }
1711
+ }
1712
+ }
1713
+ async createCommitFrame({ sagaIbGib, errors, metaspace, mySpace, identity, }) {
1714
+ const lc = `[${this.createCommitFrame.name}]`;
1715
+ try {
1716
+ if (logalot) {
1717
+ console.log(`${lc} starting... (I: 48fc57c023f80122135a284855757526)`);
1718
+ }
1719
+ const commitData = errors && errors.length > 0 ?
1720
+ {
1721
+ // errored
1722
+ sagaId: sagaIbGib.data.uuid,
1723
+ stage: SyncStage.commit,
1724
+ success: false,
1725
+ errors,
1726
+ } :
1727
+ {
1728
+ // not errored
1729
+ sagaId: sagaIbGib.data.uuid,
1730
+ stage: SyncStage.commit,
1731
+ success: true,
1732
+ };
1733
+ const commitStone = await this.createSyncMsgStone({
1734
+ data: commitData,
1735
+ localSpace: mySpace,
1736
+ metaspace
1737
+ });
1738
+ const commitFrame = await this.evolveSyncSagaIbGib({
1739
+ prevSagaIbGib: sagaIbGib,
1740
+ msgStones: [commitStone],
1741
+ sessionIdentity: identity,
1742
+ localSpace: mySpace,
1743
+ metaspace,
1744
+ });
1745
+ return commitFrame;
1746
+ }
1747
+ catch (error) {
1748
+ console.error(`${lc} ${extractErrorMsg(error)}`);
1749
+ throw error;
1750
+ }
1751
+ finally {
1752
+ if (logalot) {
1753
+ console.log(`${lc} complete.`);
1754
+ }
1755
+ }
1756
+ }
1663
1757
  async handleCommitFrame({ sagaIbGib, mySpace, myTempSpace, metaspace, identity, }) {
1664
1758
  const lc = `${this.lc}[${this.handleCommitFrame.name}]`;
1665
1759
  try {
1666
1760
  if (logalot) {
1667
1761
  console.log(`${lc} starting... (I: e179573bdd881202f8ba3168da1c3826)`);
1668
1762
  }
1763
+ let resNextSagaFrameInfo;
1669
1764
  // Sender Logic (Finalizing):
1670
1765
  // If we are here, we received a Commit frame from the Peer.
1671
1766
  // This implies the Peer has successfully committed.
1672
1767
  // We should now:
1673
1768
  // 1. Validate (implicitly done by receiving valid frame)
1674
1769
  // 2. Perform our own cleanup (Temp -> Dest, if applicable)
1675
- // 3. Return null to signal saga completion.
1676
- // Note: Currently we don't have explicit cleanup logic implemented here yet (TODO).
1770
+ // 3. Return saga completion.
1771
+ // one last validate entire history?
1772
+ const history = await getFullSyncSagaHistory({
1773
+ sagaIbGib,
1774
+ space: mySpace,
1775
+ });
1776
+ const validationErrors = await validateFullSyncSagaHistory({
1777
+ history,
1778
+ });
1779
+ if (validationErrors.length > 0) {
1780
+ const errorCommitFrame = await this.createCommitFrame({
1781
+ sagaIbGib,
1782
+ metaspace,
1783
+ mySpace,
1784
+ identity,
1785
+ errors: validationErrors,
1786
+ });
1787
+ return { frame: errorCommitFrame, }; /* <<<< returns early */
1788
+ }
1789
+ await this.executeLocalCommit({
1790
+ deltaFrame: sagaIbGib,
1791
+ sagaHistory: history,
1792
+ localSpace: mySpace,
1793
+ localTempSpace: myTempSpace,
1794
+ metaspace,
1795
+ });
1796
+ // todo: implement explicit cleanup logic here and in peer
1797
+ console.error(`${lc} NAG ERROR (NOT THROWN): implement cleanup logic, including add a cleanup method to the peer (E: 3a9a24befb98a981a88fbdbf52920e26)`);
1677
1798
  if (logalot) {
1678
1799
  console.log(`${lc} Peer committed. Finalizing saga locally. Saga Complete.`);
1679
1800
  }
1680
- return { responseWasNull: true };
1801
+ // the holy grail!
1802
+ return { sagaComplete: true };
1681
1803
  }
1682
1804
  catch (error) {
1683
- console.error(`${lc} ${extractErrorMsg(error)}`);
1684
- throw error;
1805
+ const emsg = `${lc} ${extractErrorMsg(error)}`;
1806
+ console.error(emsg);
1807
+ const errorCommitFrame = await this.createCommitFrame({
1808
+ sagaIbGib,
1809
+ errors: [emsg],
1810
+ metaspace,
1811
+ mySpace,
1812
+ identity,
1813
+ });
1814
+ return { frame: errorCommitFrame };
1685
1815
  }
1686
1816
  finally {
1687
1817
  if (logalot) {
@@ -1720,6 +1850,69 @@ export class SyncSagaCoordinator {
1720
1850
  }
1721
1851
  }
1722
1852
  }
1853
+ async getPayloadsForRequestedInfos({ deltaRequestAddrInfos, mySpace, }) {
1854
+ const lc = `${this.lc}[${this.getPayloadsForRequestedInfos.name}]`;
1855
+ try {
1856
+ if (logalot) {
1857
+ console.log(`${lc} starting... (I: 4fe13d0d80050f20a8b74ba80cee5826)`);
1858
+ }
1859
+ /**
1860
+ * graph of ibgibs we will send to the receiver. addr-based, so will
1861
+ * already be unique (no need to call `unique` on the domains
1862
+ * ibgibs)
1863
+ */
1864
+ const outgoingPayloadIbGibsDomainGraph = {};
1865
+ for (const { addr, latestAddrAlreadyHave } of deltaRequestAddrInfos) {
1866
+ let deltaDepGraph;
1867
+ if (latestAddrAlreadyHave) {
1868
+ // already has some, so only get the delta
1869
+ // remember: if we didn't have the other's latest addr, then
1870
+ // this would be in the conflicts not requested addrs
1871
+ deltaDepGraph = await getDeltaDependencyGraph({
1872
+ ibGibAddr: addr,
1873
+ latestCommonFrameAddr: latestAddrAlreadyHave,
1874
+ space: mySpace,
1875
+ live: true,
1876
+ });
1877
+ }
1878
+ else {
1879
+ // doesn't have anything, so get the entire dependency graph
1880
+ // INEFFICIENT: we've already gotten all of the domain
1881
+ // dependencies in initDomainGraph, but getDependencyGraph
1882
+ // only works against a space so we are going to rerun this.
1883
+ // an optimization would be to adapt/create a new
1884
+ // getDependencyGraph to work against an existing flat ibgib
1885
+ // map.
1886
+ deltaDepGraph = await getDependencyGraph({
1887
+ ibGibAddr: addr,
1888
+ space: mySpace,
1889
+ live: true,
1890
+ });
1891
+ }
1892
+ const depGraphSize = Object.keys(deltaDepGraph).length;
1893
+ if (depGraphSize === 0) {
1894
+ throw new Error(`(UNEXPECTED) couldn't get requested addrs in mySpace (${mySpace.ib})? How did the receiver know to ask for these addrs if they weren't in our original graph? (E: 281eaebcdf77dd73e8245b2872100826)`);
1895
+ }
1896
+ else {
1897
+ // we have dependencies!
1898
+ Object.values(deltaDepGraph).forEach(x => {
1899
+ outgoingPayloadIbGibsDomainGraph[getIbGibAddr({ ibGib: x })] = x;
1900
+ });
1901
+ }
1902
+ }
1903
+ const result = Object.values(outgoingPayloadIbGibsDomainGraph);
1904
+ return result;
1905
+ }
1906
+ catch (error) {
1907
+ console.error(`${lc} ${extractErrorMsg(error)}`);
1908
+ throw error;
1909
+ }
1910
+ finally {
1911
+ if (logalot) {
1912
+ console.log(`${lc} complete.`);
1913
+ }
1914
+ }
1915
+ }
1723
1916
  /**
1724
1917
  * Evolves the saga timeline with a new frame.
1725
1918
  */