@ibgib/core-gib 0.0.112 → 0.1.1

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 (67) hide show
  1. package/dist/common/import-export/import-export-types.d.mts +8 -0
  2. package/dist/common/import-export/import-export-types.d.mts.map +1 -1
  3. package/dist/timeline/timeline-api.d.mts +297 -0
  4. package/dist/timeline/timeline-api.d.mts.map +1 -0
  5. package/dist/timeline/timeline-api.mjs +725 -0
  6. package/dist/timeline/timeline-api.mjs.map +1 -0
  7. package/dist/timeline/timeline-types.d.mts +42 -0
  8. package/dist/timeline/timeline-types.d.mts.map +1 -0
  9. package/dist/timeline/timeline-types.mjs +2 -0
  10. package/dist/timeline/timeline-types.mjs.map +1 -0
  11. package/dist/witness/space/filesystem-space/filesystem-space-v1.d.mts +0 -1
  12. package/dist/witness/space/filesystem-space/filesystem-space-v1.d.mts.map +1 -1
  13. package/dist/witness/space/filesystem-space/filesystem-space-v1.mjs +0 -3
  14. package/dist/witness/space/filesystem-space/filesystem-space-v1.mjs.map +1 -1
  15. package/dist/witness/space/inner-space/inner-space-constants.d.mts +2 -0
  16. package/dist/witness/space/inner-space/inner-space-constants.d.mts.map +1 -0
  17. package/dist/witness/space/inner-space/inner-space-constants.mjs +2 -0
  18. package/dist/witness/space/inner-space/inner-space-constants.mjs.map +1 -0
  19. package/dist/witness/space/inner-space/inner-space-types.d.mts +23 -0
  20. package/dist/witness/space/inner-space/inner-space-types.d.mts.map +1 -0
  21. package/dist/witness/space/inner-space/inner-space-types.mjs +32 -0
  22. package/dist/witness/space/inner-space/inner-space-types.mjs.map +1 -0
  23. package/dist/witness/space/inner-space/inner-space-v1.d.mts +13 -7
  24. package/dist/witness/space/inner-space/inner-space-v1.d.mts.map +1 -1
  25. package/dist/witness/space/inner-space/inner-space-v1.mjs +159 -8
  26. package/dist/witness/space/inner-space/inner-space-v1.mjs.map +1 -1
  27. package/dist/witness/space/inner-space/inner-space-v1.respec.mjs +206 -52
  28. package/dist/witness/space/inner-space/inner-space-v1.respec.mjs.map +1 -1
  29. package/dist/witness/space/metaspace/metaspace-base.d.mts.map +1 -1
  30. package/dist/witness/space/metaspace/metaspace-base.mjs +4 -2
  31. package/dist/witness/space/metaspace/metaspace-base.mjs.map +1 -1
  32. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.d.mts.map +1 -1
  33. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.mjs +28 -9
  34. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.mjs.map +1 -1
  35. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.d.mts.map +1 -1
  36. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.mjs +27 -3
  37. package/dist/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.mjs.map +1 -1
  38. package/dist/witness/space/reconciliation-space/reconciliation-space-base.d.mts +100 -0
  39. package/dist/witness/space/reconciliation-space/reconciliation-space-base.d.mts.map +1 -0
  40. package/dist/witness/space/reconciliation-space/reconciliation-space-base.mjs +758 -0
  41. package/dist/witness/space/reconciliation-space/reconciliation-space-base.mjs.map +1 -0
  42. package/dist/witness/space/reconciliation-space/reconciliation-space-helper.d.mts +40 -0
  43. package/dist/witness/space/reconciliation-space/reconciliation-space-helper.d.mts.map +1 -0
  44. package/dist/witness/space/reconciliation-space/reconciliation-space-helper.mjs +90 -0
  45. package/dist/witness/space/reconciliation-space/reconciliation-space-helper.mjs.map +1 -0
  46. package/dist/witness/space/space-helper.d.mts.map +1 -1
  47. package/dist/witness/space/space-helper.mjs +11 -2
  48. package/dist/witness/space/space-helper.mjs.map +1 -1
  49. package/dist/witness/space/space-respec-helper.d.mts.map +1 -1
  50. package/dist/witness/space/space-respec-helper.mjs +3 -0
  51. package/dist/witness/space/space-respec-helper.mjs.map +1 -1
  52. package/package.json +1 -1
  53. package/src/common/import-export/import-export-types.mts +8 -0
  54. package/src/timeline/timeline-api.mts +943 -0
  55. package/src/timeline/timeline-types.mts +38 -0
  56. package/src/witness/space/filesystem-space/filesystem-space-v1.mts +0 -3
  57. package/src/witness/space/inner-space/inner-space-constants.mts +1 -0
  58. package/src/witness/space/inner-space/inner-space-types.mts +44 -0
  59. package/src/witness/space/inner-space/inner-space-v1.mts +157 -28
  60. package/src/witness/space/inner-space/inner-space-v1.respec.mts +242 -58
  61. package/src/witness/space/metaspace/metaspace-base.mts +7 -1
  62. package/src/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace-helper.mts +32 -10
  63. package/src/witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.mts +76 -53
  64. package/src/witness/space/reconciliation-space/reconciliation-space-base.mts +884 -0
  65. package/src/witness/space/reconciliation-space/reconciliation-space-helper.mts +125 -0
  66. package/src/witness/space/space-helper.mts +6 -2
  67. package/src/witness/space/space-respec-helper.mts +4 -4
