@ibgib/core-gib 0.1.12 → 0.1.14

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 (106) hide show
  1. package/dist/keystone/keystone-helpers.mjs +3 -3
  2. package/dist/keystone/keystone-helpers.mjs.map +1 -1
  3. package/dist/sync/sync-constants.d.mts +4 -1
  4. package/dist/sync/sync-constants.d.mts.map +1 -1
  5. package/dist/sync/sync-constants.mjs +3 -0
  6. package/dist/sync/sync-constants.mjs.map +1 -1
  7. package/dist/sync/sync-helpers.d.mts +18 -2
  8. package/dist/sync/sync-helpers.d.mts.map +1 -1
  9. package/dist/sync/sync-helpers.mjs +84 -3
  10. package/dist/sync/sync-helpers.mjs.map +1 -1
  11. package/dist/sync/sync-innerspace.respec.d.mts +0 -6
  12. package/dist/sync/sync-innerspace.respec.d.mts.map +1 -1
  13. package/dist/sync/sync-innerspace.respec.mjs +395 -241
  14. package/dist/sync/sync-innerspace.respec.mjs.map +1 -1
  15. package/dist/sync/sync-peer/sync-peer-types.d.mts +31 -0
  16. package/dist/sync/sync-peer/sync-peer-types.d.mts.map +1 -0
  17. package/dist/sync/sync-peer/sync-peer-types.mjs +5 -0
  18. package/dist/sync/sync-peer/sync-peer-types.mjs.map +1 -0
  19. package/dist/sync/sync-peer/sync-peer-v1.d.mts +22 -0
  20. package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -0
  21. package/dist/sync/sync-peer/sync-peer-v1.mjs +13 -0
  22. package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -0
  23. package/dist/sync/sync-saga-context/sync-saga-context-constants.d.mts +8 -0
  24. package/dist/sync/sync-saga-context/sync-saga-context-constants.d.mts.map +1 -0
  25. package/dist/sync/sync-saga-context/sync-saga-context-constants.mjs +8 -0
  26. package/dist/sync/sync-saga-context/sync-saga-context-constants.mjs.map +1 -0
  27. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts +54 -0
  28. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts.map +1 -0
  29. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs +87 -0
  30. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs.map +1 -0
  31. package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts +66 -0
  32. package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts.map +1 -0
  33. package/dist/sync/sync-saga-context/sync-saga-context-types.mjs +12 -0
  34. package/dist/sync/sync-saga-context/sync-saga-context-types.mjs.map +1 -0
  35. package/dist/sync/sync-saga-coordinator.d.mts +136 -91
  36. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  37. package/dist/sync/sync-saga-coordinator.mjs +563 -287
  38. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  39. package/dist/sync/sync-saga-coordinator.respec.mjs +7 -7
  40. package/dist/sync/sync-saga-coordinator.respec.mjs.map +1 -1
  41. package/dist/sync/sync-saga-message/sync-saga-message-constants.d.mts +2 -0
  42. package/dist/sync/sync-saga-message/sync-saga-message-constants.d.mts.map +1 -0
  43. package/dist/sync/sync-saga-message/sync-saga-message-constants.mjs +2 -0
  44. package/dist/sync/sync-saga-message/sync-saga-message-constants.mjs.map +1 -0
  45. package/dist/sync/sync-saga-message/sync-saga-message-helpers.d.mts +15 -0
  46. package/dist/sync/sync-saga-message/sync-saga-message-helpers.d.mts.map +1 -0
  47. package/dist/sync/sync-saga-message/sync-saga-message-helpers.mjs +43 -0
  48. package/dist/sync/sync-saga-message/sync-saga-message-helpers.mjs.map +1 -0
  49. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts +39 -0
  50. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts.map +1 -0
  51. package/dist/sync/sync-saga-message/sync-saga-message-types.mjs +2 -0
  52. package/dist/sync/sync-saga-message/sync-saga-message-types.mjs.map +1 -0
  53. package/dist/sync/sync-types.d.mts +81 -3
  54. package/dist/sync/sync-types.d.mts.map +1 -1
  55. package/dist/sync/sync-types.mjs +27 -1
  56. package/dist/sync/sync-types.mjs.map +1 -1
  57. package/dist/timeline/timeline-api.d.mts +16 -3
  58. package/dist/timeline/timeline-api.d.mts.map +1 -1
  59. package/dist/timeline/timeline-api.mjs +7 -7
  60. package/dist/timeline/timeline-api.mjs.map +1 -1
  61. package/dist/witness/space/inner-space/inner-space-v1.d.mts.map +1 -1
  62. package/dist/witness/space/inner-space/inner-space-v1.mjs +3 -4
  63. package/dist/witness/space/inner-space/inner-space-v1.mjs.map +1 -1
  64. package/dist/witness/space/outer-space/outer-space-types.d.mts +2 -0
  65. package/dist/witness/space/outer-space/outer-space-types.d.mts.map +1 -1
  66. package/dist/witness/space/space-base-v1.d.mts +19 -1
  67. package/dist/witness/space/space-base-v1.d.mts.map +1 -1
  68. package/dist/witness/space/space-base-v1.mjs +66 -6
  69. package/dist/witness/space/space-base-v1.mjs.map +1 -1
  70. package/dist/witness/space/space-helper.d.mts +14 -0
  71. package/dist/witness/space/space-helper.d.mts.map +1 -1
  72. package/dist/witness/space/space-helper.mjs +44 -1
  73. package/dist/witness/space/space-helper.mjs.map +1 -1
  74. package/dist/witness/space/space-respec-helper.d.mts.map +1 -1
  75. package/dist/witness/space/space-respec-helper.mjs +1 -1
  76. package/dist/witness/space/space-respec-helper.mjs.map +1 -1
  77. package/dist/witness/space/space-types.d.mts +12 -1
  78. package/dist/witness/space/space-types.d.mts.map +1 -1
  79. package/dist/witness/space/space-types.mjs +4 -0
  80. package/dist/witness/space/space-types.mjs.map +1 -1
  81. package/package.json +2 -2
  82. package/src/keystone/keystone-helpers.mts +3 -3
  83. package/src/sync/README.md +275 -0
  84. package/src/sync/sync-constants.mts +5 -0
  85. package/src/sync/sync-helpers.mts +105 -6
  86. package/src/sync/sync-innerspace.respec.mts +458 -289
  87. package/src/sync/sync-peer/sync-peer-types.mts +43 -0
  88. package/src/sync/sync-peer/sync-peer-v1.mts +28 -0
  89. package/src/sync/sync-saga-context/sync-saga-context-constants.mts +8 -0
  90. package/src/sync/sync-saga-context/sync-saga-context-helpers.mts +147 -0
  91. package/src/sync/sync-saga-context/sync-saga-context-types.mts +80 -0
  92. package/src/sync/sync-saga-coordinator.mts +762 -329
  93. package/src/sync/sync-saga-coordinator.respec.mts +7 -7
  94. package/src/sync/sync-saga-message/sync-saga-message-constants.mts +1 -0
  95. package/src/sync/sync-saga-message/sync-saga-message-helpers.mts +59 -0
  96. package/src/sync/sync-saga-message/sync-saga-message-types.mts +53 -0
  97. package/src/sync/sync-types.mts +103 -3
  98. package/src/timeline/timeline-api.mts +20 -4
  99. package/src/witness/space/inner-space/inner-space-v1.mts +3 -2
  100. package/src/witness/space/reconciliation-space/reconciliation-space-base.mts.OLD.md +884 -0
  101. package/src/witness/space/reconciliation-space/reconciliation-space-helper.mts.OLD.md +125 -0
  102. package/src/witness/space/space-base-v1.mts +62 -12
  103. package/src/witness/space/space-helper.mts +50 -1
  104. package/src/witness/space/space-respec-helper.mts +2 -1
  105. package/src/witness/space/space-types.mts +13 -1
  106. package/tmp.md +3 -9
