@ibgib/core-gib 0.1.11 → 0.1.12

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 (29) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/sync/sync-innerspace.respec.mjs +147 -25
  3. package/dist/sync/sync-innerspace.respec.mjs.map +1 -1
  4. package/dist/timeline/timeline-api.respec.mjs +34 -7
  5. package/dist/timeline/timeline-api.respec.mjs.map +1 -1
  6. package/dist/witness/space/inner-space/inner-space-v1.d.mts +1 -1
  7. package/dist/witness/space/inner-space/inner-space-v1.d.mts.map +1 -1
  8. package/dist/witness/space/inner-space/inner-space-v1.mjs +4 -3
  9. package/dist/witness/space/inner-space/inner-space-v1.mjs.map +1 -1
  10. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.d.mts +18 -0
  11. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.d.mts.map +1 -1
  12. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.mjs +39 -10
  13. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.mjs.map +1 -1
  14. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.d.mts.map +1 -1
  15. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.mjs +2 -1
  16. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.mjs.map +1 -1
  17. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.respec.mjs +6 -4
  18. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.respec.mjs.map +1 -1
  19. package/dist/witness/space/space-helper.d.mts.map +1 -1
  20. package/dist/witness/space/space-helper.mjs +1 -0
  21. package/dist/witness/space/space-helper.mjs.map +1 -1
  22. package/package.json +1 -1
  23. package/src/sync/sync-innerspace.respec.mts +170 -25
  24. package/src/timeline/timeline-api.respec.mts +34 -16
  25. package/src/witness/space/inner-space/inner-space-v1.mts +5 -3
  26. package/src/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.mts +39 -10
  27. package/src/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.mts +2 -1
  28. package/src/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.respec.mts +5 -3
  29. package/src/witness/space/space-helper.mts +1 -1
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @module sync-innerspace.respec
3
- *
3
+ *
4
4
  * Verifies SyncSagaCoordinator using InnerSpace (in-memory/local) spaces.
5
5
  * This avoids disk I/O issues and focuses on the synchronization logic.
6
6
  */
@@ -18,6 +18,7 @@ import { Metaspace_Innerspace } from '../witness/space/metaspace/metaspace-inner
18
18
  import { InnerSpace_V1 } from '../witness/space/inner-space/inner-space-v1.mjs';
19
19
  import { createStoneHelper, createTimelineRootHelper, getTestKeystoneServiceHelper } from '../agent-helpers.mjs';
20
20
  import { mut8Timeline, appendToTimeline } from '../timeline/timeline-api.mjs';
21
+ import { getDependencyGraph } from '../common/other/graph-helper.mjs';
21
22
 
22
23
  const logalot = true;
23
24
  const lc = `[sync-innerspace.respec]`;