@@ -0,0 +1,725 @@
1
+ /**
2
+ * @module timeline-api.mts This facade provides a simplified, timeline-oriented
3
+ * API for interacting with ibGibs, abstracting away low-level transform details
4
+ * (like nCounter, dna, dna, tjp rel8ns) and handling concurrency control (via
5
+ * locking) for maintaining timeline integrity.
6
+ */
7
+ import { extractErrorMsg, getTimestampInTicks } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
8
+ import { Rel8n } from "@ibgib/ts-gib/dist/V1/types.mjs";
9
+ import { getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
10
+ import { mut8 } from "@ibgib/ts-gib/dist/V1/transforms/mut8.mjs";
11
+ import { rel8 } from "@ibgib/ts-gib/dist/V1/transforms/rel8.mjs";
12
+ import { getGibInfo, isPrimitive } from "@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs";
13
+ import { Factory_V1 } from "@ibgib/ts-gib/dist/V1/factory.mjs";
14
+ import { ROOT } from '@ibgib/ts-gib/dist/V1/constants.mjs';
15
+ import { GLOBAL_LOG_A_LOT } from "../core-constants.mjs";
16
+ import { getSpecialConfigKey, toDto } from "../common/other/ibgib-helper.mjs";
17
+ import { execInSpaceWithLocking, persistTransformResult } from "../witness/space/space-helper.mjs";
18
+ const logalot = GLOBAL_LOG_A_LOT;
19
+ /**
20
+ * Deterministically generates a lock scope for a given timeline.
21
+ *
22
+ * ## internal details, may change
23
+ *
24
+ * ATOW (05/2025), this will return the tjpGib of the timeline. So if the addr
25
+ * is `comment Foo^ABC123.DEF456`, where ABC123 and DEF456 are hashes, then this
26
+ * will return `DEF456`. For an addr that is just `comment Bar^GHI789`, then
27
+ * this *is* the TJP and thus its gib is `GHI789` and that is what is returned.
28
+ */
29
+ export async function getLockScope({ timeline }) {
30
+ const lc = `[${getLockScope.name}]`;
31
+ try {
32
+ if (logalot) {
33
+ console.log(`${lc} starting...`);
34
+ }
35
+ if (isPrimitive({ ibGib: timeline })) {
36
+ // this is an abnormal/unusual path
37
+ console.warn(`${lc} getting lock scope on a primitive ibgib can grossly impact performance. (W: 55203e415ae2ac7ddb19c21772b28925)`);
38
+ return getIbGibAddr({ ibGib: timeline });
39
+ }
40
+ else {
41
+ // happy path
42
+ const gibInfo = getGibInfo({ gib: timeline.gib });
43
+ const tjpGib = gibInfo.tjpGib ?? gibInfo.punctiliarHash;
44
+ if (!tjpGib) {
45
+ // This should not happen for a valid ibGib, but as a safeguard
46
+ throw new Error(`${lc} (UNEXPECTED) Could not determine tjpGib or punctiliarHash from ibGib. (E: eb3b6472e9b335991a1b0869f772f7d3)`);
47
+ }
48
+ return tjpGib;
49
+ }
50
+ }
51
+ catch (error) {
52
+ console.error(`${lc} ${extractErrorMsg(error)}`);
53
+ throw error;
54
+ }
55
+ finally {
56
+ if (logalot) {
57
+ console.log(`${lc} complete.`);
58
+ }
59
+ }
60
+ }
61
+ export async function isSameTimeline({ a, b, }) {
62
+ const lc = `[${isSameTimeline.name}]`;
63
+ try {
64
+ if (logalot) {
65
+ console.log(`${lc} starting... (I: 0f8b68106f48a5c5c8d67f58b4b4d825)`);
66
+ }
67
+ // DRY kluge b/c I'm soooooooo tired ...need to gtfo here
68
+ const aLockScope = await getLockScope({ timeline: a });
69
+ const bLockScope = await getLockScope({ timeline: b });
70
+ return aLockScope === bLockScope;
71
+ }
72
+ catch (error) {
73
+ console.error(`${lc} ${extractErrorMsg(error)}`);
74
+ throw error;
75
+ }
76
+ finally {
77
+ if (logalot) {
78
+ console.log(`${lc} complete.`);
79
+ }
80
+ }
81
+ }
82
+ /**
83
+ * Appends a list of ibGibs to a timeline in the order given using the
84
+ * associated rel8nName (named edge).
85
+ *
86
+ * ## regarding persistence and registerNewIbGib pubsub
87
+ *
88
+ * The caller is responsible for persisting any ibGibs that are contained in
89
+ * {@link rel8nInfos}. However, all newly created ibgibs resulting from extending
90
+ * {@link timeline} *WILL* be saved in the {@link space}.
91
+ *
92
+ * This also will call `metaspace.registerNewIbGib` for the new timeline ibgib
93
+ * created ONLY, and will only do this AFTER both...
94
+ * * the timeline's lock is released AND AFTER
95
+ * * any indexes are updated if given via {@link timelineIndexInfo}.
96
+ * * atow (05/2025) this does not await the registerNewIbGib call, but this may
97
+ * change at any time.
98
+ */
99
+ export async function appendToTimeline({ timeline, rel8nInfos, timelineIndexInfo, metaspace, space, skipLock, }) {
100
+ const lc = `[${appendToTimeline.name}]`;
101
+ try {
102
+ if (logalot) {
103
+ console.log(`${lc} starting... (I: fcdff10832215068019355265f4cbc25)`);
104
+ }
105
+ space ??= await metaspace.getLocalUserSpace({ lock: false });
106
+ if (!space) {
107
+ throw new Error(`(UNEXPECTED) space falsy? couldn't even get default local user space? (E: 2051b44a052d6a2984b9a22f680e4625)`);
108
+ }
109
+ const lockScope = await getLockScope({ timeline });
110
+ /**
111
+ * This fn actually does the append and will be executed in the locked
112
+ * setting if skipLock is falsy.
113
+ */
114
+ const fn = async () => {
115
+ if (!space) {
116
+ throw new Error(`(UNEXPECTED) space falsy? couldn't even get default local user space? (E: 845c4181c8c15d7219166ceb3c4dca25)`);
117
+ }
118
+ // Get the latest version of the provided timeline ibgib.
119
+ const timelineAddr = getIbGibAddr({ ibGib: timeline });
120
+ const latestTimelineIbGibAddr = await metaspace.getLatestAddr({
121
+ addr: timelineAddr,
122
+ space,
123
+ });
124
+ if (!latestTimelineIbGibAddr) {
125
+ throw new Error(`${lc} (UNEXPECTED) Could not get latest address for timeline ${getIbGibAddr({ ibGib: timeline })}. (E: a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9)`);
126
+ }
127
+ let latestTimelineIbGibDto = toDto({ ibGib: timeline });
128
+ if (timelineAddr !== latestTimelineIbGibAddr) {
129
+ const resGetLatest = await metaspace.get({
130
+ addrs: [latestTimelineIbGibAddr],
131
+ space,
132
+ });
133
+ if (resGetLatest.errorMsg || (resGetLatest.ibGibs ?? []).length !== 1) {
134
+ throw new Error(`${lc} (UNEXPECTED) couldn't get latest timeline ibgib (${latestTimelineIbGibAddr}) from space (${space.ib}). errorMsg: ${resGetLatest.errorMsg ?? '[unknown error]'} (E: b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0)`);
135
+ }
136
+ latestTimelineIbGibDto = resGetLatest.ibGibs.at(0);
137
+ }
138
+ // Prepare rel8nsToAddByAddr
139
+ const rel8nsToAddByAddr = {};
140
+ // Add the 'past' rel8n pointing to the previous timeline frame.
141
+ // rel8nsToAddByAddr.past = [getIbGibAddr({ ibGib: latestTimelineIbGib })]; // this happens automatically
142
+ // Add rel8ns from the provided rel8nInfos.
143
+ for (const rel8nInfo of rel8nInfos) {
144
+ const { rel8nName, ibGibs } = rel8nInfo;
145
+ if (ibGibs.length === 0) {
146
+ console.warn(`${lc} tried to add 0 ibGibs to rel8nName ${rel8nName}? skipping... (W: 708252dfdeb60757fee4554e769aaa25)`);
147
+ continue;
148
+ }
149
+ if (!rel8nsToAddByAddr[rel8nName]) {
150
+ rel8nsToAddByAddr[rel8nName] = [];
151
+ }
152
+ rel8nsToAddByAddr[rel8nName].push(...ibGibs.map(ibGib => getIbGibAddr({ ibGib })));
153
+ }
154
+ // Perform a rel8 transform on the latest timeline ibgib.
155
+ const resRel8 = await rel8({
156
+ type: 'rel8',
157
+ src: latestTimelineIbGibDto,
158
+ rel8nsToAddByAddr,
159
+ dna: true,
160
+ nCounter: true,
161
+ });
162
+ const newTimelineIbGib = resRel8.newIbGib;
163
+ // Persist the transform result.
164
+ await metaspace.persistTransformResult({ resTransform: resRel8, space });
165
+ // If timelineIndexInfo is provided, update the special index.
166
+ if (timelineIndexInfo) {
167
+ await updateSpecialIndex({
168
+ type: timelineIndexInfo.type,
169
+ rel8nInfos: [{ rel8nName: timelineIndexInfo.rel8nName, ibGibs: [newTimelineIbGib] }],
170
+ metaspace,
171
+ space,
172
+ skipLock,
173
+ });
174
+ }
175
+ // should we publish within the lock or not within the lock?
176
+ // should we await the publish or spin it off
177
+ // right now I have this spin off, inside the lock
178
+ // await metaspace.registerNewIbGib({ ibGib: newTimelineIbGib, space });
179
+ metaspace.registerNewIbGib({ ibGib: newTimelineIbGib, space }); // spin off
180
+ return newTimelineIbGib;
181
+ };
182
+ const newTimelineIbGib = skipLock ?
183
+ await fn() :
184
+ await execInSpaceWithLocking({
185
+ scope: lockScope,
186
+ secondsValid: 180,
187
+ maxDelayMs: 100,
188
+ maxLockAttempts: 1800,
189
+ space,
190
+ callerInstanceId: getTimestampInTicks(),
191
+ fn,
192
+ });
193
+ // should we publish within the lock or not within the lock?
194
+ // should we await the publish or spin it off
195
+ // right now I have this spin off, inside the lock
196
+ // await metaspace.registerNewIbGib({ ibGib: newTimelineIbGib, space });
197
+ // metaspace.registerNewIbGib({ ibGib: newTimelineIbGib, space }); // spin off
198
+ return newTimelineIbGib;
199
+ }
200
+ catch (error) {
201
+ console.error(`${lc} ${extractErrorMsg(error)}`);
202
+ throw error;
203
+ }
204
+ finally {
205
+ if (logalot) {
206
+ console.log(`${lc} complete.`);
207
+ }
208
+ }
209
+ }
210
+ /**
211
+ * Updates a special ibgib in the given {@link space} with new and/or updated
212
+ * {@link rel8nInfos}.
213
+ *
214
+ * ## on "special" ibgibs
215
+ *
216
+ * "Special" ibgibs are mostly used as indexes, but not necessarily. These are
217
+ * slightly different than most normal ibgibs in that they are not in some way
218
+ * or another attached to a root in the space, rather, they are rel8d directly
219
+ * to the local user space itself. So when a special ibgib is changed, i.e. its
220
+ * own timeline is extended, its new address is always proactively updated on
221
+ * the space directly. so `space.rel8ns[key]` (where key is derived from the
222
+ * given {@link type}) is updated with newSpecialIbGib's addr.
223
+ *
224
+ * @see {@link setConfigAddr}
225
+ * @see {@link rel8ToSpecialIbGib}
226
+ *
227
+ * ## upsert
228
+ *
229
+ * This is analogous to an upsert operation *into* the special index. So we are
230
+ * updating the index's rel8ns either way whether or not that rel8n already
231
+ * exists.
232
+ */
233
+ export async function updateSpecialIndex({ type, rel8nInfos, dataToAddOrPatch, metaspace, space, skipLock, }) {
234
+ const lc = `[${updateSpecialIndex.name}]`;
235
+ try {
236
+ if (logalot) {
237
+ console.log(`${lc} starting... (I: 6e7d05fe916d813b71766e2eaa747c25)`);
238
+ }
239
+ if (type === "latest") {
240
+ throw new Error(`cannot update the "latest" special index by this function. The registerNewIbGib will do this automatically. (E: 231eb78a221ccdbcf56cd1899260a425)`);
241
+ }
242
+ space ??= await metaspace.getLocalUserSpace({ lock: false });
243
+ if (!space) {
244
+ throw new Error(`(UNEXPECTED) space falsy? couldn't even get default local user space? (E: 43067821a4749a7648fe2612d25d7f25)`);
245
+ }
246
+ /**
247
+ * This fn actually does the update and will be executed in the locked
248
+ * setting.
249
+ */
250
+ const fn = async () => {
251
+ const fnGetSpecialIndex = async () => {
252
+ // always get the latest version of the special index ibgib
253
+ // fresh. The initialize: true option will create it if it
254
+ // doesn't exist.
255
+ const specialIndex = await metaspace.getSpecialIbGib({
256
+ type,
257
+ space,
258
+ initialize: true,
259
+ });
260
+ if (!specialIndex) {
261
+ throw new Error(`(UNEXPECTED) couldn't initialize/get special ibgib index of type ${type}. (E: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6)`);
262
+ }
263
+ if (!specialIndex.rel8ns) {
264
+ console.warn(`${lc} not sure if this ever hits, but is there ever a scenario where specialIndex.rel8ns is falsy? (W: 06161c366bc7ec858b9b5aa7ee9b6d25)`);
265
+ }
266
+ return specialIndex;
267
+ };
268
+ for (const rel8nInfo of (rel8nInfos ?? [])) {
269
+ // parse the rel8nInfo for this iteration
270
+ const { rel8nName, ibGibs } = rel8nInfo;
271
+ if (ibGibs.length === 0) {
272
+ console.error(`${lc} ibGibs empty. skipping rel8nName (${rel8nName}). (E: 150d74f73f97aea1b97d173d92c77125)`);
273
+ }
274
+ const specialIndex = await fnGetSpecialIndex();
275
+ // // always get the latest version of the special index ibgib
276
+ // // fresh. The initialize: true option will create it if it
277
+ // // doesn't exist.
278
+ // const specialIndex = await metaspace.getSpecialIbGib({
279
+ // type,
280
+ // space,
281
+ // initialize: true,
282
+ // });
283
+ // if (!specialIndex) {
284
+ // throw new Error(`(UNEXPECTED) couldn't initialize/get special ibgib index of type ${type}. (E: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6)`);
285
+ // }
286
+ // if (!specialIndex.rel8ns) {
287
+ // console.warn(`${lc} not sure if this ever hits, but is there ever a scenario where specialIndex.rel8ns is falsy? (W: 06161c366bc7ec858b9b5aa7ee9b6d25)`)
288
+ // }
289
+ const existingSpecialIndexRel8ns = specialIndex.rel8ns ?? {};
290
+ // before we just add all the ibgibs, we need to gather info on
291
+ // what previous ibgibs we need to unrel8
292
+ let addrsToUnRel8 = undefined;
293
+ // check if we even need to even compare existing rel8ns
294
+ const existingAddrsThisRel8nName = existingSpecialIndexRel8ns[rel8nName] ?? [];
295
+ if (existingAddrsThisRel8nName.length > 0) {
296
+ // we have existing rel8ns for this rel8nName, so remove any
297
+ // that share the tjpGib of addrs we're adding or use the
298
+ // past/current full addrs. check actual code here for impl
299
+ const toUnrel8ThisRel8nName_Set = new Set();
300
+ ibGibs.forEach(ibGib => {
301
+ const addr = getIbGibAddr({ ibGib });
302
+ // by tjpGib impl
303
+ // const gibInfo = getGibInfo({ gib: ibGib.gib });
304
+ // const tjpGib = gibInfo.tjpGib ?? gibInfo.punctiliarHash ?? ibGib.gib ?? GIB;
305
+ // existingAddrsThisRel8nName
306
+ // .filter(x => x.includes(tjpGib))
307
+ // .forEach(x => toUnrel8ThisRel8nName_Set.add(x));
308
+ // by full addrs impl
309
+ const pastAddrs = ibGib.rel8ns?.past ?? [];
310
+ existingAddrsThisRel8nName
311
+ .filter(x => [...pastAddrs, addr].includes(x))
312
+ .forEach(x => toUnrel8ThisRel8nName_Set.add(x));
313
+ });
314
+ if (toUnrel8ThisRel8nName_Set.size > 0) {
315
+ addrsToUnRel8 = Array.from(toUnrel8ThisRel8nName_Set);
316
+ }
317
+ }
318
+ // we now have enough to execute the rel8
319
+ await metaspace.rel8ToSpecialIbGib({
320
+ type,
321
+ rel8nName,
322
+ ibGibsToRel8: ibGibs,
323
+ addrsToUnRel8,
324
+ space,
325
+ linked: false,
326
+ severPast: false,
327
+ deletePreviousSpecialIbGib: false, // only used in latest special ibgib
328
+ });
329
+ }
330
+ if (Object.keys(dataToAddOrPatch ?? {}).length > 0) {
331
+ const specialIndex = await fnGetSpecialIndex();
332
+ const resNewSpecial = await mut8({
333
+ src: specialIndex,
334
+ dataToAddOrPatch,
335
+ dna: false,
336
+ linkedRel8ns: [Rel8n.past],
337
+ nCounter: true,
338
+ });
339
+ const newSpecialIbGib = resNewSpecial.newIbGib;
340
+ // persist
341
+ await persistTransformResult({ resTransform: resNewSpecial, space: space });
342
+ // update the space ibgib which contains the special/config information
343
+ const configKey = getSpecialConfigKey({ type });
344
+ await metaspace.setConfigAddr({
345
+ key: configKey,
346
+ addr: getIbGibAddr({ ibGib: newSpecialIbGib }),
347
+ space,
348
+ });
349
+ await metaspace.registerNewIbGib({ ibGib: newSpecialIbGib, space, });
350
+ }
351
+ };
352
+ if (skipLock) {
353
+ await fn();
354
+ }
355
+ else {
356
+ // Use execInSpaceWithLocking with the special index type as the scope.
357
+ // We are currently choosing to always lock for special indexes for
358
+ // safety. The skipLock parameter from CommonTimelineOpts is included
359
+ // in the signature for consistency but not used in the locking logic
360
+ // here based on our decision to always lock special indexes.
361
+ await execInSpaceWithLocking({
362
+ scope: type,
363
+ secondsValid: 60,
364
+ maxDelayMs: 100,
365
+ maxLockAttempts: 600,
366
+ space,
367
+ // callerInstanceId: // You might need a way to generate a unique ID for the caller
368
+ fn,
369
+ });
370
+ }
371
+ }
372
+ catch (error) {
373
+ console.error(`${lc} ${extractErrorMsg(error)}`);
374
+ throw error;
375
+ }
376
+ finally {
377
+ if (logalot) {
378
+ console.log(`${lc} complete.`);
379
+ }
380
+ }
381
+ }
382
+ export async function getLatestTimelineIbGibDto_nonLocking({ timeline, timelineAddr, metaspace, space, }) {
383
+ const lc = `[${getLatestTimelineIbGibDto_nonLocking.name}]`;
384
+ try {
385
+ if (logalot) {
386
+ console.log(`${lc} starting... (I: f2b605361368e1956f6db878dbfeb825)`);
387
+ }
388
+ if (!timeline && !timelineAddr) {
389
+ throw new Error(`either timeline or timelineAddr required. (E: 97551b2b18ecd22a18185a783f9a0825)`);
390
+ }
391
+ timelineAddr ??= getIbGibAddr({ ibGib: timeline });
392
+ // const timelineAddr = getIbGibAddr({ ibGib: timeline });
393
+ const latestTimelineIbGibAddr = await metaspace.getLatestAddr({
394
+ addr: timelineAddr,
395
+ space,
396
+ }) ?? timelineAddr;
397
+ if (!latestTimelineIbGibAddr) {
398
+ throw new Error(`${lc} (UNEXPECTED) Could not get latest address for timeline ${getIbGibAddr({ ibGib: timeline })}. (E: a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9)`);
399
+ }
400
+ let latestTimelineIbGibDto; // = toDto({ ibGib: timeline }) as TIbGib;
401
+ if (timelineAddr === latestTimelineIbGibAddr) {
402
+ // latest addr is the same
403
+ if (!timeline) {
404
+ const resGetLatest = await metaspace.get({
405
+ addrs: [latestTimelineIbGibAddr],
406
+ space,
407
+ });
408
+ if (resGetLatest.errorMsg || (resGetLatest.ibGibs ?? []).length !== 1) {
409
+ throw new Error(`${lc} (UNEXPECTED) couldn't get latest timeline ibgib (${latestTimelineIbGibAddr}) from space (${space.ib}). errorMsg: ${resGetLatest.errorMsg ?? '[unknown error]'} (E: 3fc767a594788a43a4ba18c87491a825)`);
410
+ }
411
+ timeline = resGetLatest.ibGibs.at(0);
412
+ }
413
+ latestTimelineIbGibDto = toDto({ ibGib: timeline });
414
+ }
415
+ else {
416
+ // latest addr is different
417
+ const resGetLatest = await metaspace.get({
418
+ addrs: [latestTimelineIbGibAddr],
419
+ space,
420
+ });
421
+ if (resGetLatest.errorMsg || (resGetLatest.ibGibs ?? []).length !== 1) {
422
+ throw new Error(`${lc} (UNEXPECTED) couldn't get latest timeline ibgib (${latestTimelineIbGibAddr}) from space (${space.ib}). errorMsg: ${resGetLatest.errorMsg ?? '[unknown error]'} (E: b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0)`);
423
+ }
424
+ latestTimelineIbGibDto = resGetLatest.ibGibs.at(0);
425
+ }
426
+ return latestTimelineIbGibDto;
427
+ }
428
+ catch (error) {
429
+ console.error(`${lc} ${extractErrorMsg(error)}`);
430
+ throw error;
431
+ }
432
+ finally {
433
+ if (logalot) {
434
+ console.log(`${lc} complete.`);
435
+ }
436
+ }
437
+ }
438
+ export async function mut8Timeline({ timeline, timelineAddr, mut8Opts, metaspace, space, skipLock, timelineIndexInfo, }) {
439
+ const lc = `[${mut8Timeline.name}]`;
440
+ try {
441
+ if (logalot) {
442
+ console.log(`${lc} starting... (I: genuuid)`);
443
+ }
444
+ if (!timeline && !timelineAddr) {
445
+ throw new Error(`(UNEXPECTED) both timeline and timelineAddr falsy? either one is required. (E: a19d98c6acb87af3b876c1484f6ac825)`);
446
+ }
447
+ space ??= await metaspace.getLocalUserSpace({ lock: false });
448
+ if (!space) {
449
+ throw new Error(`(UNEXPECTED) space falsy? couldn't even get default local user space? (E: genuuid)`);
450
+ }
451
+ if (!timeline) {
452
+ const resGet = await metaspace.get({
453
+ addrs: [timelineAddr],
454
+ space,
455
+ });
456
+ if (!resGet.success || resGet.ibGibs?.length !== 1) {
457
+ throw new Error(`couldn't get timeline ibGib from timelineAddr (${timelineAddr}) in space (${space?.ib ?? 'undefined'}) (E: genuuid)`);
458
+ }
459
+ timeline = resGet.ibGibs.at(0);
460
+ }
461
+ const lockScope = await getLockScope({ timeline });
462
+ /**
463
+ * This fn actually does the update and will be executed in the locked
464
+ * setting.
465
+ */
466
+ const fn = async () => {
467
+ if (!space) {
468
+ throw new Error(`(UNEXPECTED) space falsy? couldn't even get default local user space? (E: 845c4181c8c15d7219166ceb3c4dca25)`);
469
+ }
470
+ // Get the latest version of the provided timeline ibgib.
471
+ if (!timeline) {
472
+ throw new Error(`(UNEXPECTED) timeline falsy? we should be ensured that it's truthy at this point. (E: 2e1758b2cc3820531f7ac7f5f6b3a825)`);
473
+ }
474
+ const latestTimelineIbGibDto = await getLatestTimelineIbGibDto_nonLocking({
475
+ timeline, metaspace, space,
476
+ });
477
+ // adjust mut8Opts depending
478
+ const resMut8 = await mut8({
479
+ ...mut8Opts,
480
+ src: latestTimelineIbGibDto,
481
+ dna: true,
482
+ nCounter: true,
483
+ });
484
+ const newTimelineIbGib = resMut8.newIbGib;
485
+ // Persist the transform result.
486
+ await metaspace.persistTransformResult({ resTransform: resMut8, space });
487
+ // If timelineIndexInfo is provided, update the special index.
488
+ if (timelineIndexInfo) {
489
+ await updateSpecialIndex({
490
+ type: timelineIndexInfo.type,
491
+ rel8nInfos: [{ rel8nName: timelineIndexInfo.rel8nName, ibGibs: [newTimelineIbGib] }],
492
+ metaspace,
493
+ space,
494
+ skipLock,
495
+ });
496
+ }
497
+ // should we publish within the lock or not within the lock?
498
+ // should we await the publish or spin it off
499
+ // right now I have this spin off, inside the lock
500
+ // await metaspace.registerNewIbGib({ ibGib: newTimelineIbGib, space });
501
+ // we await the register call because this spins off the publish events (we are assuming implementation details here)
502
+ await metaspace.registerNewIbGib({ ibGib: newTimelineIbGib, space }); // already spins off
503
+ return newTimelineIbGib;
504
+ };
505
+ const newTimelineIbGib = skipLock ?
506
+ await fn() :
507
+ await execInSpaceWithLocking({
508
+ scope: lockScope,
509
+ secondsValid: 180,
510
+ maxDelayMs: 100,
511
+ maxLockAttempts: 1800,
512
+ space,
513
+ callerInstanceId: getTimestampInTicks(),
514
+ fn,
515
+ });
516
+ return newTimelineIbGib;
517
+ }
518
+ catch (error) {
519
+ console.error(`${lc} ${extractErrorMsg(error)}`);
520
+ throw error;
521
+ }
522
+ finally {
523
+ if (logalot) {
524
+ console.log(`${lc} complete.`);
525
+ }
526
+ }
527
+ }
528
+ // todo: implement simplified locking wrappers to raw `rel8`, and `fork`
529
+ // transforms functions. These should be `rel8Timeline`, and `forkTimeline`. But
530
+ // these should not have skipLock available, since at that point you're really
531
+ // basically doing the raw transforms and can use those.
532
+ /**
533
+ * Creates a new ibGib timeline and persists it to the given space.
534
+ *
535
+ * This is the primary entry point for creating any new, trackable piece of data
536
+ * in the ibGib system.
537
+ *
538
+ * ## On usage of this factory function
539
+ *
540
+ * This is often used for one-offs or testing, but usually you will want to
541
+ * create your own factory function and use this internally.
542
+ *
543
+ * ## On "New" vs. "Fork"
544
+ *
545
+ * Every ibGib is a transformation (a "fork") of an existing ibgib, with the
546
+ * most primitive ibGib being the {@link ROOT} primitive. This is like the ibgib
547
+ * analog to a zero/infinity value (the same asymptote from two sides), or in CS
548
+ * OOP, this is like the root/base of the class hierarchy. But it's important to
549
+ * keep in mind that time is a first-class citizen and that we are always
550
+ * working with that instead of some detached "new" siloed thing.
551
+ *
552
+ * ## On Parenting
553
+ *
554
+ * The identity of an ibGib is tied to its ancestry via the `ancestor` rel8n
555
+ * (`someIbGib.rel8ns.ancestor`). This function gives you two ways to specify
556
+ * the parent to fork:
557
+ *
558
+ * 1. {@link parentIb}: If you provide a simple string like `'comment'` or `'picture'`,
559
+ * this function will handle creating the "primitive" parent ibGib
560
+ * (`comment^gib` or `picture^gib`) for you. This is the easiest way to
561
+ * create "typed" data, so that if you examine the `ancestor` rel8n, and see
562
+ * this, you know would know that this ibgib is a "comment" or "picture". Use
563
+ * this if you are not forking a particular instance of another ibGib.
564
+ *
565
+ * 2. {@link parentIbGib}: Provide a full, existing `IbGib` reference to be the
566
+ * parent. This can be used when using a previous ibGib as a template for
567
+ * just one use case. Note that this parent ibgib (and all of its
568
+ * dependency graph) must exist in the same given {@link space} (if
569
+ * provided), or in the default local user space via the {@link metaspace}.
570
+ * Almost always (always?), an existing parent ibgib will itself ultimately
571
+ * descend from a primitive ibgib.
572
+ *
573
+ * If neither `parentIb` nor `parentIbGib` is provided, it defaults to forking
574
+ * the absolute {@link ROOT} ibGib, resulting in a generic, untyped timeline (or
575
+ * relegates the typing to some other mechanism, like the `ibGib.ib` or other).
576
+ *
577
+ * @returns The entire transform result object, which includes `newIbGib` (the
578
+ * latest/head of the newly created timeline) and `intermediateIbGibs` (the
579
+ * primitive ibGibs that form its DNA and any interstitial ibGibs that were
580
+ * created).
581
+ */
582
+ export async function createTimeline({ ib, data, rel8ns, parentIb, parentIbGib, metaspace, space, }) {
583
+ const lc = `[${createTimeline.name}]`;
584
+ try {
585
+ if (logalot) {
586
+ console.log(`${lc} starting...`);
587
+ }
588
+ space ??= await metaspace.getLocalUserSpace({ lock: false });
589
+ if (!space) {
590
+ throw new Error(`(UNEXPECTED) space is required, but is falsy. (E: 252994a554224b17aa9816c7a765c925)`);
591
+ }
592
+ // Determine the parent to fork based on the provided options.
593
+ parentIbGib ??= parentIb ?
594
+ // Easiest consumer-friendly path: create a primitive parent from a string.
595
+ parentIbGib = Factory_V1.primitive({ ib: parentIb }) :
596
+ // Default to the absolute ROOT if no parent info is given.
597
+ parentIbGib = ROOT;
598
+ const resNew = await Factory_V1.firstGen({
599
+ parentIbGib,
600
+ ib,
601
+ data,
602
+ rel8ns,
603
+ // these options are what make this a "timeline"
604
+ dna: true,
605
+ nCounter: true,
606
+ tjp: { timestamp: true, uuid: true },
607
+ });
608
+ // Persist the new timeline and its DNA to the designated space.
609
+ await metaspace.persistTransformResult({ resTransform: resNew, space });
610
+ await metaspace.registerNewIbGib({ ibGib: resNew.newIbGib, space });
611
+ // We don't need to lock here because it's a new, independent timeline,
612
+ // so there are no concurrency concerns yet.
613
+ return resNew;
614
+ }
615
+ catch (error) {
616
+ console.error(`${lc} ${extractErrorMsg(error)}`);
617
+ throw error;
618
+ }
619
+ }
620
+ /**
621
+ * Retrieves the DNA ibGibs for a given ibGib.
622
+ *
623
+ * In V1, DNA is considered atomic and is not nested. This function performs a
624
+ * direct lookup of the ibGibs pointed to by the `dna` rel8n.
625
+ *
626
+ * @returns An array of the primitive DNA ibGibs.
627
+ */
628
+ export async function getDna({ ibGib, metaspace, space, }) {
629
+ const lc = `[${getDna.name}]`;
630
+ try {
631
+ if (logalot) {
632
+ console.log(`${lc} starting...`);
633
+ }
634
+ space ??= await metaspace.getLocalUserSpace({ lock: false });
635
+ if (!space) {
636
+ throw new Error(`(UNEXPECTED) space is required. (E: c1b9a9b8c7d6e5f4a3b2a1a0b9c8d7e6)`);
637
+ }
638
+ const dnaAddrs = ibGib.rel8ns?.dna ?? [];
639
+ if (dnaAddrs.length === 0) {
640
+ return [];
641
+ }
642
+ const resGet = await metaspace.get({ addrs: dnaAddrs, space });
643
+ if (!resGet.success || (resGet.ibGibs ?? []).length !== dnaAddrs.length) {
644
+ const notFound = dnaAddrs.filter(addr => !resGet.ibGibs?.some(x => getIbGibAddr({ ibGib: x }) === addr));
645
+ throw new Error(`Could not get all dna ibGibs for ${getIbGibAddr({ ibGib })}. Addrs not found: ${notFound.join(', ')}. Errors: ${resGet.errorMsg ?? '[unknown error (E: 92cf95774828d8a978331da859098625)]'} (E: d2c0b1a9a8b7c6d5e4f3a2b1a0b9c8d7)`);
646
+ }
647
+ return resGet.ibGibs;
648
+ }
649
+ catch (error) {
650
+ console.error(`${lc} ${extractErrorMsg(error)}`);
651
+ throw error;
652
+ }
653
+ }
654
+ /**
655
+ * Constructs a {@link TimelineHistoryInfo} record about the given timeline
656
+ * (using the {@link timeline} `ibGib.rel8ns.past`), with loaded past ibgibs,
657
+ * and if {@link includeDna}, a reference to their dna ibgibs as well.
658
+ *
659
+ * @returns A complete, ordered array of ibGibs constituting the timeline,
660
+ * from the earliest ancestor to the provided `timeline` ibGib.
661
+ */
662
+ export async function getHistory({ timeline, getLatest, includeDna, metaspace, space, }) {
663
+ const lc = `[${getHistory.name}]`;
664
+ try {
665
+ if (logalot) {
666
+ console.log(`${lc} starting... (I: 7fbc442a27e8f9fda8ac4228ded84825)`);
667
+ }
668
+ space ??= await metaspace.getLocalUserSpace({ lock: false });
669
+ if (!space) {
670
+ throw new Error(`(UNEXPECTED) space is required. (E: e3d1c0b1a9a8b7c6d5e4f3a2b1a0b9c8)`);
671
+ }
672
+ const ibGibsToMap = (ibgibs) => {
673
+ const map = {};
674
+ ibgibs.forEach(x => { map[getIbGibAddr({ ibGib: x })] = x; });
675
+ return map;
676
+ };
677
+ const headIbGib = getLatest ?
678
+ await getLatestTimelineIbGibDto_nonLocking({ timeline, metaspace, space }) :
679
+ toDto({ ibGib: timeline });
680
+ const headAddr = getIbGibAddr({ ibGib: headIbGib });
681
+ let pastIbGibMap = {};
682
+ const dnaMap = includeDna ?
683
+ ibGibsToMap(await getDna({ ibGib: headIbGib, metaspace, space })) :
684
+ undefined;
685
+ const pastAddrs = timeline.rel8ns?.past ?? [];
686
+ if (pastAddrs.length === 0) {
687
+ return {
688
+ headIbGib,
689
+ orderedPastIbGibs: [],
690
+ pastIbGibMap,
691
+ dnaMap,
692
+ }; /* <<<< returns early */
693
+ }
694
+ const resGet = await metaspace.get({ addrs: pastAddrs, space });
695
+ if (!resGet.success || (resGet.ibGibs ?? []).length !== pastAddrs.length) {
696
+ const notFound = pastAddrs.filter(addr => !resGet.ibGibs?.some(x => getIbGibAddr({ ibGib: x }) === addr));
697
+ throw new Error(`Could not get all dna ibGibs for ${headAddr}. Addrs not found: ${notFound.join(', ')}. Errors: ${resGet.errorMsg ?? '[unknown error (E: 887339d8b5580ed1ac9892a554255525)]'} (E: 4ab7a8a58adff4e238171f7c110c6825)`);
698
+ }
699
+ pastIbGibMap = ibGibsToMap(resGet.ibGibs);
700
+ const orderedPastIbGibs = [];
701
+ for (const pastAddr of pastAddrs) {
702
+ const pastIbGib = pastIbGibMap[pastAddr];
703
+ if (!pastIbGib) {
704
+ throw new Error(`(UNEXPECTED) pastIbGib falsy? due to our logic, the pastIbGibMap should be complete. (E: 6010d8c14184124008631928e1265525)`);
705
+ }
706
+ orderedPastIbGibs.push(pastIbGib);
707
+ }
708
+ return {
709
+ headIbGib,
710
+ orderedPastIbGibs,
711
+ pastIbGibMap,
712
+ dnaMap,
713
+ };
714
+ }
715
+ catch (error) {
716
+ console.error(`${lc} ${extractErrorMsg(error)}`);
717
+ throw error;
718
+ }
719
+ finally {
720
+ if (logalot) {
721
+ console.log(`${lc} complete.`);
722
+ }
723
+ }
724
+ }
725
+ //# sourceMappingURL=timeline-api.mjs.map