@@ -0,0 +1,884 @@
1
+ import { extractErrorMsg, getUUID, groupBy } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
2
+ import { getGibInfo } from '@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs';
3
+ import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
4
+ import { IbGibAddr } from '@ibgib/ts-gib/dist/types.mjs';
5
+ import { Factory_V1 as factory, } from '@ibgib/ts-gib/dist/V1/factory.mjs';
6
+ import { getIbAndGib, getIbGibAddr, } from '@ibgib/ts-gib/dist/helper.mjs';
7
+ import { mut8 } from '@ibgib/ts-gib/dist/V1/transforms/mut8.mjs';
8
+
9
+ import { GLOBAL_LOG_A_LOT } from '../../../core-constants.mjs';
10
+ import { SpaceBase_V1 } from '../space-base-v1.mjs';
11
+ import {
12
+ IbGibSpaceData,
13
+ IbGibSpaceOptionsData,
14
+ IbGibSpaceOptionsRel8ns,
15
+ IbGibSpaceOptionsIbGib,
16
+ IbGibSpaceResultData,
17
+ IbGibSpaceResultRel8ns,
18
+ IbGibSpaceResultIbGib,
19
+ IbGibSpaceRel8ns,
20
+ IbGibSpaceOptionsCmd,
21
+ } from '../space-types.mjs';
22
+ import { execInSpaceWithLocking, getSpaceIb, throwIfDuplicates, } from '../space-helper.mjs';
23
+ import { getTjpAddr, splitPerTjpAndOrDna, } from '../../../common/other/ibgib-helper.mjs';
24
+ import { getStatusIb } from '../outer-space/outer-space-helper.mjs';
25
+ import { ParticipantInfo, StatusCode, SyncSagaInfo, SyncSpaceOptionsCmdModifier, SyncSpaceOptionsIbGib, SyncStatusData, SyncStatusIbGib } from '../outer-space/outer-space-types.mjs';
26
+ import { STATUS_UNDEFINED_TX_ID } from '../space-constants.mjs';
27
+ import { SubjectWitness } from '../../../common/pubsub/subject/subject-types.mjs';
28
+ import { applyTransforms } from './reconciliation-space-helper.mjs';
29
+
30
+
31
+ const logalot = GLOBAL_LOG_A_LOT;
32
+
33
+ export interface ReconciliationSpaceData extends IbGibSpaceData {
34
+ // currently no special properties, but creating for extensibility
35
+ }
36
+ export interface ReconciliationSpaceRel8ns extends IbGibSpaceRel8ns {
37
+ // currently no special properties, but creating for extensibility
38
+ }
39
+
40
+
41
+ /**
42
+ * Base class for spaces that perform intelligent merging of ibgib timelines,
43
+ * whether it's a bi-directional sync, a one-way merge, or another custom
44
+ * reconciliation strategy.
45
+ *
46
+ * This class contains the core, backend-agnostic logic for timeline
47
+ * reconciliation. Concrete implementations must provide the primitive
48
+ * I/O functions for their specific backing store.
49
+ */
50
+ export abstract class ReconciliationSpaceBase<
51
+ TIbGib extends IbGib_V1 = IbGib_V1,
52
+ TData extends ReconciliationSpaceData = ReconciliationSpaceData,
53
+ TRel8ns extends ReconciliationSpaceRel8ns = ReconciliationSpaceRel8ns,
54
+ TSpaceOptionsData extends IbGibSpaceOptionsData = IbGibSpaceOptionsData,
55
+ TSpaceOptionsRel8ns extends IbGibSpaceOptionsRel8ns = IbGibSpaceOptionsRel8ns,
56
+ TSpaceOptionsIbGib extends IbGibSpaceOptionsIbGib<TIbGib, TSpaceOptionsData, TSpaceOptionsRel8ns> = IbGibSpaceOptionsIbGib<TIbGib, TSpaceOptionsData, TSpaceOptionsRel8ns>,
57
+ TSpaceResultData extends IbGibSpaceResultData = IbGibSpaceResultData,
58
+ TSpaceResultRel8ns extends IbGibSpaceResultRel8ns = IbGibSpaceResultRel8ns,
59
+ TSpaceResultIbGib extends IbGibSpaceResultIbGib<TIbGib, TSpaceResultData, TSpaceResultRel8ns> = IbGibSpaceResultIbGib<TIbGib, TSpaceResultData, TSpaceResultRel8ns>
60
+ > extends SpaceBase_V1<
61
+ TIbGib,
62
+ TSpaceOptionsData,
63
+ TSpaceOptionsRel8ns,
64
+ TSpaceOptionsIbGib,
65
+ TSpaceResultData,
66
+ TSpaceResultRel8ns,
67
+ TSpaceResultIbGib,
68
+ TData,
69
+ TRel8ns
70
+ > {
71
+
72
+ protected lc: string = `[ReconciliationSpaceBase]`;
73
+
74
+ protected abstract _getLatestAddrsInStore(ibGibs: TIbGib[]): Promise<{ [addr: string]: IbGibAddr | null }>;
75
+
76
+ protected abstract _getIbGibsFromStore(addrs: IbGibAddr[]): Promise<{ [addr: string]: TIbGib }>;
77
+
78
+ protected abstract _putIbGibsToStore(ibGibs: TIbGib[]): Promise<void>;
79
+
80
+ protected abstract _deleteIbGibsFromStore(addrs: IbGibAddr[]): Promise<void>;
81
+
82
+ // protected abstract spinOffToCompleteSync(arg: any): Promise<void>;
83
+ protected async spinOffToCompleteSync({
84
+ srcSpaceId,
85
+ sagaId,
86
+ ibGibs,
87
+ statusStartIbGibs,
88
+ syncStatusIbGib_Start,
89
+ syncStatus$,
90
+ errors,
91
+ warnings,
92
+ }: {
93
+ srcSpaceId: string,
94
+ sagaId: string,
95
+ ibGibs: TIbGib[],
96
+ statusStartIbGibs: TIbGib[],
97
+ syncStatusIbGib_Start: SyncStatusIbGib,
98
+ syncStatus$: SubjectWitness<SyncStatusIbGib>;
99
+ errors: string[],
100
+ warnings: string[],
101
+ }): Promise<void> {
102
+ const lc = `${this.lc}[${this.spinOffToCompleteSync.name}]`;
103
+ errors = errors ?? [];
104
+ warnings = warnings ?? [];
105
+ const verbose = logalot;
106
+ let timeLogName = `[sync_log][${sagaId}][${ibGibs.length}]`;
107
+ if (verbose) { console.time(timeLogName); }
108
+
109
+ try {
110
+ if (verbose) { console.timeLog(timeLogName, `${lc} starting...`); }
111
+
112
+ let statusIbGib = syncStatusIbGib_Start;
113
+ statusIbGib.statusIbGibGraph = statusStartIbGibs;
114
+
115
+ await this.saveInStoreIfConfigAndPublishStatus({ statusIbGib, syncStatus$ });
116
+
117
+ if (verbose) { console.timeLog(timeLogName, 'saveInStoreAndPublishStatus complete'); }
118
+
119
+ const ibGibsToStoreNotAlreadyStored: TIbGib[] = [];
120
+ const updates: { [tjpAddr: string]: IbGibAddr } = {};
121
+
122
+ if (verbose) { console.timeLog(timeLogName, '_getLatestAddrsInStore starting...'); }
123
+ const resLatestAddrsMap = await this._getLatestAddrsInStore(ibGibs);
124
+ if (verbose) { console.timeLog(timeLogName, '_getLatestAddrsInStore complete'); }
125
+
126
+ let { mapWithTjp_YesDna, mapWithTjp_NoDna, mapWithoutTjps } = splitPerTjpAndOrDna({ ibGibs });
127
+ const mapIbGibsWithTjp = { ...mapWithTjp_YesDna, ...mapWithTjp_NoDna };
128
+ const stoneIbGibs: TIbGib[] = Object.values(mapWithoutTjps) as TIbGib[];
129
+ const stoneIbGibsAddrToIbGibMap: { [addr: string]: TIbGib } = {};
130
+ stoneIbGibs.forEach(x => { stoneIbGibsAddrToIbGibMap[getIbGibAddr({ ibGib: x })] = x as TIbGib; });
131
+ const stoneAddrs = Object.keys(stoneIbGibsAddrToIbGibMap);
132
+
133
+ const stoneIbGibsNotInStore: TIbGib[] = stoneIbGibs.filter(x => !resLatestAddrsMap[getIbGibAddr({ ibGib: x })]);
134
+ const stoneAddrsNotInStore = stoneIbGibsNotInStore.map(x => getIbGibAddr({ ibGib: x }));
135
+
136
+ const ibGibsWithTjp = Object.values(mapIbGibsWithTjp);
137
+ const mapIbGibsWithTjpGroupedByTjpAddr = groupBy({
138
+ items: ibGibsWithTjp,
139
+ keyFn: x => getTjpAddr({ ibGib: x })!
140
+ });
141
+ const tjpAddrs = Object.keys(mapIbGibsWithTjpGroupedByTjpAddr);
142
+ if (logalot) { console.timeLog(timeLogName, `tjpAddrs.length: ${tjpAddrs.length}`); }
143
+
144
+ const tjpOrStoneAddrs = [...tjpAddrs,];
145
+ if (stoneAddrsNotInStore.length > 0) {
146
+ tjpOrStoneAddrs.push(stoneAddrsNotInStore.at(0)!);
147
+ } else if (stoneAddrs.length > 0) {
148
+ tjpOrStoneAddrs.push(stoneAddrs.at(0)!);
149
+ }
150
+ if (logalot) { console.timeLog(timeLogName, `tjpOrStoneAddrs.length: ${tjpOrStoneAddrs.length}`); }
151
+
152
+
153
+ for (let i = 0; i < tjpOrStoneAddrs.length; i++) {
154
+ let statusCode: StatusCode;
155
+
156
+ const tjpOrStoneAddr = tjpOrStoneAddrs[i];
157
+ const tjpGib = getIbAndGib({ ibGibAddr: tjpOrStoneAddr }).gib;
158
+
159
+ if (verbose) { console.timeLog(timeLogName, `execInSpaceWithLocking tjpGib: ${tjpGib.slice(0, 16)} starting...`); }
160
+ await execInSpaceWithLocking({
161
+ space: this,
162
+ scope: tjpGib,
163
+ secondsValid: 60 * 5,
164
+ maxDelayMs: 1000 * 60,
165
+ callerInstanceId: sagaId,
166
+ maxLockAttempts: 5,
167
+ fn: async () => {
168
+ const lcFn = `${lc}[fn][${tjpGib.slice(0, 5)}]`;
169
+ const ibGibsToStore_thisIteration: TIbGib[] = [];
170
+ const ibGibsCreated_thisTjp: TIbGib[] = [];
171
+ const ibGibsOnlyInStore_thisTjp: TIbGib[] = [];
172
+ const ibGibsMergeMap_thisTjp: { [oldAddr: string]: TIbGib } = {};
173
+ const latestAddr_Store = resLatestAddrsMap[tjpOrStoneAddr];
174
+ const tjpGroupIbGibs_Local_Ascending: TIbGib[] = tjpAddrs.includes(tjpOrStoneAddr) ?
175
+ mapIbGibsWithTjpGroupedByTjpAddr[tjpOrStoneAddr]
176
+ .filter(x => (x.data?.n ?? -1) >= 0)
177
+ .sort((a, b) => (a.data?.n ?? -1) > (b.data?.n ?? -1) ? 1 : -1) as TIbGib[] :
178
+ [];
179
+
180
+ if (latestAddr_Store) {
181
+ if (tjpAddrs.includes(tjpOrStoneAddr)) {
182
+ const tjpGroupAddrs_Local_Ascending = tjpGroupIbGibs_Local_Ascending.map(x => getIbGibAddr({ ibGib: x }));
183
+ const latestAddr_Local = tjpGroupAddrs_Local_Ascending[tjpGroupAddrs_Local_Ascending.length - 1];
184
+
185
+ if (latestAddr_Store === latestAddr_Local) {
186
+ statusCode = StatusCode.already_synced;
187
+ } else if (tjpGroupAddrs_Local_Ascending.includes(latestAddr_Store)) {
188
+ this.reconcile_UpdateStoreWithMoreRecentLocal({
189
+ tjpAddr: tjpOrStoneAddr,
190
+ latestAddr_Store,
191
+ tjpGroupAddrs_Local_Ascending,
192
+ tjpGroupIbGibs_Local_Ascending,
193
+ ibGibsToStore: ibGibsToStore_thisIteration,
194
+ updates,
195
+ });
196
+ statusCode = StatusCode.updated;
197
+ } else {
198
+ const latestIbGib_Local = tjpGroupIbGibs_Local_Ascending.find(x => getIbGibAddr({ ibGib: x }) === latestAddr_Local)!;
199
+ const latestIbGib_Local_HasDna = (latestIbGib_Local.rel8ns?.dna ?? []).length > 0;
200
+ const resGetStoreIbGib = await this._getIbGibsFromStore([latestAddr_Store]);
201
+ const latestIbGib_Store = resGetStoreIbGib[latestAddr_Store];
202
+
203
+ if (!latestIbGib_Store) { throw new Error(`(UNEXPECTED) latestAddr_Store not found in store: ${latestAddr_Store}`); }
204
+
205
+ const latestIbGib_Store_HasDna = (latestIbGib_Store.rel8ns?.dna ?? []).length > 0;
206
+ if (latestIbGib_Local_HasDna && latestIbGib_Store_HasDna) {
207
+ await this.reconcile_MergeLocalWithStore_ViaDna({
208
+ tjpAddr: tjpOrStoneAddr,
209
+ latestAddr_Local, latestIbGib_Local,
210
+ latestAddr_Store, latestIbGib_Store,
211
+ ibGibsCreated: ibGibsCreated_thisTjp,
212
+ ibGibMergeMap: ibGibsMergeMap_thisTjp,
213
+ ibGibsOnlyInStore: ibGibsOnlyInStore_thisTjp,
214
+ allLocalIbGibs: ibGibs,
215
+ updates,
216
+ timeLogName,
217
+ });
218
+ ibGibsCreated_thisTjp.forEach(x => ibGibsToStore_thisIteration.push(x));
219
+ statusCode = StatusCode.merged_dna;
220
+ } else {
221
+ await this.reconcile_MergeLocalWithStore_ViaState({
222
+ tjpAddr: tjpOrStoneAddr,
223
+ latestIbGib_Local, latestAddr_Local, latestAddr_Store,
224
+ ibGibsCreated: ibGibsCreated_thisTjp,
225
+ ibGibMergeMap: ibGibsMergeMap_thisTjp,
226
+ updates,
227
+ });
228
+ ibGibsCreated_thisTjp.forEach(x => ibGibsToStore_thisIteration.push(x));
229
+ statusCode = StatusCode.merged_state;
230
+ }
231
+ }
232
+ } else {
233
+ statusCode = StatusCode.already_synced;
234
+ }
235
+ } else {
236
+ if (tjpAddrs.includes(tjpOrStoneAddr)) {
237
+ this.reconcile_InsertFirstTimeIntoStore({
238
+ tjpGroupIbGibs_Local_Ascending,
239
+ ibGibsToStore: ibGibsToStore_thisIteration,
240
+ });
241
+ } else {
242
+ stoneAddrsNotInStore.forEach(stoneAddrNotInStore => {
243
+ ibGibsToStore_thisIteration.push(
244
+ stoneIbGibsAddrToIbGibMap[stoneAddrNotInStore]
245
+ );
246
+ });
247
+ }
248
+ statusCode = StatusCode.inserted;
249
+ }
250
+
251
+ const ibGibAddrsForSureAlreadyInStore = Object.values(resLatestAddrsMap);
252
+ for (let i = 0; i < ibGibsToStore_thisIteration.length; i++) {
253
+ const maybeIbGib = ibGibsToStore_thisIteration[i];
254
+ const maybeAddr = getIbGibAddr({ ibGib: maybeIbGib });
255
+ if (!ibGibAddrsForSureAlreadyInStore.includes(maybeAddr) &&
256
+ !ibGibsToStoreNotAlreadyStored.some(x => getIbGibAddr({ ibGib: x }) === maybeAddr)) {
257
+ ibGibsToStoreNotAlreadyStored.push(maybeIbGib);
258
+ }
259
+ }
260
+
261
+ if (ibGibsToStoreNotAlreadyStored.length > 0) {
262
+ await this._putIbGibsToStore(ibGibsToStoreNotAlreadyStored);
263
+ }
264
+
265
+ const ibGibAddrs_DidRxFromLocal = ibGibsToStoreNotAlreadyStored.length > 0 ?
266
+ ibGibsToStoreNotAlreadyStored.map(x => getIbGibAddr({ ibGib: x })) :
267
+ undefined;
268
+ const ibGibAddrsCreated = ibGibsCreated_thisTjp.length > 0 ?
269
+ ibGibsCreated_thisTjp.map(x => getIbGibAddr({ ibGib: x })) :
270
+ undefined;
271
+ const ibGibAddrs_DidTxToLocal = ibGibsOnlyInStore_thisTjp.length > 0 ?
272
+ ibGibsOnlyInStore_thisTjp.map(x => getIbGibAddr({ ibGib: x })) :
273
+ undefined;
274
+ const ibGibAddrsMergeMap: { [oldAddr: string]: IbGibAddr } = {};
275
+ for (const [oldAddr, newIbGib] of Object.entries(ibGibsMergeMap_thisTjp)) {
276
+ ibGibAddrsMergeMap[oldAddr] = getIbGibAddr({ ibGib: newIbGib });
277
+ }
278
+
279
+ const resSyncStatusIbGib = await mut8({
280
+ src: statusIbGib,
281
+ mut8Ib: getStatusIb({
282
+ spaceType: 'sync', spaceSubtype: 'aws-dynamodb', statusCode, sagaId,
283
+ }),
284
+ dataToAddOrPatch: {
285
+ statusCode: statusCode,
286
+ success: true,
287
+ errors: (errors ?? []).length > 0 ? errors.concat() : undefined,
288
+ warnings: (warnings ?? []).length > 0 ? warnings.concat() : undefined,
289
+ didRx: ibGibAddrs_DidRxFromLocal?.concat(),
290
+ didTx: ibGibAddrs_DidTxToLocal?.concat(),
291
+ didCreate: ibGibAddrsCreated?.concat(),
292
+ didMergeMap: ibGibAddrsMergeMap,
293
+ } satisfies Partial<SyncStatusData>,
294
+ dna: false,
295
+ });
296
+
297
+ statusIbGib = resSyncStatusIbGib.newIbGib as SyncStatusIbGib;
298
+ statusIbGib.statusIbGibGraph = resSyncStatusIbGib.intermediateIbGibs ?
299
+ [statusIbGib, ...resSyncStatusIbGib.intermediateIbGibs] :
300
+ [statusIbGib];
301
+ // if (ibGibsCreated_thisTjp.length >)
302
+ // stopped here...need to provide the rest of this code
303
+
304
+ // }
305
+ // });
306
+ // }
307
+ // } catch (error) {
308
+ // console.error(`${lc} ${extractErrorMsg(error)}`);
309
+ // throw error;
310
+ // }
311
+ // }
312
+ if (ibGibsCreated_thisTjp.length > 0) {
313
+ statusIbGib.createdIbGibs = ibGibsCreated_thisTjp.concat();
314
+ }
315
+ if (ibGibsOnlyInStore_thisTjp.length > 0) {
316
+ statusIbGib.storeOnlyIbGibs = ibGibsOnlyInStore_thisTjp.concat();
317
+ }
318
+ if (Object.keys(ibGibsMergeMap_thisTjp).length > 0) {
319
+ statusIbGib.ibGibsMergeMap = ibGibsMergeMap_thisTjp;
320
+ }
321
+
322
+ await this.saveInStoreIfConfigAndPublishStatus({ statusIbGib, syncStatus$ });
323
+
324
+ }, // end of fn for execInSpaceWithLocking
325
+ }); // end of execInSpaceWithLocking
326
+ if (verbose) { console.timeLog(timeLogName, `execInSpaceWithLocking tjpGib: ${tjpGib.slice(0, 16)} complete.`); }
327
+ } // end of for loop
328
+
329
+ if (verbose) { console.timeLog(timeLogName, 'complete saga cleanup starting...'); }
330
+ const statusCode = StatusCode.completed;
331
+ const resSyncStatusIbGib_Complete = await mut8({
332
+ src: statusIbGib,
333
+ mut8Ib: getStatusIb({
334
+ spaceType: 'sync', spaceSubtype: this.data!.subtype!, statusCode, sagaId,
335
+ }),
336
+ dataToAddOrPatch: {
337
+ statusCode,
338
+ success: true,
339
+ errors: (errors ?? []).length > 0 ? errors.concat() : undefined,
340
+ warnings: (warnings ?? []).length > 0 ? warnings.concat() : undefined,
341
+ } satisfies Partial<SyncStatusData>,
342
+ dna: false,
343
+ });
344
+ statusIbGib = resSyncStatusIbGib_Complete.newIbGib as SyncStatusIbGib;
345
+ statusIbGib.statusIbGibGraph = resSyncStatusIbGib_Complete.intermediateIbGibs ?
346
+ [statusIbGib, ...resSyncStatusIbGib_Complete.intermediateIbGibs] :
347
+ [statusIbGib];
348
+
349
+ await this.saveInStoreIfConfigAndPublishStatus({ statusIbGib, syncStatus$ });
350
+
351
+ if (verbose) { console.timeLog(timeLogName, 'complete saga cleanup complete.'); }
352
+
353
+ if (syncStatus$.complete && !syncStatus$.isCompleteOrErrored) {
354
+ if (timeLogName) {
355
+ if (verbose) { console.timeEnd(timeLogName); }
356
+ timeLogName = '';
357
+ }
358
+ await syncStatus$.complete();
359
+ } else {
360
+ console.warn(`(UNEXPECTED) !syncStatus$.complete? this complete handler is expected to be truthy (W: e706de7fa3289194e59bee9ecf96c224)`);
361
+ }
362
+
363
+ } catch (error) {
364
+ const emsg = `${lc} ${extractErrorMsg(error)}`;
365
+ if (verbose) { console.timeLog(timeLogName, `errored. emsg: ${emsg}`); }
366
+ console.error(emsg);
367
+
368
+ if (!syncStatus$.isCompleteOrErrored) {
369
+ if (!syncStatus$.error) { throw new Error(`(UNEXPECTED) !syncStatus$.error? (E: a26bfba7663301986c633c3c2c764824)`); }
370
+ if (timeLogName) {
371
+ if (verbose) { console.timeEnd(timeLogName); }
372
+ timeLogName = '';
373
+ }
374
+ await syncStatus$.error(emsg);
375
+ }
376
+ }
377
+ }
378
+
379
+ protected async saveInStoreIfConfigAndPublishStatus({
380
+ statusIbGib,
381
+ syncStatus$
382
+ }: {
383
+ statusIbGib: SyncStatusIbGib,
384
+ syncStatus$: SubjectWitness<SyncStatusIbGib>
385
+ }): Promise<void> {
386
+ const lc = `${this.lc}[${this.saveInStoreIfConfigAndPublishStatus.name}]`;
387
+ try {
388
+ if ((this.data as any)?.dontStoreStatusUpdatesInSyncSpace) {
389
+ if (logalot) { console.log(`${lc} configured to NOT store status updates in this space. (I: 0166928761a34375b367b61f9d45398d)`); }
390
+ } else {
391
+ if ((statusIbGib.statusIbGibGraph ?? []).length === 0) { throw new Error(`statusIbGib.statusIbGibGraph required. (E: 2a11a84f501243799b66a5b28b76b88b)`); }
392
+ await this._putIbGibsToStore(statusIbGib.statusIbGibGraph! as TIbGib[]);
393
+ }
394
+
395
+ if (syncStatus$.next && !syncStatus$.isCompleteOrErrored) {
396
+ await syncStatus$.next(statusIbGib);
397
+ } else {
398
+ // just warn for now
399
+ console.warn(`${lc} (UNEXPECTED) syncStatus$ subject either does not have a next handler or is already completed/errored. (W: 489a580a563b4f6990264177d6118d53)`);
400
+ }
401
+ } catch (error) {
402
+ const emsg = `${lc} ${extractErrorMsg(error)}`;
403
+ console.error(emsg);
404
+ throw error;
405
+ }
406
+ }
407
+
408
+
409
+ // protected abstract reconcile_UpdateStoreWithMoreRecentLocal(arg: {
410
+ // tjpAddr: IbGibAddr,
411
+ // latestAddr_Store: IbGibAddr,
412
+ // tjpGroupAddrs_Local_Ascending: IbGibAddr[],
413
+ // tjpGroupIbGibs_Local_Ascending: TIbGib[],
414
+ // ibGibsToStore: TIbGib[],
415
+ // updates: { [tjpAddr: string]: IbGibAddr },
416
+ // }): void;
417
+ protected reconcile_UpdateStoreWithMoreRecentLocal({
418
+ tjpAddr,
419
+ latestAddr_Store,
420
+ tjpGroupAddrs_Local_Ascending,
421
+ tjpGroupIbGibs_Local_Ascending,
422
+ ibGibsToStore,
423
+ updates,
424
+ }: {
425
+ tjpAddr: IbGibAddr,
426
+ latestAddr_Store: IbGibAddr,
427
+ tjpGroupAddrs_Local_Ascending: IbGibAddr[],
428
+ tjpGroupIbGibs_Local_Ascending: TIbGib[],
429
+ ibGibsToStore: TIbGib[],
430
+ updates: { [tjpAddr: string]: IbGibAddr },
431
+ }): void {
432
+ const lc = `${this.lc}[${this.reconcile_UpdateStoreWithMoreRecentLocal.name}]`;
433
+ try {
434
+ const lastSyncPoint_Local_Idx = tjpGroupAddrs_Local_Ascending.indexOf(latestAddr_Store);
435
+ if (lastSyncPoint_Local_Idx === -1) { throw new Error(`(UNEXPECTED) latestAddr_Store not found in local ibGibs. latestAddr_Store: ${latestAddr_Store} (E: 8820c754d5d94ab4971d87af48a4369e)`); }
436
+ if (lastSyncPoint_Local_Idx === tjpGroupAddrs_Local_Ascending.length - 1) {
437
+ // we thought we were out of sync, but we are not.
438
+ // this can happen in race conditions.
439
+ console.warn(`${lc} (UNEXPECTED) lastSyncPoint_Local_Idx is latest local ibgib index. This means we are already synced, but somehow thought we weren't. (W: 4927cf51c76a4e2e8509c25f46a9a0f7)`);
440
+ return;
441
+ }
442
+ const ibGibsToUpdate = tjpGroupIbGibs_Local_Ascending.slice(lastSyncPoint_Local_Idx + 1);
443
+ ibGibsToUpdate.forEach(x => ibGibsToStore.push(x));
444
+ updates[tjpAddr] = getIbGibAddr({ ibGib: ibGibsToUpdate[ibGibsToUpdate.length - 1] });
445
+ } catch (error) {
446
+ const emsg = `${lc} ${extractErrorMsg(error)}`;
447
+ console.error(emsg);
448
+ throw error;
449
+ }
450
+ }
451
+
452
+ protected async getDna(arg: {
453
+ ibGib: TIbGib,
454
+ throwOnDnaFail?: boolean,
455
+ }): Promise<TIbGib[]> {
456
+ const lc = `${this.lc}[${this.getDna.name}]`;
457
+ const { ibGib, throwOnDnaFail = true } = arg;
458
+ try {
459
+ const dnaAddrs = ibGib.rel8ns?.dna ?? [];
460
+
461
+ if (dnaAddrs.length === 0) {
462
+ // This would be unexpected for a dna'd ibgib, but we handle it.
463
+ return [];
464
+ }
465
+
466
+ // BATCH fetch all dna ibgibs from the store in a single call.
467
+ // This will return a map of { addr: ibGib }.
468
+ const dnaIbGibsMap = await this._getIbGibsFromStore(dnaAddrs);
469
+
470
+ // The order of the dnaAddrs array *is* the canonical order.
471
+ // We must reconstruct the array in that order from the map.
472
+ const orderedDnaIbGibs = dnaAddrs.map(addr => dnaIbGibsMap[addr]).filter(ibGib => !!ibGib);
473
+
474
+ if (orderedDnaIbGibs.length !== dnaAddrs.length) {
475
+ const emsg = `Mismatch in DNA. Requested ${dnaAddrs.length} addrs but only found ${orderedDnaIbGibs.length}. This may indicate a partial save or data loss. (E: 1ce346ba0fc88b71c6a399282d481825)`;
476
+ if (throwOnDnaFail) {
477
+ throw new Error(emsg);
478
+ } else {
479
+ console.warn(`${lc} ${emsg}`);
480
+ }
481
+ }
482
+
483
+ return orderedDnaIbGibs as TIbGib[];
484
+ } catch (error) {
485
+ const emsg = `${lc} ${extractErrorMsg(error)}`;
486
+ console.error(emsg);
487
+ throw error;
488
+ }
489
+ }
490
+
491
+
492
+ protected async reconcile_MergeLocalWithStore_ViaDna({
493
+ tjpAddr,
494
+ latestAddr_Local,
495
+ latestIbGib_Local,
496
+ latestAddr_Store,
497
+ latestIbGib_Store,
498
+ ibGibsCreated,
499
+ ibGibMergeMap,
500
+ ibGibsOnlyInStore,
501
+ allLocalIbGibs,
502
+ updates,
503
+ timeLogName,
504
+ }: {
505
+ tjpAddr: IbGibAddr,
506
+ latestAddr_Local: IbGibAddr,
507
+ latestIbGib_Local: TIbGib,
508
+ latestAddr_Store: IbGibAddr,
509
+ latestIbGib_Store: TIbGib,
510
+ ibGibsCreated: TIbGib[],
511
+ ibGibsOnlyInStore: TIbGib[],
512
+ ibGibMergeMap: { [oldLatestAddr: string]: TIbGib },
513
+ allLocalIbGibs: TIbGib[],
514
+ updates: { [tjpAddr: string]: IbGibAddr },
515
+ timeLogName: string,
516
+ }): Promise<void> {
517
+ const lc = `${this.lc}[${this.reconcile_MergeLocalWithStore_ViaDna.name}]`;
518
+ const verbose = logalot;
519
+ try {
520
+ if (verbose) { console.timeLog(timeLogName, 'getting full dna timeline for local and store...'); }
521
+ // get full dna timelines for both local and store versions
522
+ // TO THIS:
523
+ const dnaGraph_Local = await this.getDna({ ibGib: latestIbGib_Local });
524
+ const dnaAddrs_Local = dnaGraph_Local.map(x => getIbGibAddr({ ibGib: x }));
525
+ const dnaGraph_Store = await this.getDna({ ibGib: latestIbGib_Store });
526
+ const dnaAddrs_Store = dnaGraph_Store.map(x => getIbGibAddr({ ibGib: x }));
527
+
528
+ // const resGetDna_Local = await this.getDna({ ibGib: latestIbGib_Local, mode: 'all' });
529
+ // const dnaGraph_Local = resGetDna_Local.ibGibs;
530
+ // const dnaAddrs_Local = dnaGraph_Local.map(x => getIbGibAddr({ ibGib: x }));
531
+ // const resGetDna_Store = await this.getDna({ ibGib: latestIbGib_Store, mode: 'all' });
532
+ // const dnaGraph_Store = resGetDna_Store.ibGibs;
533
+ // const dnaAddrs_Store = dnaGraph_Store.map(x => getIbGibAddr({ ibGib: x }));
534
+
535
+ if (verbose) { console.timeLog(timeLogName, 'getting full dna timeline for local and store...complete'); }
536
+
537
+ // find the common ancestor addr, if any.
538
+ // we start from the end of the shorter list and work our way backwards.
539
+ let commonAncestorAddr: IbGibAddr | undefined;
540
+ if (dnaAddrs_Local.length < dnaAddrs_Store.length) {
541
+ for (let i = dnaAddrs_Local.length - 1; i >= 0; i--) {
542
+ const addr = dnaAddrs_Local[i];
543
+ if (dnaAddrs_Store.includes(addr)) {
544
+ commonAncestorAddr = addr;
545
+ break;
546
+ }
547
+ }
548
+ } else {
549
+ for (let i = dnaAddrs_Store.length - 1; i >= 0; i--) {
550
+ const addr = dnaAddrs_Store[i];
551
+ if (dnaAddrs_Local.includes(addr)) {
552
+ commonAncestorAddr = addr;
553
+ break;
554
+ }
555
+ }
556
+ }
557
+ if (!commonAncestorAddr) { throw new Error(`Could not find common ancestor between local and store timelines. Local: ${latestAddr_Local}, Store: ${latestAddr_Store}. This timeline requires manual reconciliation. (E: 49219b101a9f4568bd740d046e30ea2d)`); }
558
+
559
+ const commonAncestorIdx_Local = dnaAddrs_Local.indexOf(commonAncestorAddr);
560
+ const commonAncestorIdx_Store = dnaAddrs_Store.indexOf(commonAncestorAddr);
561
+
562
+ const dnaAddrsToApplyToStoreVersion = dnaAddrs_Local.slice(commonAncestorIdx_Local + 1);
563
+ const dnaAddrsToApplyToLocalVersion = dnaAddrs_Store.slice(commonAncestorIdx_Store + 1);
564
+
565
+ // get the ibGibs that are only in the store and send them to the local client
566
+ if (dnaAddrsToApplyToLocalVersion.length > 0) {
567
+ if (verbose) { console.timeLog(timeLogName, `getting ${dnaAddrsToApplyToLocalVersion.length} ibgibs from store that do not exist locally...`); }
568
+ const resGetIbGibs = await this._getIbGibsFromStore(dnaAddrsToApplyToLocalVersion);
569
+ Object.values(resGetIbGibs).forEach(x => ibGibsOnlyInStore.push(x));
570
+ if (verbose) { console.timeLog(timeLogName, `getting ${dnaAddrsToApplyToLocalVersion.length} ibgibs from store that do not exist locally...complete`); }
571
+ }
572
+
573
+ if (dnaAddrsToApplyToStoreVersion.length > 0) {
574
+ // this is the merge part, where we create new ibgibs that represent the merge
575
+ if (verbose) { console.timeLog(timeLogName, `applying ${dnaAddrsToApplyToStoreVersion.length} transforms from local that do not exist in store...`); }
576
+ const createdIbGibs_Running: TIbGib[] = [];
577
+ const resApply = await applyTransforms({
578
+ src: latestIbGib_Store,
579
+ createdIbGibs_Running,
580
+ dnaAddrsToApplyToStoreVersion,
581
+ allLocalIbGibs,
582
+ }) as TIbGib;
583
+ const mergedIbGib = resApply;
584
+ if (verbose) { console.timeLog(timeLogName, `applying ${dnaAddrsToApplyToStoreVersion.length} transforms from local that do not exist in store...complete`); }
585
+
586
+ if (verbose) { console.timeLog(timeLogName, `applying ${dnaAddrsToApplyToLocalVersion.length} transforms from store that do not exist locally...`); }
587
+ const resApply2 = await applyTransforms({
588
+ src: mergedIbGib,
589
+ createdIbGibs_Running,
590
+ dnaAddrsToApplyToStoreVersion: dnaAddrsToApplyToLocalVersion,
591
+ allLocalIbGibs: ibGibsOnlyInStore,
592
+ }) as TIbGib;
593
+ const finalMergedIbGib = resApply2;
594
+ if (verbose) { console.timeLog(timeLogName, `applying ${dnaAddrsToApplyToLocalVersion.length} transforms from store that do not exist locally...complete`); }
595
+
596
+ // gather all the created ibgibs (including intermediates)
597
+ createdIbGibs_Running.forEach(x => {
598
+ const addr = getIbGibAddr({ ibGib: x });
599
+ if (!ibGibsCreated.some(y => getIbGibAddr({ ibGib: y }) === addr)) {
600
+ ibGibsCreated.push(x);
601
+ }
602
+ });
603
+ const finalMergedAddr = getIbGibAddr({ ibGib: finalMergedIbGib });
604
+ if (!ibGibsCreated.some(y => getIbGibAddr({ ibGib: y }) === finalMergedAddr)) {
605
+ ibGibsCreated.push(finalMergedIbGib);
606
+ }
607
+
608
+ ibGibMergeMap[latestAddr_Local] = finalMergedIbGib;
609
+ ibGibMergeMap[latestAddr_Store] = finalMergedIbGib;
610
+ updates[tjpAddr] = finalMergedAddr;
611
+ }
612
+
613
+ } catch (error) {
614
+ const emsg = `${lc} ${extractErrorMsg(error)}`;
615
+ console.error(emsg);
616
+ throw error;
617
+ }
618
+ }
619
+
620
+ // protected abstract reconcile_MergeLocalWithStore_ViaState(arg: {
621
+ // tjpAddr: IbGibAddr,
622
+ // latestIbGib_Local: TIbGib,
623
+ // latestAddr_Local: IbGibAddr,
624
+ // latestAddr_Store: IbGibAddr,
625
+ // ibGibsCreated: TIbGib[],
626
+ // ibGibMergeMap: { [oldLatestAddr: string]: TIbGib },
627
+ // updates: { [tjpAddr: string]: IbGibAddr },
628
+ // }): Promise<void>;
629
+ protected async reconcile_MergeLocalWithStore_ViaState({
630
+ tjpAddr,
631
+ latestIbGib_Local,
632
+ latestAddr_Local,
633
+ latestAddr_Store,
634
+ ibGibsCreated,
635
+ ibGibMergeMap,
636
+ updates,
637
+ }: {
638
+ tjpAddr: IbGibAddr,
639
+ latestIbGib_Local: TIbGib,
640
+ latestAddr_Local: IbGibAddr,
641
+ latestAddr_Store: IbGibAddr,
642
+ ibGibsCreated: TIbGib[],
643
+ ibGibMergeMap: { [oldLatestAddr: string]: TIbGib },
644
+ updates: { [tjpAddr: string]: IbGibAddr },
645
+ }): Promise<void> {
646
+ const lc = `${this.lc}[${this.reconcile_MergeLocalWithStore_ViaState.name}]`;
647
+ try {
648
+ // we're essentially just creating a new ibgib with the merged data.
649
+ const resMut8 = await mut8({
650
+ src: latestIbGib_Local,
651
+ // we're just going to merge the data properties.
652
+ // this is a naive "last-write-wins" approach for non-dna timelines
653
+ dataToAddOrPatch: { ...latestIbGib_Local.data },
654
+ noTimestamp: true, // we want to control the ib and gib
655
+ });
656
+ const mergedIbGib = resMut8.newIbGib as TIbGib;
657
+ const mergedAddr = getIbGibAddr({ ibGib: mergedIbGib });
658
+ if (resMut8.intermediateIbGibs) {
659
+ resMut8.intermediateIbGibs.forEach(x => ibGibsCreated.push(x as TIbGib));
660
+ }
661
+ ibGibsCreated.push(mergedIbGib);
662
+ ibGibMergeMap[latestAddr_Local] = mergedIbGib;
663
+ ibGibMergeMap[latestAddr_Store] = mergedIbGib;
664
+ updates[tjpAddr] = mergedAddr;
665
+ } catch (error) {
666
+ const emsg = `${lc} ${extractErrorMsg(error)}`;
667
+ console.error(emsg);
668
+ throw error;
669
+ }
670
+ }
671
+
672
+ protected async reconcile_InsertFirstTimeIntoStore({
673
+ tjpGroupIbGibs_Local_Ascending,
674
+ ibGibsToStore,
675
+ }: {
676
+ tjpGroupIbGibs_Local_Ascending: TIbGib[],
677
+ ibGibsToStore: TIbGib[],
678
+ }): Promise<void> {
679
+ const lc = `${this.lc}[${this.reconcile_InsertFirstTimeIntoStore.name}]`;
680
+ try {
681
+ // This is the first time we are seeing this tjp in the store.
682
+ // So we can just add the entire local timeline to the list of
683
+ // ibgibs to be persisted.
684
+ tjpGroupIbGibs_Local_Ascending.forEach(x => ibGibsToStore.push(x));
685
+ } catch (error) {
686
+ const emsg = `${lc} ${extractErrorMsg(error)}`;
687
+ console.error(emsg);
688
+ throw error;
689
+ }
690
+ }
691
+
692
+ // protected async applyTransforms({
693
+ // src,
694
+ // createdIbGibs_Running,
695
+ // dnaAddrsToApplyToStoreVersion,
696
+ // allLocalIbGibs,
697
+ // }: {
698
+ // src: TIbGib,
699
+ // createdIbGibs_Running: TIbGib[],
700
+ // dnaAddrsToApplyToStoreVersion: IbGibAddr[],
701
+ // allLocalIbGibs: TIbGib[],
702
+ // }): Promise<TIbGib> {
703
+ // const lc = `${this.lc}[${this.applyTransforms.name}]`;
704
+ // try {
705
+ // if (logalot) { console.log(`${lc} starting...`); }
706
+
707
+ // let currentSrc = src;
708
+ // // find the dna ibgibs from the local ibgibs that were passed in.
709
+ // const allLocalIbGibsMap = new Map<IbGibAddr, TIbGib>();
710
+ // allLocalIbGibs.forEach(x => allLocalIbGibsMap.set(getIbGibAddr({ ibGib: x }), x));
711
+
712
+ // for (const dnaAddr of dnaAddrsToApplyToStoreVersion) {
713
+ // const dnaIbGib = allLocalIbGibsMap.get(dnaAddr);
714
+ // if (!dnaIbGib) { throw new Error(`(UNEXPECTED) dnaIbGib not found in allLocalIbGibs. addr: ${dnaAddr} (E: 106402377a644e5989710f606e9323ff)`); }
715
+ // const resMut8 = await mut8({
716
+ // src: currentSrc,
717
+ // mut8Ib: dnaIbGib.ib,
718
+ // dataToAddOrPatch: { ...dnaIbGib.data }, // this is a transform, so we just care about data and ib
719
+ // noTimestamp: true,
720
+ // });
721
+
722
+ // currentSrc = resMut8.newIbGib as TIbGib;
723
+ // if (resMut8.intermediateIbGibs) {
724
+ // resMut8.intermediateIbGibs.forEach(x => createdIbGibs_Running.push(x as TIbGib));
725
+ // }
726
+ // createdIbGibs_Running.push(currentSrc);
727
+ // }
728
+
729
+ // return currentSrc;
730
+ // } catch (error) {
731
+ // const emsg = `${lc} ${extractErrorMsg(error)}`;
732
+ // console.error(emsg);
733
+ // throw error;
734
+ // }
735
+ // }
736
+
737
+
738
+ protected async routeAndDoCommand<TCmdModifier extends SyncSpaceOptionsCmdModifier = SyncSpaceOptionsCmdModifier>({
739
+ cmd,
740
+ cmdModifiers,
741
+ arg,
742
+ }: {
743
+ cmd: IbGibSpaceOptionsCmd | string,
744
+ cmdModifiers: (TCmdModifier | string)[],
745
+ arg: TSpaceOptionsIbGib,
746
+ }): Promise<TSpaceResultIbGib | undefined> {
747
+ const lc = `${this.lc}[${this.routeAndDoCommand.name}]`;
748
+ if ((cmdModifiers ?? []).length === 0 || !cmdModifiers.includes('sync')) {
749
+ return super.routeAndDoCommand({ cmd, cmdModifiers, arg });
750
+ }
751
+ switch (cmd) {
752
+ case IbGibSpaceOptionsCmd.put:
753
+ if (cmdModifiers.includes('sync')) {
754
+ if (logalot) { console.log(`${lc} cmd is put and modifier includes sync. Routing to putSync function. (I: 2dc358c88a1746329b379d4e8ba7e09e)`); }
755
+ let resPutSync = await this.putSync(arg as unknown as SyncSpaceOptionsIbGib);
756
+ return resPutSync as unknown as TSpaceResultIbGib;
757
+ } else {
758
+ return super.routeAndDoCommand({ cmd, cmdModifiers, arg });
759
+ }
760
+
761
+ default:
762
+ return super.routeAndDoCommand({ cmd, cmdModifiers, arg });
763
+ }
764
+ }
765
+
766
+ protected async putSync(arg: SyncSpaceOptionsIbGib):
767
+ Promise<IbGibSpaceResultIbGib<TIbGib, IbGibSpaceResultData, IbGibSpaceResultRel8ns>> {
768
+ let lc = `${this.lc}[${this.putSync.name}]`;
769
+ const resultData: TSpaceResultData = { optsAddr: getIbGibAddr({ ibGib: arg }), } as TSpaceResultData;
770
+ let errors: string[] = [];
771
+ let warnings: string[] = [];
772
+ let syncSagaInfo: SyncSagaInfo = arg?.syncSagaInfo;
773
+ const verbose = logalot;
774
+ try {
775
+ // #region validation, initialize some variables
776
+ if (!arg.data) { throw new Error(`arg.data required. (E: 847a1506e7054d53b7bf5ff87a4b32da)`); }
777
+ if ((arg.data.ibGibAddrs ?? []).length === 0) { throw new Error(`arg.data.ibGibAddrs required. (E: 6f2062572cc247f6a12b34759418c66b)`); }
778
+ throwIfDuplicates({ ibGibAddrs: arg.data.ibGibAddrs });
779
+ if (!arg.data.sagaId) { throw new Error(`sagaId required. (E: af30b1b3cf3a4676a89399514743da79)`); }
780
+ const timeLogName = `[sync_log][${arg.data.sagaId}]`;
781
+ if (verbose) { console.timeLog(timeLogName, `${lc} starting...`); }
782
+ if ((arg.ibGibs ?? []).length === 0) { throw new Error(`no ibgibs given. (E: 62ae74eab0434b90b866caa285403143)`); }
783
+ throwIfDuplicates({ ibGibs: arg.ibGibs });
784
+ if (!arg.syncSagaInfo) { throw new Error(`arg.syncSagaInfo required. (E: 33efb28789ff40b9b340eedcba0017f7)`); }
785
+
786
+ if (!arg.syncSagaInfo.spaceId) { throw new Error(`arg.syncSagaInfo.spaceId required. (E: b20f6dbf3c4a466c9ff5aa7488e903ee)`); }
787
+ if ((arg.data.participants ?? []).length === 0) { throw new Error(`arg.data.participants required. (E: 3e8121dc078342d18810a3e2c9671f98)`); }
788
+ if (arg.data.participants!.filter(x => x.s_d === "src").length === 0) { throw new Error(`invalid participants. src required. (E: fbfcab1b8cf34d4a8d51a48a0a43e6af)`); }
789
+ if (arg.data.participants!.filter(x => x.s_d === "src").length > 1) { throw new Error(`invalid participants. only 1 src allowed. (E: 9c2d76ab4dc141ce878de2649a68d4b6)`); }
790
+ if (arg.data.participants!.filter(x => x.s_d === "dest").length === 0) { throw new Error(`invalid participants. at least 1 dest required. (E: 7d037be500844191b25655521eb4cde7)`); }
791
+ const srcSpaceId = arg.data.participants!.filter(p => p.s_d === "src")[0].id;
792
+ if (!srcSpaceId) { throw new Error(`invalid participants. srcSpaceId required. (E: c55c96ebb1c9429fabb0e90adf5ce157)`); }
793
+ if (!this.data) { throw new Error(`(UNEXPECTED) !this.data? (E: 77163b8ffc7f439a8ba8b410db0071e7)`); }
794
+
795
+ // #endregion validation, initialize some variables
796
+
797
+ const { statusIbGib: syncStatusIbGib_Start, statusIbGibsGraph: statusStartIbGibs } =
798
+ await this.getStatusIbGibs_Start({
799
+ sagaId: arg.data.sagaId,
800
+ participants: arg.data.participants!,
801
+ ibGibAddrs: arg.data.ibGibAddrs!,
802
+ });
803
+ (resultData as any).sagaId = arg.data.sagaId;
804
+ if (!syncStatusIbGib_Start.rel8ns?.tjp?.at(0)) { throw new Error(`(UNEXPECTED) !syncStatusIbGib_Start.rel8ns?.tjp?.at(0)? (E: 7ab2b8efb18a446d8695a01cada13c24)`); }
805
+ (resultData as any).statusTjpAddr = syncStatusIbGib_Start.rel8ns.tjp[0];
806
+
807
+ this.spinOffToCompleteSync({
808
+ srcSpaceId,
809
+ sagaId: arg.data.sagaId,
810
+ ibGibs: arg.ibGibs!.concat() as TIbGib[],
811
+ statusStartIbGibs: statusStartIbGibs as TIbGib[],
812
+ syncStatusIbGib_Start,
813
+ syncStatus$: syncSagaInfo.syncStatus$,
814
+ errors,
815
+ warnings,
816
+ });
817
+ } catch (error) {
818
+ console.error(`${lc} error: ${extractErrorMsg(error)}`);
819
+ resultData.errors = [extractErrorMsg(error)];
820
+ }
821
+ try {
822
+ const result = await this.resulty({ resultData });
823
+ (result as any).syncSagaInfo = syncSagaInfo;
824
+ return result;
825
+ } catch (error) {
826
+ console.error(`${lc} ${extractErrorMsg(error)}`);
827
+ throw error;
828
+ }
829
+ }
830
+
831
+ private async getStatusIbGibs_Start({
832
+ sagaId,
833
+ participants,
834
+ ibGibAddrs,
835
+ }: {
836
+ sagaId: string,
837
+ participants: ParticipantInfo[],
838
+ ibGibAddrs: IbGibAddr[],
839
+ }): Promise<{ statusIbGib: SyncStatusIbGib, statusIbGibsGraph: IbGib_V1[] }> {
840
+ const lc = `${this.lc}[${this.getStatusIbGibs_Start.name}]`;
841
+ try {
842
+ if ((participants ?? []).length === 0) { throw new Error(`participants required. (E: a707efcdd7594a4aa70599e84ffa43c4)`); }
843
+
844
+ const parentIb = getStatusIb({
845
+ spaceType: 'sync', spaceSubtype: 'aws-dynamodb',
846
+ statusCode: StatusCode.undefined,
847
+ sagaId: STATUS_UNDEFINED_TX_ID, // "undefined" means '0' atow!!
848
+ });
849
+ const parentIbGib = factory.primitive({ ib: parentIb });
850
+
851
+ const statusCode = StatusCode.started;
852
+ const tjpIb = getStatusIb({
853
+ statusCode,
854
+ spaceType: 'sync', spaceSubtype: 'aws-dynamodb',
855
+ sagaId,
856
+ });
857
+ const data = {
858
+ statusCode: statusCode,
859
+ participants,
860
+ toTx: ibGibAddrs,
861
+ } satisfies SyncStatusData;
862
+ const resTjp = await factory.firstGen({
863
+ parentIbGib,
864
+ ib: tjpIb,
865
+ data,
866
+ dna: false,
867
+ nCounter: true,
868
+ tjp: { uuid: true, timestamp: true },
869
+ });
870
+ const startIbGib = resTjp.newIbGib as SyncStatusIbGib;
871
+ let statusIbGibsGraph: IbGib_V1[] = [
872
+ startIbGib,
873
+ ...(resTjp.intermediateIbGibs ?? []),
874
+ ];
875
+
876
+ return { statusIbGib: startIbGib, statusIbGibsGraph };
877
+ } catch (error) {
878
+ const emsg = `${lc} ${extractErrorMsg(error)}`;
879
+ console.error(emsg);
880
+ throw error;
881
+ }
882
+ }
883
+
884
+ }