@@ -28,11 +29,10 @@ await respecfully(sir, `Sync InnerSpaces`, async () => {
28
29
  let sourceSpace: InnerSpace_V1;
29
30
  let destSpace: InnerSpace_V1;
30
31
 
31
- // Setup before each test? Or once?
32
+ // Setup before each test? Or once?
32
33
  // For now, let's just do it inside the test block to be safe/simple.
33
34
 
34
35
  await ifWe(sir, `Basic Push Sync (Source -> Dest)`, async () => {
35
- // await ifWeMight(sir, `Basic Push Sync (Source -> Dest)`, async () => {
36
36
  // 1. Setup Spaces
37
37
  metaspace = new Metaspace_Innerspace(undefined);
38
38
  await metaspace.initialize({
@@ -113,32 +113,177 @@ await respecfully(sir, `Sync InnerSpaces`, async () => {
113
113
  identity
114
114
  });
115
115
 
116
- // 5. Verify Dest
117
- console.log(`${lc} Verifying Destination...`);
116
+ // 5. Verify Dest (Full Dependency Graph)
117
+ console.log(`${lc} Verifying Destination (Full Graph)...`);
118
118
 
119
- // Check Stone
120
- const getStone = await getFromSpace({ space: destSpace, addr: stoneAddr });
121
- iReckon(sir, getStone.success).asTo('getStone.success').isGonnaBeTrue();
122
- iReckon(sir, getStone.ibGibs?.[0]).asTo('stone in dest').isGonnaBeTruthy();
123
- console.log(`${lc} Verified Stone synced.`);
119
+ // We expect the graph to contain:
120
+ // 1. childWithRel
121
+ // 2. child (past of childWithRel)
122
+ // 3. root (ancestor of child, past of child)
123
+ // 4. stone (linked to childWithRel)
124
+ // 5. primitives (timeline_root, child, stone_data, identity, fork, mut8, rel8, root^gib, etc.)
124
125
 
125
- // Check Root (Dependency of Child)
126
- const getRoot = await getFromSpace({ space: destSpace, addr: rootAddr });
127
- iReckon(sir, getRoot.success).asTo('getRoot.success').isGonnaBeTrue();
128
- iReckon(sir, getRoot.ibGibs?.[0]).asTo('root in dest').isGonnaBeTruthy();
129
- console.log(`${lc} Verified Root synced.`);
126
+ // Let's get the graph from the source first to know what to expect (ground truth)
127
+ const sourceGraph = await getDependencyGraph({
128
+ ibGibs: [childWithRel],
129
+ space: sourceSpace,
130
+ });
131
+ const sourceAddrs = Object.keys(sourceGraph);
132
+ console.log(`${lc} Source Graph Size: ${sourceAddrs.length}`);
133
+
134
+ // Now get the graph from the destination
135
+ const destGraph = await getDependencyGraph({
136
+ ibGibs: [childWithRel],
137
+ space: destSpace,
138
+ });
139
+ const destAddrs = Object.keys(destGraph);
140
+ console.log(`${lc} Dest Graph Size: ${destAddrs.length}`);
141
+
142
+ // Assert
143
+ iReckon(sir, destAddrs.length).asTo('dest graph size').isGonnaBe(sourceAddrs.length);
144
+
145
+ for (const addr of sourceAddrs) {
146
+ const inDest = !!destGraph[addr];
147
+ if (!inDest) {
148
+ console.error(`${lc} Missing in dest: ${addr}`);
149
+ }
150
+ iReckon(sir, inDest).asTo(`addr present in dest: ${addr}`).isGonnaBeTrue();
151
+ }
152
+
153
+ console.log(`${lc} Verified Full Dependency Graph synced.`);
154
+ });
155
+
156
+ await ifWe(sir, `Idempotency (No-op if already synced)`, async () => {
157
+ // 1. Setup Spaces
158
+ const metaspace = new Metaspace_Innerspace(undefined);
159
+ await metaspace.initialize({
160
+ getFnAlert: () => async ({ title, msg }) => { console.log(`[Alert] ${title}: ${msg}`); },
161
+ getFnPrompt: () => async ({ title, msg }) => { console.log(`[Prompt] ${title}: ${msg}`); return ''; },
162
+ getFnPromptPassword: () => async (title, msg) => { console.log(`[PromptPwd] ${title}: ${msg}`); return null; },
163
+ });
164
+
165
+ const sourceSpace = new InnerSpace_V1({ name: 'source_idem', uuid: 'source_idem_uuid' } as any);
166
+ await (sourceSpace as any).initialize();
167
+
168
+ const destSpace = new InnerSpace_V1({ name: 'dest_idem', uuid: 'dest_idem_uuid' } as any);
169
+ await (destSpace as any).initialize();
170
+
171
+ // 2. Seed Source and Sync ONCE
172
+ const root = await createTimelineRootHelper({
173
+ ib: 'timeline_root',
174
+ data: { type: 'root', n: 0 },
175
+ space: sourceSpace,
176
+ });
177
+
178
+ const mockKeystone = await getTestKeystoneServiceHelper();
179
+ const identity = await (mockKeystone as any).getIdentity();
180
+ const coordinator = new SyncSagaCoordinator(mockKeystone);
181
+
182
+ console.log(`${lc} Running First Sync...`);
183
+ await coordinator.sync({
184
+ source: sourceSpace,
185
+ dest: destSpace,
186
+ domainIbGibs: [root],
187
+ identity
188
+ });
189
+
190
+ // Verify Initial State
191
+ const rootAddr = getIbGibAddr({ ibGib: root });
192
+ const getRoot1 = await getFromSpace({ space: destSpace, addr: rootAddr });
193
+ iReckon(sir, getRoot1.success).asTo('First Sync success').isGonnaBeTrue();
130
194
 
131
- // Check Child (Dependency of ChildWithRel)
132
- const getChild = await getFromSpace({ space: destSpace, addr: childAddr });
133
- iReckon(sir, getChild.success).asTo('getChild.success').isGonnaBeTrue();
134
- iReckon(sir, getChild.ibGibs?.[0]).asTo('child in dest').isGonnaBeTruthy();
135
- console.log(`${lc} Verified Child synced.`);
195
+ // 3. Run Sync AGAIN (Should be No-op)
196
+ console.log(`${lc} Running Second Sync...`);
197
+ await coordinator.sync({
198
+ source: sourceSpace,
199
+ dest: destSpace,
200
+ domainIbGibs: [root],
201
+ identity
202
+ });
203
+
204
+ // 4. Verify State Unchanged / Still Valid
205
+ const getRoot2 = await getFromSpace({ space: destSpace, addr: rootAddr });
206
+ iReckon(sir, getRoot2.success).asTo('Second Sync success').isGonnaBeTrue();
207
+
208
+ // Ensure no duplication or errors in destination (checking count in dependency graph might be good proxy?)
209
+ const destGraph = await getDependencyGraph({
210
+ ibGibs: [root],
211
+ space: destSpace,
212
+ });
213
+ iReckon(sir, Object.keys(destGraph).length).asTo('Dest Graph Size unchanged').isGonnaBe(Object.keys(destGraph).length); // Trivial assertion, mostly checking for no throw
214
+
215
+ console.log(`${lc} Verified Idempotency.`);
216
+ });
217
+
218
+ await ifWeMight(sir, `Dest Ahead (Pull/Fast-Backward)`, async () => {
219
+ // 1. Setup Spaces
220
+ const metaspace = new Metaspace_Innerspace(undefined);
221
+ await metaspace.initialize({
222
+ getFnAlert: () => async ({ title, msg }) => { console.log(`[Alert] ${title}: ${msg}`); },
223
+ getFnPrompt: () => async ({ title, msg }) => { console.log(`[Prompt] ${title}: ${msg}`); return ''; },
224
+ getFnPromptPassword: () => async (title, msg) => { console.log(`[PromptPwd] ${title}: ${msg}`); return null; },
225
+ });
226
+
227
+ const sourceSpace = new InnerSpace_V1({ name: 'source_pull', uuid: 'source_pull_uuid' } as any);
228
+ await (sourceSpace as any).initialize();
229
+
230
+ const destSpace = new InnerSpace_V1({ name: 'dest_pull', uuid: 'dest_pull_uuid' } as any);
231
+ await (destSpace as any).initialize();
232
+
233
+ // 2. Setup Initial Shared State
234
+ // Create root in Source, Sync to Dest
235
+ console.log(`${lc} Seeding initial shared state...`);
236
+ const root = await createTimelineRootHelper({
237
+ ib: 'timeline_pull',
238
+ data: { type: 'root', n: 0, state: 'initial' },
239
+ space: sourceSpace,
240
+ });
241
+ const rootAddr = getIbGibAddr({ ibGib: root });
242
+
243
+ const mockKeystone = await getTestKeystoneServiceHelper();
244
+ const identity = await (mockKeystone as any).getIdentity();
245
+ const coordinator = new SyncSagaCoordinator(mockKeystone);
246
+
247
+ await coordinator.sync({
248
+ source: sourceSpace,
249
+ dest: destSpace,
250
+ domainIbGibs: [root],
251
+ identity
252
+ });
253
+
254
+ // 3. Evolve DESTINATION (Simulate external update)
255
+ // We act "as if" we are on Dest side evolving it
256
+ console.log(`${lc} Evolving Destination (making Source behind)...`);
257
+ const childDest = await mut8Timeline({
258
+ timeline: root, // works because mut8Timeline just needs the ib/data/rel8ns/n, doesn't need to be "in" the space object-wise, but we persist to destSpace
259
+ mut8Opts: { dataToAddOrPatch: { n: 1, state: 'ahead' } },
260
+ metaspace,
261
+ space: destSpace,
262
+ });
263
+ const childDestAddr = getIbGibAddr({ ibGib: childDest });
264
+
265
+ // Verify Source DOES NOT have childDest
266
+ const getChildInSource = await getFromSpace({ space: sourceSpace, addr: childDestAddr });
267
+ iReckon(sir, getChildInSource.success).asTo('Source is behind').isGonnaBeFalse(); // Or success=true/addrsNotFound depending on impl
268
+
269
+ // 4. Run Sync from Source
270
+ // Checks:
271
+ // - Source should detect it is behind (or "conflict" in current generic terms).
272
+ // - Source should Pull 'childDest' from Dest.
273
+ // - Source should update itself.
274
+ console.log(`${lc} Running Sync (Pull)...`);
275
+ await coordinator.sync({
276
+ source: sourceSpace,
277
+ dest: destSpace,
278
+ domainIbGibs: [root], // We start with what Source knows (root)
279
+ identity
280
+ });
136
281
 
137
- // Check ChildWithRel (The Tip)
138
- const getChildWithRel = await getFromSpace({ space: destSpace, addr: childWithRelAddr });
139
- iReckon(sir, getChildWithRel.success).asTo('getChildWithRel.success').isGonnaBeTrue();
140
- iReckon(sir, getChildWithRel.ibGibs?.[0]).asTo('childWithRel in dest').isGonnaBeTruthy();
141
- console.log(`${lc} Verified Timeline Tip synced.`);
282
+ // 5. Verify Source Caught Up
283
+ const getChildInSourcePost = await getFromSpace({ space: sourceSpace, addr: childDestAddr });
284
+ iReckon(sir, getChildInSourcePost.success).asTo('Source pulled new frame').isGonnaBeTrue();
285
+ iReckon(sir, getChildInSourcePost.ibGibs?.[0]).asTo('Source has childDest').isGonnaBeTruthy();
142
286
 
287
+ console.log(`${lc} Verified Dest Ahead / Pull.`);
143
288
  });
144
289
  });
@@ -9,24 +9,22 @@ import {
9
9
  lastOfEach, lastOfAll,
10
10
  ifWeMight, iReckon, respecfully, respecfullyDear
11
11
  } from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
12
+ const maam = `[${import.meta.url}]`, sir = maam;
13
+ import { getUUID } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
14
+ import { IbGibData_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
15
+ import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
12
16
 
13
- import { IbGib_V1, IbGibData_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
17
+ import { GLOBAL_LOG_A_LOT } from '../core-constants.mjs';
14
18
  import { InnerSpace_V1 } from '../witness/space/inner-space/inner-space-v1.mjs';
15
- import { DEFAULT_INNER_SPACE_DATA_V1 } from '../witness/space/inner-space/inner-space-types.mjs';
19
+ import { getLatestAddrs, getFromSpace } from '../witness/space/space-helper.mjs';
16
20
  import {
17
- getLatestAddrs, persistTransformResult, registerNewIbGib, getFromSpace
18
- } from '../witness/space/space-helper.mjs';
19
- import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
20
- import {
21
- createTimeline, mut8Timeline, appendToTimeline, getHistory
21
+ createTimeline, mut8Timeline, getHistory, appendToTimeline
22
22
  } from './timeline-api.mjs';
23
- import { MetaspaceService } from '../witness/space/metaspace/metaspace-types.mjs';
24
- import { IbGibAddr } from '@ibgib/ts-gib/dist/types.mjs';
25
- import { IbGibSpaceAny } from '../witness/space/space-base-v1.mjs';
26
-
27
23
  import { Metaspace_Innerspace } from '../witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.mjs';
24
+ import { resetInnerSpaces } from '../witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.mjs';
25
+
26
+ const logalot = GLOBAL_LOG_A_LOT;
28
27
 
29
- const maam = `[${import.meta.url}]`, sir = maam;
30
28
 
31
29
  interface TestData extends IbGibData_V1 {
32
30
  note?: string;
@@ -40,11 +38,12 @@ respecfully(sir, `[timeline-api]`, async () => {
40
38
  let metaspace: Metaspace_Innerspace;
41
39
 
42
40
  firstOfEach(sir, async () => {
41
+ resetInnerSpaces();
43
42
  metaspace = new Metaspace_Innerspace(undefined);
44
43
  await metaspace.initialize({
45
44
  getFnAlert: () => async ({ title, msg }) => { console.log(`[Alert] ${title}: ${msg}`); },
46
45
  getFnPrompt: () => async ({ title, msg }) => { console.log(`[Prompt] ${title}: ${msg}`); return ''; },
47
- getFnPromptPassword: () => async (title, msg) => { console.log(`[PromptPwd] ${title}: ${msg}`); return null; },
46
+ getFnPromptPassword: () => async (title, msg) => { console.log(`[PromptPwd] ${title}: ${msg}`); return 'password'; },
48
47
  });
49
48
  space = metaspace.zeroSpace as InnerSpace_V1;
50
49
  });
@@ -165,7 +164,8 @@ respecfully(sir, `[timeline-api]`, async () => {
165
164
  const concurrencyLevels = [1, 2, 5, 50];
166
165
 
167
166
  for (const N of concurrencyLevels) {
168
- console.log(`[Stress Test] Testing concurrency level: ${N}`);
167
+ if (logalot) { console.log(`[Stress Test] Testing concurrency level: ${N}`); }
168
+
169
169
 
170
170
  // Arrange: Baseline
171
171
  let tInitial = (await createTimeline<TestData>({
@@ -179,8 +179,26 @@ respecfully(sir, `[timeline-api]`, async () => {
179
179
  const initialN = (tInitial.data!.n || 0); // should be 1
180
180
  const historyInitial = await getHistory({ timeline: tInitial, metaspace, space });
181
181
  const initialHistoryLength = historyInitial.orderedPastIbGibs.length; // should be 1 (genesis)
182
+ console.log(`already had addr for fork expected (I: 585a392f1c5aa0eedc1aedd8bbc31325)`);
182
183
 
183
184
  // Act: Launch N mutations simultaneously
185
+ /**
186
+ * I'm getting output (warnings?) that the transform ibgib addr
187
+ * already exists. This stems from the fact that dna/transform
188
+ * ibgibs do not have timestamps or anything, they simply are
189
+ * memoized args to the transform functions. So we need something
190
+ * unique _in the arg itself_, which in this case means in the
191
+ * `dataToAddOrPatch` field.
192
+ *
193
+ * Note, however, that it is expected for the original `fork`
194
+ * transform that created tInitial to be common and for it to
195
+ * already have this fork dna ibgib. But this shouldn't happen for
196
+ * each mut8 transform.
197
+ */
198
+ const uniqueIdsForUniqueTransforms: string[] = [];
199
+ for (let i = 0; i < N; i++) {
200
+ uniqueIdsForUniqueTransforms.push(await getUUID());
201
+ }
184
202
  const promises: Promise<any>[] = [];
185
203
  for (let i = 0; i < N; i++) {
186
204
  promises.push(mut8Timeline<TestData>({
@@ -191,7 +209,7 @@ respecfully(sir, `[timeline-api]`, async () => {
191
209
  space,
192
210
  mut8Opts: {
193
211
  dataToAddOrPatch: {
194
- uniq: i, // distinct data to ensure unique hashes if needed
212
+ uniqueId: uniqueIdsForUniqueTransforms.pop(),
195
213
  }
196
214
  }
197
215
  // No skipLock! We want them to contend.
@@ -225,7 +243,7 @@ respecfully(sir, `[timeline-api]`, async () => {
225
243
  const expectedHistoryLength = initialHistoryLength + N;
226
244
  iReckon(sir, history.orderedPastIbGibs.length).asTo(`[N=${N}] history length`).isGonnaBe(expectedHistoryLength);
227
245
 
228
- console.log(`[Stress Test] [N=${N}] SUCCESS. Final n=${latestIbGib.data!.n}`);
246
+ if (logalot) { console.log(`[Stress Test] [N=${N}] SUCCESS. Final n=${latestIbGib.data!.n}`); }
229
247
 
230
248
  } catch (err) {
231
249
  console.error(`[Stress Test] [N=${N}] FAILED:`, err);
@@ -1,7 +1,6 @@
1
1
  import { clone, extractErrorMsg, groupBy, pretty } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
2
2
  import { IbGibAddr } from '@ibgib/ts-gib/dist/types.mjs';
3
3
  import { getIbGibAddr, } from '@ibgib/ts-gib/dist/helper.mjs';
4
- import { IbGib_V1, getGib, } from '@ibgib/ts-gib/dist/V1/index.mjs';
5
4
  import { validateIbGibIntrinsically } from '@ibgib/ts-gib/dist/V1/validate-helper.mjs';
6
5
 
7
6
  import { GLOBAL_LOG_A_LOT } from '../../../core-constants.mjs';
@@ -14,6 +13,8 @@ import { getSpaceIb, } from '../space-helper.mjs';
14
13
  import { getTjpAddr } from '../../../common/other/ibgib-helper.mjs';
15
14
  import { ReconciliationSpaceBase, ReconciliationSpaceData, ReconciliationSpaceRel8ns } from '../reconciliation-space/reconciliation-space-base.mjs';
16
15
  import { DEFAULT_INNER_SPACE_DATA_V1, InnerSpaceData_V1, InnerSpaceRel8ns_V1 } from './inner-space-types.mjs';
16
+ import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
17
+ import { getGib } from '@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs';
17
18
 
18
19
  const logalot = GLOBAL_LOG_A_LOT;
19
20
 
@@ -197,7 +198,7 @@ export class InnerSpace_V1<
197
198
 
198
199
  if (addrsAlreadyHave.length > 0) {
199
200
  resultData.addrsAlreadyHave = addrsAlreadyHave;
200
- resultData.warnings = (resultData.warnings || []).concat([`${lc} already had addr(s).`]);
201
+ resultData.warnings = (resultData.warnings || []).concat([`${lc} already had addr(s): ${addrsAlreadyHave.join('|')}`]);
201
202
  }
202
203
  resultData.success = true;
203
204
  } catch (error) {
@@ -321,7 +322,8 @@ export class InnerSpace_V1<
321
322
  const timeline = ibGibsInSpaceByTjp[tjpAddr];
322
323
 
323
324
  if (timeline.some(ibGib => ibGib.data?.n === undefined)) {
324
- console.warn(`${lc} timeline includes ibgibs with ibGib.data?.n === undefined (W: 7360a8e81b05accf244fb4b86e796325)`);
325
+ const filtered = timeline.filter(ibGib => ibGib.data?.n === undefined);
326
+ console.warn(`${lc} timeline includes ibgibs with ibGib.data?.n === undefined.\nfiltered:\n${filtered.map(x => pretty(x)).join('\n')}}(W: 7360a8e81b05accf244fb4b86e796325)`);
325
327
  }
326
328
  // sort mutates array in place
327
329
  timeline.sort((a, b) => (a.data?.n ?? -1) > (b.data?.n ?? -1) ? 1 : -1); // sorts ascending, e.g., 0,1,2...[Highest]
@@ -10,7 +10,39 @@ import { InnerSpace_V1, } from "../../inner-space/inner-space-v1.mjs";
10
10
  import { InnerSpaceData_V1 } from "../../inner-space/inner-space-types.mjs";
11
11
 
12
12
 
13
- const innerSpaces: { [tjpGib: string]: IbGibSpaceAny } = {};
13
+ const innerSpaces: { [spaceId: string]: IbGibSpaceAny } = {};
14
+
15
+ /**
16
+ * Extracts the spaceId from the ib string.
17
+ *
18
+ * ib format: `witness space [classname] [name] [id] [type] [subtype]`
19
+ */
20
+ export function getSpaceIdFromIb(ib: string): string {
21
+ if (!ib) { throw new Error(`ib required. (E: 7c28c8e1a8a24345bb344155b4131422)`); }
22
+ const parts = ib.split(' ');
23
+ // witness space classname name id ...
24
+ // 0 1 2 3 4
25
+ if (parts.length < 5) { throw new Error(`invalid space ib format: ${ib} (E: 14a84497e59648949822067786481223)`); }
26
+ return parts[4];
27
+ }
28
+
29
+ /**
30
+ * Manually registers a space in the module-level registry.
31
+ * Use this when creating spaces outside of the standard factory functions
32
+ * (e.g. via direct constructor calls) to ensure they are resolvable by DTO.
33
+ */
34
+ export const registerInnerSpace = (space: IbGibSpaceAny) => {
35
+ const spaceId = getSpaceIdFromIb(space.ib);
36
+ innerSpaces[spaceId] = space;
37
+ }
38
+
39
+ /**
40
+ * Resets the internal registry of spaces.
41
+ * USE FOR TESTING ONLY.
42
+ */
43
+ export const resetInnerSpaces = () => {
44
+ Object.keys(innerSpaces).forEach(key => delete innerSpaces[key]);
45
+ }
14
46
 
15
47
  export const fnCreateNewLocalSpace: LocalSpaceFactoryFunction = async ({
16
48
  allowCancel,
@@ -74,9 +106,7 @@ Enter space name:
74
106
  if (newLocalSpace.gib === GIB) { throw new Error(`localSpace.gib not updated correctly.`); }
75
107
  if (logalot) { console.log(`${lc} localSpace.gib: ${newLocalSpace.gib} (after sha256v1)`); }
76
108
 
77
- const gibInfo = getGibInfo({ gib: newLocalSpace.gib });
78
- const tjpGib = gibInfo.tjpGib ?? newLocalSpace.gib!;
79
- innerSpaces[tjpGib] = newLocalSpace;
109
+ registerInnerSpace(newLocalSpace as IbGibSpaceAny);
80
110
 
81
111
  return newLocalSpace as IbGibSpaceAny;
82
112
  } catch (error) {
@@ -103,9 +133,9 @@ export const fnDtoToSpace: DtoToSpaceFunction = async (spaceDto) => {
103
133
  if (!spaceDto.data) { throw new Error(`invalid spaceDto. InnerSpace_V1 should have truthy data. (E: d402fda7a6a53668b655c2885029a423)`); }
104
134
  // console.dir(spaceDto); // I want to keep this in if we need to turn the logging back on
105
135
 
106
- const gibInfo = getGibInfo({ gib: spaceDto.gib });
107
- const tjpGib = gibInfo.tjpGib ?? spaceDto.gib!;
108
- const existingSpace = innerSpaces[tjpGib];
136
+ const spaceId = getSpaceIdFromIb(spaceDto.ib);
137
+ // console.log(`${lc} spaceDto.gib: ${spaceDto.gib}\ninnerSpaces keys:\n${Object.keys(innerSpaces).join('\n')}`);
138
+ const existingSpace = innerSpaces[spaceId];
109
139
  if (existingSpace) {
110
140
  return existingSpace;
111
141
  } else {
@@ -113,9 +143,8 @@ export const fnDtoToSpace: DtoToSpaceFunction = async (spaceDto) => {
113
143
  console.warn(`${lc} in memory innerspace dto that isnt' the reference to the object itself in memory, and we don't have it in the inner spaces map? i guess we'll create a new one from the dto (W: b8973f3a43f546eeaf59f60331896e75)`)
114
144
  let space = new InnerSpace_V1(spaceDto.data as InnerSpaceData_V1, spaceDto.rel8ns);
115
145
  await space.initialized;
116
- const gibInfo = getGibInfo({ gib: space.gib });
117
- const tjpGib = gibInfo.tjpGib ?? space.gib!;
118
- innerSpaces[tjpGib] = space;
146
+
147
+ registerInnerSpace(space);
119
148
  return space;
120
149
  }
121
150
  }
@@ -12,7 +12,7 @@ import { IbGibSpaceAny } from '../../../../witness/space/space-base-v1.mjs';
12
12
  import { InnerSpace_V1 } from '../../../../witness/space/inner-space/inner-space-v1.mjs';
13
13
  import { IbGibCacheService } from '../../../../common/cache/cache-types.mjs';
14
14
  import { MetaspaceFactory } from '../metaspace-types.mjs';
15
- import { fnCreateNewLocalSpace, fnDtoToSpace } from './metaspace-innerspace-helper.mjs';
15
+ import { fnCreateNewLocalSpace, fnDtoToSpace, registerInnerSpace } from './metaspace-innerspace-helper.mjs';
16
16
  import { MetaspaceBase } from '../metaspace-base.mjs';
17
17
 
18
18
  const logalot = GLOBAL_LOG_A_LOT;
@@ -75,6 +75,7 @@ export class Metaspace_Innerspace extends MetaspaceBase {
75
75
  const zeroSpace = new InnerSpace_V1(/*initialData*/ undefined as any, /*initialRel8ns*/ undefined);
76
76
  zeroSpace.gib = 'gib';
77
77
  this._zeroSpace = zeroSpace;
78
+ registerInnerSpace(this._zeroSpace);
78
79
  return zeroSpace;
79
80
  }
80
81
  };
@@ -16,6 +16,7 @@ import { InnerSpace_V1 } from '../../../../witness/space/inner-space/inner-space
16
16
  import { Metaspace_Innerspace } from './metaspace-innerspace.mjs';
17
17
  import { createTimeline, mut8Timeline } from '../../../../timeline/timeline-api.mjs';
18
18
  import { MetaspaceService } from '../metaspace-types.mjs';
19
+ import { resetInnerSpaces } from './metaspace-innerspace-helper.mjs';
19
20
 
20
21
  const maam = `[${import.meta.url}]`, sir = maam;
21
22
 
@@ -24,6 +25,7 @@ respecfully(sir, `[metaspace-innerspace]`, async () => {
24
25
  let metaspace: Metaspace_Innerspace;
25
26
 
26
27
  firstOfEach(sir, async () => {
28
+ resetInnerSpaces();
27
29
  metaspace = new Metaspace_Innerspace(undefined); // no cache for now
28
30
  await metaspace.initialize({
29
31
  getFnAlert: () => async ({ title, msg }) => { console.log(`[Alert] ${title}: ${msg}`); },
@@ -32,17 +34,17 @@ respecfully(sir, `[metaspace-innerspace]`, async () => {
32
34
  });
33
35
  });
34
36
 
35
- await ifWeMight(sir, `can instantiate`, async () => {
37
+ await ifWe(sir, `can instantiate`, async () => {
36
38
  iReckon(sir, metaspace).asTo('metaspace').isGonnaBeTruthy();
37
39
  iReckon(sir, metaspace.initialized).asTo('initialized').isGonnaBeTrue();
38
40
  });
39
41
 
40
- await ifWeMight(sir, `has zeroSpace`, async () => {
42
+ await ifWe(sir, `has zeroSpace`, async () => {
41
43
  const zs = metaspace.zeroSpace;
42
44
  iReckon(sir, zs).asTo('zeroSpace').isGonnaBeTruthy();
43
45
  });
44
46
 
45
- await ifWeMight(sir, `can createTimeline and track latest`, async () => {
47
+ await ifWe(sir, `can createTimeline and track latest`, async () => {
46
48
  // This implicitly tests getLatestAddr/s via timeline-api usage if we were using it,
47
49
  // but here we call it directly or via minimal timeline op.
48
50
 
@@ -51,7 +51,6 @@ import { validateBootstrapIbGib } from './bootstrap/bootstrap-helper.mjs';
51
51
  import { BootstrapData, BootstrapIbGib, BootstrapRel8ns } from './bootstrap/bootstrap-types.mjs';
52
52
  import { newUpMetaStone } from '../../common/meta-stone/meta-stone-helper.mjs';
53
53
  import { WITNESS_ATOM } from '../witness-constants.mjs';
54
- import { SyncSpaceIbGib } from './outer-space/outer-space-types.mjs';
55
54
 
56
55
  let logalot = GLOBAL_LOG_A_LOT;
57
56
 
@@ -1620,6 +1619,7 @@ async function createRootIbGib({
1620
1619
  linkedRel8ns: [Rel8n.past, Rel8n.ancestor],
1621
1620
  tjp: { uuid: true, timestamp: true },
1622
1621
  dna: true,
1622
+ nCounter: true,
1623
1623
  });
1624
1624
  const { newIbGib } = resNewIbGib;
1625
1625
  await persistTransformResult({