@ibgib/core-gib 0.1.20 → 0.1.21
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.
- package/dist/sync/graft-info/graft-info-constants.d.mts +5 -0
- package/dist/sync/graft-info/graft-info-constants.d.mts.map +1 -0
- package/dist/sync/graft-info/graft-info-constants.mjs +5 -0
- package/dist/sync/graft-info/graft-info-constants.mjs.map +1 -0
- package/dist/sync/graft-info/graft-info-helpers.d.mts +49 -0
- package/dist/sync/graft-info/graft-info-helpers.d.mts.map +1 -0
- package/dist/sync/graft-info/graft-info-helpers.mjs +236 -0
- package/dist/sync/graft-info/graft-info-helpers.mjs.map +1 -0
- package/dist/sync/graft-info/graft-info-helpers.respec.d.mts +2 -0
- package/dist/sync/graft-info/graft-info-helpers.respec.d.mts.map +1 -0
- package/dist/sync/graft-info/graft-info-helpers.respec.mjs +70 -0
- package/dist/sync/graft-info/graft-info-helpers.respec.mjs.map +1 -0
- package/dist/sync/graft-info/graft-info-types.d.mts +31 -0
- package/dist/sync/{merge-info/merge-info-types.d.mts.map → graft-info/graft-info-types.d.mts.map} +1 -1
- package/dist/sync/graft-info/graft-info-types.mjs +2 -0
- package/dist/sync/graft-info/graft-info-types.mjs.map +1 -0
- package/dist/sync/strategies/conflict-optimistic.d.mts +1 -1
- package/dist/sync/strategies/conflict-optimistic.d.mts.map +1 -1
- package/dist/sync/strategies/conflict-optimistic.mjs +10 -60
- package/dist/sync/strategies/conflict-optimistic.mjs.map +1 -1
- package/dist/sync/sync-conflict.respec.mjs +152 -33
- package/dist/sync/sync-conflict.respec.mjs.map +1 -1
- package/dist/sync/sync-constants.d.mts +1 -3
- package/dist/sync/sync-constants.d.mts.map +1 -1
- package/dist/sync/sync-constants.mjs +0 -2
- package/dist/sync/sync-constants.mjs.map +1 -1
- package/dist/sync/sync-peer/sync-peer-innerspace-v1.d.mts +5 -2
- package/dist/sync/sync-peer/sync-peer-innerspace-v1.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-innerspace-v1.mjs +70 -7
- package/dist/sync/sync-peer/sync-peer-innerspace-v1.mjs.map +1 -1
- package/dist/sync/sync-saga-coordinator.d.mts +25 -18
- package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
- package/dist/sync/sync-saga-coordinator.mjs +508 -316
- package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
- package/dist/sync/sync-saga-message/sync-saga-message-helpers.d.mts.map +1 -1
- package/dist/sync/sync-saga-message/sync-saga-message-helpers.mjs +1 -0
- package/dist/sync/sync-saga-message/sync-saga-message-helpers.mjs.map +1 -1
- package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts +1 -12
- package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts.map +1 -1
- package/ibgib-foundations.md +20 -2
- package/package.json +1 -1
- package/src/sync/graft-info/graft-info-constants.mts +4 -0
- package/src/sync/graft-info/graft-info-helpers.mts +308 -0
- package/src/sync/graft-info/graft-info-helpers.respec.mts +83 -0
- package/src/sync/graft-info/graft-info-types.mts +33 -0
- package/src/sync/strategies/conflict-optimistic.mts +11 -70
- package/src/sync/sync-conflict.respec.mts +171 -35
- package/src/sync/sync-constants.mts +1 -4
- package/src/sync/sync-peer/sync-peer-innerspace-v1.mts +85 -12
- package/src/sync/sync-saga-coordinator.mts +569 -338
- package/src/sync/sync-saga-message/sync-saga-message-helpers.mts +2 -0
- package/src/sync/sync-saga-message/sync-saga-message-types.mts +0 -11
- package/test_output.log +0 -0
- package/tmp.md +43 -2
- package/dist/sync/merge-info/merge-info-constants.d.mts +0 -2
- package/dist/sync/merge-info/merge-info-constants.d.mts.map +0 -1
- package/dist/sync/merge-info/merge-info-constants.mjs +0 -2
- package/dist/sync/merge-info/merge-info-constants.mjs.map +0 -1
- package/dist/sync/merge-info/merge-info-helpers.d.mts +0 -51
- package/dist/sync/merge-info/merge-info-helpers.d.mts.map +0 -1
- package/dist/sync/merge-info/merge-info-helpers.mjs +0 -92
- package/dist/sync/merge-info/merge-info-helpers.mjs.map +0 -1
- package/dist/sync/merge-info/merge-info-helpers.respec.d.mts +0 -2
- package/dist/sync/merge-info/merge-info-helpers.respec.d.mts.map +0 -1
- package/dist/sync/merge-info/merge-info-helpers.respec.mjs +0 -32
- package/dist/sync/merge-info/merge-info-helpers.respec.mjs.map +0 -1
- package/dist/sync/merge-info/merge-info-types.d.mts +0 -26
- package/dist/sync/merge-info/merge-info-types.mjs +0 -2
- package/dist/sync/merge-info/merge-info-types.mjs.map +0 -1
- package/src/sync/merge-info/merge-info-constants.mts +0 -1
- package/src/sync/merge-info/merge-info-helpers.mts +0 -134
- package/src/sync/merge-info/merge-info-helpers.respec.mts +0 -41
- package/src/sync/merge-info/merge-info-types.mts +0 -28
|
@@ -21,9 +21,12 @@ import { createTimelineRootHelper, getTestKeystoneServiceHelper } from '../agent
|
|
|
21
21
|
import { mut8Timeline } from '../timeline/timeline-api.mjs';
|
|
22
22
|
import { SyncPeerInnerspace_V1 } from './sync-peer/sync-peer-innerspace-v1.mjs';
|
|
23
23
|
import { DEFAULT_INNER_SPACE_DATA_V1 } from '../witness/space/inner-space/inner-space-types.mjs';
|
|
24
|
-
import { toDto } from '../common/other/ibgib-helper.mjs';
|
|
24
|
+
import { getTjpAddr, toDto } from '../common/other/ibgib-helper.mjs';
|
|
25
25
|
import { SyncConflictStrategy, SyncSagaInfo } from './sync-types.mjs';
|
|
26
|
-
import { IbGibData_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
|
|
26
|
+
import { IbGibData_V1, IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
|
|
27
|
+
import { fnObs } from '../common/pubsub/observer/observer-helper.mjs';
|
|
28
|
+
import { getDependencyGraph } from '../common/other/graph-helper.mjs';
|
|
29
|
+
import { ErrorIbGib_V1 } from '../common/error/error-types.mjs';
|
|
27
30
|
|
|
28
31
|
interface TestData extends IbGibData_V1 {
|
|
29
32
|
text?: string;
|
|
@@ -71,28 +74,40 @@ await respecfully(sir, `Sync Conflict Resolution`, async () => {
|
|
|
71
74
|
|
|
72
75
|
// 2. Seed Common History (V0 -> V1)
|
|
73
76
|
console.log(`${lc} Creating Common History...`);
|
|
74
|
-
const
|
|
77
|
+
const testRoot = await createTimelineRootHelper<TestData>({
|
|
75
78
|
ib: 'timeline_root',
|
|
76
|
-
data: { type: '
|
|
79
|
+
data: { type: 'testRoot', text: 'v0' },
|
|
77
80
|
space: sourceSpace,
|
|
78
81
|
});
|
|
79
|
-
// Sync root to dest immediately so they start synced
|
|
80
|
-
await metaspace.put({ ibGib: root, space: destSpace });
|
|
81
|
-
await metaspace.registerNewIbGib({ ibGib: root, space: destSpace });
|
|
82
|
-
|
|
83
|
-
|
|
84
82
|
// Create V1 (Common)
|
|
85
|
-
const
|
|
86
|
-
timeline:
|
|
83
|
+
const v1_Common = await mut8Timeline<TestData>({
|
|
84
|
+
timeline: testRoot,
|
|
87
85
|
mut8Opts: { dataToAddOrPatch: { text: 'v1_common' } },
|
|
88
86
|
metaspace,
|
|
89
87
|
space: sourceSpace,
|
|
90
88
|
});
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
89
|
+
const tjpAddr =
|
|
90
|
+
getTjpAddr({ ibGib: testRoot, defaultIfNone: 'incomingAddr' }) ??
|
|
91
|
+
getIbGibAddr({ ibGib: testRoot });
|
|
92
|
+
console.log(`${lc} [TEST DEBUG] tjpAddr: ${tjpAddr}`)
|
|
93
|
+
// Sync testRoot to dest immediately so they start synced
|
|
94
|
+
// must get the entire dependency graph for testRoot
|
|
95
|
+
const depGraph_testRootAndV1Common = await getDependencyGraph({
|
|
96
|
+
ibGibAddrs: [tjpAddr],
|
|
97
|
+
space: sourceSpace,
|
|
98
|
+
live: true,
|
|
99
|
+
}) ?? {};
|
|
100
|
+
console.log(`${lc} depGraph_testRootAndV1Common: ${pretty(depGraph_testRootAndV1Common)}`)
|
|
101
|
+
if (Object.keys(depGraph_testRootAndV1Common).length === 0) {
|
|
102
|
+
throw new Error(`(UNEXPECTED) depGraph_testRootAndV1Common empty? (E: 39b4d855ffa65476084b4123786da826)`);
|
|
103
|
+
}
|
|
104
|
+
// put the entire graph into the destspace, but...
|
|
105
|
+
await metaspace.put({ ibGibs: Object.values(depGraph_testRootAndV1Common), space: destSpace });
|
|
106
|
+
// ...only register the main ibgibs
|
|
107
|
+
await metaspace.registerNewIbGib({ ibGib: testRoot, space: destSpace });
|
|
108
|
+
await metaspace.registerNewIbGib({ ibGib: v1_Common, space: destSpace });
|
|
94
109
|
|
|
95
|
-
const resGetDest = await getFromSpace({ space: destSpace, addr: getIbGibAddr({ ibGib:
|
|
110
|
+
const resGetDest = await getFromSpace({ space: destSpace, addr: getIbGibAddr({ ibGib: v1_Common }) });
|
|
96
111
|
if (!resGetDest.success || !resGetDest.ibGibs || resGetDest.ibGibs.length === 0) {
|
|
97
112
|
throw new Error(`Failed to retrieve v1_Dest from destSpace. (E: a1b2c3d4e5f6g7h8i9j0)`);
|
|
98
113
|
}
|
|
@@ -104,7 +119,7 @@ await respecfully(sir, `Sync Conflict Resolution`, async () => {
|
|
|
104
119
|
|
|
105
120
|
// Source: V1 -> V2a (Edit Field A)
|
|
106
121
|
const v2a = await mut8Timeline<TestData>({
|
|
107
|
-
timeline:
|
|
122
|
+
timeline: v1_Common,
|
|
108
123
|
mut8Opts: { dataToAddOrPatch: { fieldA: 'source_edit' } },
|
|
109
124
|
metaspace,
|
|
110
125
|
space: sourceSpace,
|
|
@@ -119,9 +134,6 @@ await respecfully(sir, `Sync Conflict Resolution`, async () => {
|
|
|
119
134
|
});
|
|
120
135
|
|
|
121
136
|
// Verify Divergence
|
|
122
|
-
const tjpAddr = root.rel8ns!.tjp![0]; // wait, root IS tjp, so no tjp rel8n...
|
|
123
|
-
// Actually root frame has isTjp: true.
|
|
124
|
-
// v1 has tjp: [v0_gib].
|
|
125
137
|
console.log(`${lc} Divergence created.`);
|
|
126
138
|
|
|
127
139
|
|
|
@@ -131,27 +143,53 @@ await respecfully(sir, `Sync Conflict Resolution`, async () => {
|
|
|
131
143
|
const senderCoordinator = new SyncSagaCoordinator(mockKeystone);
|
|
132
144
|
const receiverCoordinator = new SyncSagaCoordinator(mockKeystone);
|
|
133
145
|
|
|
146
|
+
|
|
147
|
+
// Create sender's tempSpace for transactional payload transfer
|
|
148
|
+
const senderTempSpaceName = `tmp_sender_test_${Date.now()}`;
|
|
149
|
+
const senderTempSpace = await metaspace.createNewLocalSpace({
|
|
150
|
+
opts: {
|
|
151
|
+
allowCancel: false,
|
|
152
|
+
spaceName: senderTempSpaceName,
|
|
153
|
+
getFnPrompt: metaspace.getFnPrompt!,
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
if (!senderTempSpace) { throw new Error(`(UNEXPECTED) senderTempSpace falsy? (E: ef4388c87e98f0211852eefa22414f26)`); }
|
|
157
|
+
await senderTempSpace.initialized;
|
|
158
|
+
|
|
134
159
|
const peer = new SyncPeerInnerspace_V1({
|
|
135
160
|
senderSpace: sourceSpace,
|
|
161
|
+
senderTempSpace, // Pass sender's tempSpace for payload transfer
|
|
136
162
|
receiverSpace: destSpace,
|
|
137
163
|
receiverCoordinator,
|
|
138
164
|
receiverMetaspace: metaspace,
|
|
139
165
|
});
|
|
166
|
+
await peer.initialized;
|
|
140
167
|
|
|
141
168
|
// Verify Receiver has correct KV (Pre-Sync Check)
|
|
142
169
|
// This ensures the conflict precondition exists.
|
|
143
|
-
await
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
170
|
+
await ifWeMight(sir, 'verify receiver KV pre-sync', async () => {
|
|
171
|
+
try {
|
|
172
|
+
const destKV = await receiverCoordinator.getKnowledgeVector({
|
|
173
|
+
space: destSpace,
|
|
174
|
+
metaspace,
|
|
175
|
+
domainIbGibs: [v1_Dest]
|
|
176
|
+
});
|
|
177
|
+
const v1TjpAddr = getTjpAddr({ ibGib: v1_Dest, defaultIfNone: 'incomingAddr' }) ?? getIbGibAddr({ ibGib: v1_Dest });
|
|
178
|
+
console.log(`[TEST DEBUG] v1_Dest: ${JSON.stringify(v1_Dest)}`);
|
|
179
|
+
console.log(`[TEST DEBUG] v1TjpAddr: ${v1TjpAddr}`);
|
|
180
|
+
console.log(`[TEST DEBUG] destKV: ${JSON.stringify(destKV)}`);
|
|
181
|
+
console.log(`[TEST DEBUG] v1_Dest.rel8ns.tjp: ${v1_Dest.rel8ns?.tjp?.join(', ')}`);
|
|
182
|
+
|
|
183
|
+
// Actually v1 has tjp rel8n.
|
|
184
|
+
const destTip = destKV[v1TjpAddr];
|
|
185
|
+
iReckon(sir, !!destTip).asTo(`Dest KV has timeline tip for ${v1TjpAddr}`).isGonnaBeTruthy();
|
|
186
|
+
if (!destTip) {
|
|
187
|
+
throw new Error(`Test Setup Fail: Dest Space does not have index for timeline ${v1TjpAddr}. Seeding failed. (E: c194a80b4e4877b77826c37a1753b826)`);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
} catch (error) {
|
|
191
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
192
|
+
iReckon(sir, true).asTo('getKnowledgeVector errored out').isGonnaBeFalse();
|
|
155
193
|
}
|
|
156
194
|
});
|
|
157
195
|
|
|
@@ -171,7 +209,31 @@ await respecfully(sir, `Sync Conflict Resolution`, async () => {
|
|
|
171
209
|
// explicit useSessionIdentity: true is default
|
|
172
210
|
});
|
|
173
211
|
|
|
212
|
+
const sublc = `${lc}[updates$]`;
|
|
213
|
+
/**
|
|
214
|
+
* I have added this so you can see how to subscribe to an ibgib
|
|
215
|
+
* observable using {@link fnObs}.
|
|
216
|
+
*/
|
|
217
|
+
const subscription = await resSync.updates$.subscribe(fnObs({
|
|
218
|
+
next: async (ctxIbGib) => {
|
|
219
|
+
console.log(`${sublc} next fired. ${pretty(ctxIbGib)}`);
|
|
220
|
+
},
|
|
221
|
+
error: async (e: ErrorIbGib_V1) => {
|
|
222
|
+
if (e.data) {
|
|
223
|
+
console.error(`${sublc} error fired. error: ${JSON.stringify(e.data)} (E: 01cc08ba05ad99682831174fd7c31a26)`);
|
|
224
|
+
} else {
|
|
225
|
+
console.dir(e);
|
|
226
|
+
console.error(`${sublc} error fired. error: ${extractErrorMsg(e)} (E: 73d3d61464e8e4ce4cd6efd8b9675826)`);
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
complete: async () => {
|
|
230
|
+
console.log(`${sublc} complete fired`);
|
|
231
|
+
},
|
|
232
|
+
}));
|
|
233
|
+
|
|
234
|
+
console.log(`${lc} awaiting resSync.done`)
|
|
174
235
|
await resSync.done;
|
|
236
|
+
|
|
175
237
|
console.log(`${lc} Sync Complete.`);
|
|
176
238
|
} catch (e) {
|
|
177
239
|
console.error(`${lc} Sync Failed with Error:`, e);
|
|
@@ -184,10 +246,84 @@ await respecfully(sir, `Sync Conflict Resolution`, async () => {
|
|
|
184
246
|
|
|
185
247
|
const resSourceTip = await getFromSpace({ space: sourceSpace, addr: getIbGibAddr({ ibGib: v2a }) });
|
|
186
248
|
|
|
187
|
-
await
|
|
188
|
-
//
|
|
189
|
-
//
|
|
190
|
-
|
|
249
|
+
await ifWeMight(sir, `verify merge happened`, async () => {
|
|
250
|
+
// Retrieve updated KV from Source (or check what happened to v2a)
|
|
251
|
+
// Ideally, we just check the source space for the timeline tip
|
|
252
|
+
// The timeline tip for testRoot/v0 should now be NEW.
|
|
253
|
+
|
|
254
|
+
try {
|
|
255
|
+
// Get the KV for the Source Space
|
|
256
|
+
const sourceKV = await senderCoordinator.getKnowledgeVector({
|
|
257
|
+
space: sourceSpace,
|
|
258
|
+
metaspace,
|
|
259
|
+
domainIbGibs: [testRoot] // We want to know the tip of this timeline
|
|
260
|
+
});
|
|
261
|
+
const tjpAddr =
|
|
262
|
+
getTjpAddr({ ibGib: testRoot, defaultIfNone: 'incomingAddr' }) ??
|
|
263
|
+
getIbGibAddr({ ibGib: testRoot });
|
|
264
|
+
|
|
265
|
+
if (logalot) { console.log(`${lc} getKnowledgeVector returned. sourceKV: ${pretty(sourceKV)} (I: e8780cda37c8b2a46eeb85786874e926)`); }
|
|
266
|
+
|
|
267
|
+
const sourceTipAddr = sourceKV[tjpAddr];
|
|
268
|
+
if (!sourceTipAddr) {
|
|
269
|
+
throw new Error(`Source Space missing timeline tip for ${tjpAddr} (E: ec95980b9c980c5c5870812e15e43826)`);
|
|
270
|
+
}
|
|
271
|
+
console.log(`${lc} [TEST DEBUG] sourceTipAddr: ${sourceTipAddr}`);
|
|
272
|
+
console.log(`${lc} [TEST DEBUG] v2a: ${getIbGibAddr({ ibGib: v2a })}`);
|
|
273
|
+
console.log(`${lc} [TEST DEBUG] v2b: ${getIbGibAddr({ ibGib: v2b })}`);
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
iReckon(sir, sourceTipAddr).asTo(`Source Tip (${sourceTipAddr}) should NOT be v2a`).not.isGonnaBe(getIbGibAddr({ ibGib: v2a }));
|
|
277
|
+
iReckon(sir, sourceTipAddr).asTo(`Source Tip (${sourceTipAddr}) should NOT be v2b`).not.isGonnaBe(getIbGibAddr({ ibGib: v2b }));
|
|
278
|
+
|
|
279
|
+
// Fetch the new tip
|
|
280
|
+
const resTip = await getFromSpace({ space: sourceSpace, addr: sourceTipAddr });
|
|
281
|
+
const newTip = resTip.ibGibs![0] as IbGib_V1<TestData>;
|
|
282
|
+
console.log(`${lc} [TEST DEBUG] newTip: ${JSON.stringify(newTip)}`);
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
// Check Data: Should have BOTH edits
|
|
286
|
+
iReckon(sir, newTip.data!.fieldA).asTo('New Tip Data Field A').isGonnaBe('source_edit');
|
|
287
|
+
iReckon(sir, newTip.data!.fieldB).asTo('New Tip Data Field B').isGonnaBe('dest_edit');
|
|
288
|
+
|
|
289
|
+
// Check Graft Structure
|
|
290
|
+
// Look for 'graftinfo' rel8n
|
|
291
|
+
const graftInfoRel = newTip.rel8ns?.graftinfo;
|
|
292
|
+
iReckon(sir, graftInfoRel).asTo('New Tip should have graftinfo rel8n').isGonnaBeTruthy();
|
|
293
|
+
if (graftInfoRel) {
|
|
294
|
+
iReckon(sir, graftInfoRel!.length).asTo('Only 1 graftinfo').isGonnaBe(1);
|
|
295
|
+
|
|
296
|
+
// Fetch Graft Info Stone
|
|
297
|
+
const resGraft = await getFromSpace({ space: sourceSpace, addr: graftInfoRel![0] });
|
|
298
|
+
const graftInfo = resGraft.ibGibs![0];
|
|
299
|
+
console.log(`${lc} [TEST DEBUG] graftInfo: ${JSON.stringify(graftInfo)}`);
|
|
300
|
+
|
|
301
|
+
// Check Graft Relations (graftbase, graftorphan)
|
|
302
|
+
const baseRel = graftInfo.rel8ns?.graftbase;
|
|
303
|
+
const orphanRel = graftInfo.rel8ns?.graftorphan;
|
|
304
|
+
|
|
305
|
+
iReckon(sir, baseRel).asTo('Graft Base exists').isGonnaBeTruthy();
|
|
306
|
+
iReckon(sir, orphanRel).asTo('Graft Orphan exists').isGonnaBeTruthy();
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
// Verify Base/Orphan identity (one should be v2a, one v2b)
|
|
310
|
+
const addrV2a = getIbGibAddr({ ibGib: v2a });
|
|
311
|
+
const addrV2b = getIbGibAddr({ ibGib: v2b });
|
|
312
|
+
|
|
313
|
+
const bases = baseRel || [];
|
|
314
|
+
const orphans = orphanRel || [];
|
|
315
|
+
|
|
316
|
+
const isV2aInvolved = bases.includes(addrV2a) || orphans.includes(addrV2a);
|
|
317
|
+
const isV2bInvolved = bases.includes(addrV2b) || orphans.includes(addrV2b);
|
|
318
|
+
|
|
319
|
+
iReckon(sir, isV2aInvolved).asTo('V2a is involved in graft').isGonnaBeTrue();
|
|
320
|
+
iReckon(sir, isV2bInvolved).asTo('V2b is involved in graft').isGonnaBeTrue();
|
|
321
|
+
}
|
|
322
|
+
} catch (error) {
|
|
323
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
324
|
+
iReckon(sir, true).asTo('getKnowledgeVector errored out').isGonnaBeFalse();
|
|
325
|
+
}
|
|
326
|
+
|
|
191
327
|
});
|
|
192
328
|
});
|
|
193
329
|
|
|
@@ -13,15 +13,13 @@ export const SYNC_STAGE_ACK = "ack";
|
|
|
13
13
|
export const SYNC_STAGE_REQUEST = "request";
|
|
14
14
|
export const SYNC_STAGE_DELTA = "delta";
|
|
15
15
|
export const SYNC_STAGE_COMMIT = "commit";
|
|
16
|
-
export const SYNC_STAGE_CONFLICT = "conflict";
|
|
17
16
|
|
|
18
17
|
export type SyncStage =
|
|
19
18
|
| typeof SYNC_STAGE_INIT
|
|
20
19
|
| typeof SYNC_STAGE_ACK
|
|
21
20
|
| typeof SYNC_STAGE_REQUEST
|
|
22
21
|
| typeof SYNC_STAGE_DELTA
|
|
23
|
-
| typeof SYNC_STAGE_COMMIT
|
|
24
|
-
| typeof SYNC_STAGE_CONFLICT;
|
|
22
|
+
| typeof SYNC_STAGE_COMMIT;
|
|
25
23
|
|
|
26
24
|
export const SyncStage = {
|
|
27
25
|
init: SYNC_STAGE_INIT,
|
|
@@ -29,5 +27,4 @@ export const SyncStage = {
|
|
|
29
27
|
request: SYNC_STAGE_REQUEST,
|
|
30
28
|
delta: SYNC_STAGE_DELTA,
|
|
31
29
|
commit: SYNC_STAGE_COMMIT,
|
|
32
|
-
conflict: SYNC_STAGE_CONFLICT,
|
|
33
30
|
} as const;
|
|
@@ -7,20 +7,22 @@ import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
|
|
|
7
7
|
import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
|
|
8
8
|
|
|
9
9
|
import { GLOBAL_LOG_A_LOT } from '../../core-constants.mjs';
|
|
10
|
-
import { SYNC_ATOM } from '../sync-constants.mjs';
|
|
10
|
+
import { SYNC_ATOM, SYNC_MSG_REL8N_NAME } from '../sync-constants.mjs';
|
|
11
11
|
import { IbGibSpaceAny } from '../../witness/space/space-base-v1.mjs';
|
|
12
|
-
import { SyncSagaContextIbGib_V1 } from '../sync-saga-context/sync-saga-context-types.mjs';
|
|
13
|
-
import { SyncPeer_V1 } from './sync-peer-v1.mjs';
|
|
14
12
|
import { SyncSagaCoordinator } from '../sync-saga-coordinator.mjs';
|
|
15
|
-
import { createSyncSagaContext } from '../sync-saga-context/sync-saga-context-helpers.mjs';
|
|
16
|
-
import { getFromSpace, putInSpace } from '../../witness/space/space-helper.mjs';
|
|
17
13
|
import { MetaspaceService } from '../../witness/space/metaspace/metaspace-types.mjs';
|
|
14
|
+
import { SyncPeer_V1 } from './sync-peer-v1.mjs';
|
|
15
|
+
import { getFromSpace, putInSpace } from '../../witness/space/space-helper.mjs';
|
|
16
|
+
import { SyncSagaContextIbGib_V1 } from '../sync-saga-context/sync-saga-context-types.mjs';
|
|
17
|
+
import { createSyncSagaContext } from '../sync-saga-context/sync-saga-context-helpers.mjs';
|
|
18
18
|
|
|
19
19
|
export interface SyncPeerInnerspaceOptions {
|
|
20
|
-
senderSpace: IbGibSpaceAny;
|
|
21
|
-
|
|
20
|
+
senderSpace: IbGibSpaceAny; // Durable space for audit trail
|
|
21
|
+
senderTempSpace?: IbGibSpaceAny; // Transactional space - will use if provided
|
|
22
|
+
receiverSpace: IbGibSpaceAny; // Durable space for receiver audit trail
|
|
22
23
|
receiverCoordinator: SyncSagaCoordinator;
|
|
23
24
|
receiverMetaspace: MetaspaceService; // Need this for receiver execution
|
|
25
|
+
receiverTempSpace?: IbGibSpaceAny; // Optional: will be created if not provided
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
const logalot = GLOBAL_LOG_A_LOT || true;
|
|
@@ -41,6 +43,26 @@ export class SyncPeerInnerspace_V1 extends SyncPeer_V1 {
|
|
|
41
43
|
super(opts.receiverSpace.data!); // Use receiver space data as initial phantom data? Or empty.
|
|
42
44
|
}
|
|
43
45
|
|
|
46
|
+
private async ensureReceiverTempSpace(): Promise<IbGibSpaceAny> {
|
|
47
|
+
if (!this.opts.receiverTempSpace) {
|
|
48
|
+
const { receiverMetaspace } = this.opts;
|
|
49
|
+
const uuid = crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36);
|
|
50
|
+
const tempSpaceName = `tmp_sync_recv_${uuid.substring(0, 8)}`;
|
|
51
|
+
this.opts.receiverTempSpace = await receiverMetaspace.createNewLocalSpace({
|
|
52
|
+
opts: {
|
|
53
|
+
allowCancel: false,
|
|
54
|
+
spaceName: tempSpaceName,
|
|
55
|
+
getFnPrompt: receiverMetaspace.getFnPrompt!,
|
|
56
|
+
logalot
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
if (this.opts.receiverTempSpace) {
|
|
60
|
+
await this.opts.receiverTempSpace.initialized;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return this.opts.receiverTempSpace!; // Non-null assertion since we just created it
|
|
64
|
+
}
|
|
65
|
+
|
|
44
66
|
protected async getLocalIbGib(addr: string): Promise<IbGib_V1 | undefined> {
|
|
45
67
|
const res = await getFromSpace({ space: this.opts.senderSpace, addr });
|
|
46
68
|
return res.ibGibs?.[0];
|
|
@@ -69,6 +91,27 @@ export class SyncPeerInnerspace_V1 extends SyncPeer_V1 {
|
|
|
69
91
|
const sagaFrame = resFrame.ibGibs?.[0] as any;
|
|
70
92
|
if (!sagaFrame) { throw new Error(`${lc} sagaFrame not found in receiver space: ${sagaFrameAddr} (E: 2c0190bd04ea408c909618193850029b)`); }
|
|
71
93
|
|
|
94
|
+
// Ensure receiverTempSpace exists
|
|
95
|
+
const receiverTempSpace = await this.ensureReceiverTempSpace();
|
|
96
|
+
|
|
97
|
+
// Store saga frame in tempSpace for easy queries during transaction
|
|
98
|
+
// (Control ibgibs like saga frames and msg stones go in BOTH spaces:
|
|
99
|
+
// destSpace for audit trail, tempSpace for easy queries)
|
|
100
|
+
await putInSpace({ space: receiverTempSpace, ibGib: sagaFrame });
|
|
101
|
+
await receiverMetaspace.registerNewIbGib({ ibGib: sagaFrame });
|
|
102
|
+
|
|
103
|
+
// Also store the message stone (if present) in tempSpace
|
|
104
|
+
const msgStoneAddrs = sagaFrame.rel8ns?.[SYNC_MSG_REL8N_NAME];
|
|
105
|
+
if (msgStoneAddrs && msgStoneAddrs.length > 0) {
|
|
106
|
+
const resMsgStone = await getFromSpace({ space: receiverSpace, addrs: msgStoneAddrs });
|
|
107
|
+
if (resMsgStone.ibGibs) {
|
|
108
|
+
for (const msgStone of resMsgStone.ibGibs) {
|
|
109
|
+
await putInSpace({ space: receiverTempSpace, ibGib: msgStone });
|
|
110
|
+
await receiverMetaspace.registerNewIbGib({ ibGib: msgStone });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
72
115
|
// 2. Execute Receiver Logic
|
|
73
116
|
// The Peer "Network" triggers the Receiver Coordinator.
|
|
74
117
|
if (logalot) { console.log(`${lc} Invoking Receiver Coordinator...`); }
|
|
@@ -78,7 +121,8 @@ export class SyncPeerInnerspace_V1 extends SyncPeer_V1 {
|
|
|
78
121
|
const result = await receiverCoordinator.handleSagaFrame({
|
|
79
122
|
sagaIbGib: sagaFrame,
|
|
80
123
|
srcGraph: {},
|
|
81
|
-
|
|
124
|
+
destSpace: receiverSpace, // Query existing data
|
|
125
|
+
tempSpace: receiverTempSpace, // Transaction space
|
|
82
126
|
metaspace: receiverMetaspace,
|
|
83
127
|
});
|
|
84
128
|
|
|
@@ -91,10 +135,31 @@ export class SyncPeerInnerspace_V1 extends SyncPeer_V1 {
|
|
|
91
135
|
|
|
92
136
|
if (logalot) { console.log(`${lc} responseFrame addr: ${getIbGibAddr({ ibGib: responseFrame })}`); }
|
|
93
137
|
|
|
94
|
-
// 3. Persist Response
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
|
|
138
|
+
// 3. Persist Response Control IbGibs (Frame + Msg Stones) to BOTH Spaces
|
|
139
|
+
// Control ibgibs (saga frames, msg stones, identity) go in BOTH spaces:
|
|
140
|
+
// - receiverSpace (destSpace): Audit trail
|
|
141
|
+
// - receiverTempSpace: Already there from creation in tempSpace
|
|
142
|
+
|
|
143
|
+
// Ensure response frame is in receiverSpace for audit trail
|
|
144
|
+
await putInSpace({ space: receiverSpace, ibGib: responseFrame });
|
|
145
|
+
await receiverMetaspace.registerNewIbGib({ ibGib: responseFrame });
|
|
146
|
+
|
|
147
|
+
// Ensure response msg stone is in receiverSpace for audit trail
|
|
148
|
+
const responseMsgStoneAddrs = responseFrame.rel8ns?.[SYNC_MSG_REL8N_NAME];
|
|
149
|
+
if (responseMsgStoneAddrs && responseMsgStoneAddrs.length > 0) {
|
|
150
|
+
const resResponseMsgStone = await getFromSpace({ space: receiverTempSpace, addrs: responseMsgStoneAddrs });
|
|
151
|
+
if (resResponseMsgStone.ibGibs) {
|
|
152
|
+
for (const msgStone of resResponseMsgStone.ibGibs) {
|
|
153
|
+
await putInSpace({ space: receiverSpace, ibGib: msgStone });
|
|
154
|
+
await receiverMetaspace.registerNewIbGib({ ibGib: msgStone });
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// 4. Persist Domain Payload IbGibs
|
|
160
|
+
// Domain ibgibs stay in tempSpace ONLY until commit
|
|
161
|
+
// (they're already in the appropriate space from coordinator's work)
|
|
162
|
+
const ibGibsToPersist = [...(payloadIbGibs || [])];
|
|
98
163
|
|
|
99
164
|
// Note: payloadIbGibs might have deep dependencies.
|
|
100
165
|
// Since they were generated/fetched by the Receiver Coordinator,
|
|
@@ -107,6 +172,14 @@ export class SyncPeerInnerspace_V1 extends SyncPeer_V1 {
|
|
|
107
172
|
|
|
108
173
|
await putInSpace({ space: receiverSpace, ibGibs: ibGibsToPersist });
|
|
109
174
|
|
|
175
|
+
// CRITICAL: Also put payloadIbGibs into sender's tempSpace
|
|
176
|
+
// Sender needs these for merge logic in handleDeltaFrame (tempSpace queries)
|
|
177
|
+
// Do NOT put in sender's durable space - these are transactional!
|
|
178
|
+
if (this.opts.senderTempSpace && ibGibsToPersist.length > 0) {
|
|
179
|
+
console.log(`${lc} [CONFLICT DEBUG] Transferring ${ibGibsToPersist.length} payload ibgibs to sender's tempSpace`);
|
|
180
|
+
await putInSpace({ space: this.opts.senderTempSpace, ibGibs: ibGibsToPersist });
|
|
181
|
+
}
|
|
182
|
+
|
|
110
183
|
// 4. Create Response Context
|
|
111
184
|
const responsePayloadAddrs = payloadIbGibs?.map(p => getIbGibAddr({ ibGib: p }));
|
|
112
185
|
const responseCtx = await createSyncSagaContext({
|