@ibgib/core-gib 0.1.22 → 0.1.23

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 (78) hide show
  1. package/dist/common/other/graph-helper.d.mts +8 -0
  2. package/dist/common/other/graph-helper.d.mts.map +1 -1
  3. package/dist/common/other/graph-helper.mjs +31 -1
  4. package/dist/common/other/graph-helper.mjs.map +1 -1
  5. package/dist/sync/sync-conflict.respec.mjs +12 -11
  6. package/dist/sync/sync-conflict.respec.mjs.map +1 -1
  7. package/dist/sync/sync-constants.d.mts +14 -4
  8. package/dist/sync/sync-constants.d.mts.map +1 -1
  9. package/dist/sync/sync-constants.mjs +15 -3
  10. package/dist/sync/sync-constants.mjs.map +1 -1
  11. package/dist/sync/sync-helpers.d.mts +22 -15
  12. package/dist/sync/sync-helpers.d.mts.map +1 -1
  13. package/dist/sync/sync-helpers.mjs +159 -90
  14. package/dist/sync/sync-helpers.mjs.map +1 -1
  15. package/dist/sync/sync-innerspace-constants.respec.mjs +11 -10
  16. package/dist/sync/sync-innerspace-constants.respec.mjs.map +1 -1
  17. package/dist/sync/sync-innerspace-deep-updates.respec.mjs +11 -10
  18. package/dist/sync/sync-innerspace-deep-updates.respec.mjs.map +1 -1
  19. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs +11 -10
  20. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs.map +1 -1
  21. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs +12 -10
  22. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs.map +1 -1
  23. package/dist/sync/sync-innerspace-partial-update.respec.mjs +14 -10
  24. package/dist/sync/sync-innerspace-partial-update.respec.mjs.map +1 -1
  25. package/dist/sync/sync-innerspace.respec.mjs +12 -10
  26. package/dist/sync/sync-innerspace.respec.mjs.map +1 -1
  27. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.d.mts +0 -15
  28. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.d.mts.map +1 -1
  29. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts +15 -14
  30. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts.map +1 -1
  31. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs +9 -55
  32. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs.map +1 -1
  33. package/dist/sync/sync-peer/sync-peer-types.d.mts +16 -0
  34. package/dist/sync/sync-peer/sync-peer-types.d.mts.map +1 -1
  35. package/dist/sync/sync-peer/sync-peer-v1.d.mts +39 -5
  36. package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
  37. package/dist/sync/sync-peer/sync-peer-v1.mjs +141 -4
  38. package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
  39. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts +22 -3
  40. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts.map +1 -1
  41. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs +104 -31
  42. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs.map +1 -1
  43. package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts +5 -0
  44. package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts.map +1 -1
  45. package/dist/sync/sync-saga-coordinator.d.mts +74 -70
  46. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  47. package/dist/sync/sync-saga-coordinator.mjs +475 -527
  48. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  49. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts +105 -22
  50. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts.map +1 -1
  51. package/dist/sync/sync-types.d.mts +56 -88
  52. package/dist/sync/sync-types.d.mts.map +1 -1
  53. package/dist/sync/sync-types.mjs +5 -0
  54. package/dist/sync/sync-types.mjs.map +1 -1
  55. package/dist/timeline/timeline-api.d.mts.map +1 -1
  56. package/dist/timeline/timeline-api.mjs +15 -8
  57. package/dist/timeline/timeline-api.mjs.map +1 -1
  58. package/package.json +1 -1
  59. package/src/common/other/graph-helper.mts +26 -1
  60. package/src/sync/sync-conflict.respec.mts +12 -11
  61. package/src/sync/sync-constants.mts +15 -4
  62. package/src/sync/sync-helpers.mts +167 -95
  63. package/src/sync/sync-innerspace-constants.respec.mts +11 -10
  64. package/src/sync/sync-innerspace-deep-updates.respec.mts +11 -10
  65. package/src/sync/sync-innerspace-dest-ahead.respec.mts +11 -10
  66. package/src/sync/sync-innerspace-multiple-timelines.respec.mts +12 -10
  67. package/src/sync/sync-innerspace-partial-update.respec.mts +14 -12
  68. package/src/sync/sync-innerspace.respec.mts +12 -10
  69. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.mts +0 -15
  70. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +16 -65
  71. package/src/sync/sync-peer/sync-peer-types.mts +17 -0
  72. package/src/sync/sync-peer/sync-peer-v1.mts +141 -8
  73. package/src/sync/sync-saga-context/sync-saga-context-helpers.mts +116 -37
  74. package/src/sync/sync-saga-context/sync-saga-context-types.mts +5 -0
  75. package/src/sync/sync-saga-coordinator.mts +525 -617
  76. package/src/sync/sync-saga-message/sync-saga-message-types.mts +106 -22
  77. package/src/sync/sync-types.mts +59 -101
  78. package/src/timeline/timeline-api.mts +17 -10
@@ -1,8 +1,9 @@
1
1
  import { IbGib_V1, IbGibData_V1, IbGibRel8ns_V1 } from "@ibgib/ts-gib/dist/V1/types.mjs";
2
2
  import { KeystoneIbGib_V1 } from "../../keystone/keystone-types.mjs";
3
3
  import { SyncStage } from "../sync-constants.mjs";
4
- import { SyncMode, SyncConflictStrategy, SyncInitData, SyncRequestData, SyncDeltaData, SyncCommitData } from "../sync-types.mjs";
4
+ import { SyncMode, SyncConflictStrategy, } from "../sync-types.mjs";
5
5
  import { SYNC_SAGA_MSG_ATOM } from "./sync-saga-message-constants.mjs";
6
+ import { IbGibAddr } from "@ibgib/ts-gib/dist/types.mjs";
6
7
 
7
8
  export interface SyncSagaMessageIb_V1 {
8
9
  atom: typeof SYNC_SAGA_MSG_ATOM;
@@ -33,9 +34,66 @@ export interface SyncSagaMessageIbGib_V1 extends IbGib_V1<SyncSagaMessageData_V1
33
34
  // CONCRETE MESSAGE PAYLOADS (EXTENDING DATA)
34
35
  // ===========================================================================
35
36
 
36
- export interface SyncSagaMessageInitData_V1 extends SyncSagaMessageData_V1, SyncInitData {
37
+ /**
38
+ * The "Hello" of the sync protocol.
39
+ *
40
+ * Exchanges knowledge vectors (what I have) and identity (who I am).
41
+ */
42
+ export interface SyncSagaMessageInitData_V1 extends SyncSagaMessageData_V1 {
37
43
  stage: typeof SyncStage.init;
38
44
  stones: string[];
45
+ /**
46
+ * Map of TJP (Temporal Joint Point) to latest known ibGibAddr.
47
+ * Use this to calculate what is missing (Delta).
48
+ *
49
+ * IOW, this is a map of the starting and end points of an ibGib's timeline.
50
+ */
51
+ knowledgeVector: { [tjp: string]: IbGibAddr };
52
+
53
+ /**
54
+ * The Keystone Identity of the sender.
55
+ * Required for the first handshake or if the receiver doesn't know the sender.
56
+ */
57
+ identity?: KeystoneIbGib_V1;
58
+
59
+ /**
60
+ * What the sender wants to do.
61
+ * e.g. "push" (I have data for you) or "pull" (Give me data).
62
+ * @default 'push'
63
+ */
64
+ mode?: SyncMode;
65
+
66
+ /**
67
+ * This is also in the sync saga ibgib itself now...
68
+ *
69
+ * @see {@link SyncOptions.conflictStrategy}
70
+ */
71
+ conflictStrategy?: SyncConflictStrategy;
72
+ }
73
+
74
+ export interface SyncSagaConflictInfo {
75
+ tjpAddr: string;
76
+ /**
77
+ * "local" is relative to the POV of the creator of the conflict info
78
+ */
79
+ localAddr: string;
80
+ /**
81
+ * "remote" is relative to the POV of the creator of the conflict info
82
+ */
83
+ remoteAddr: string;
84
+ /**
85
+ * Full history of the timeline from the Receiver's perspective.
86
+ * Used by Sender to find LCA.
87
+ */
88
+ timelineAddrs: string[];
89
+ /**
90
+ * string description
91
+ */
92
+ reason: string;
93
+ /**
94
+ * if true, this conflict should abort the sync
95
+ */
96
+ terminal: boolean;
39
97
  }
40
98
 
41
99
  export interface SyncSagaMessageAckData_V1 extends SyncSagaMessageData_V1 {
@@ -43,31 +101,37 @@ export interface SyncSagaMessageAckData_V1 extends SyncSagaMessageData_V1 {
43
101
  deltaReqAddrs: string[];
44
102
  pushOfferAddrs: string[];
45
103
  /**
46
- * Map of group keys (TJP or Constant Addr) to list of known addresses (Full History).
47
- * Used by Sender to calculate differential payloads.
104
+ * Map of group keys (TJP addr/constant addr) to list of known addresses
105
+ * in that timeline.
106
+ *
107
+ * This will be used by Sender to calculate differential payloads. So
108
+ * when the sender goes to get the dependency graph of its tip ibgib,
109
+ * it can skip all of the addrs in this.
110
+ *
111
+ * For example, say sender has A^5 and receiver only has A^3. Sender
112
+ * will see in this map { [A^0]: [A^0, A^1, A^2, A^3] } and know that
113
+ * it needs all of the dependencies of A^5 (including A^4), but it does
114
+ * NOT need to send A^0-A^3 (and dependencies) because receiver already has
115
+ * these.
48
116
  */
49
- knowledgeVector?: { [groupKey: string]: string[] };
117
+ knowledgeVector?: { [tjpAddr: string]: string[] };
50
118
  /**
51
119
  * List of identified conflicts.
52
120
  *
53
- * If present, the Sender should use the `timelineAddrs` (Receiver's history)
54
- * to compute the LCA and delta requirements for merging.
55
- */
56
- conflicts?: {
57
- tjpAddr: string;
58
- localAddr: string;
59
- remoteAddr: string;
60
- /**
61
- * Full history of the timeline from the Receiver's perspective.
62
- * Used by Sender to find LCA.
63
- */
64
- timelineAddrs: string[];
65
- reason: string;
66
- terminal: boolean;
67
- }[];
121
+ * If present, the Sender should use the `timelineAddrs` (Receiver's
122
+ * history) to compute the LCA and delta requirements for merging.
123
+ */
124
+ conflicts?: SyncSagaConflictInfo[];
68
125
  }
69
126
 
70
- export interface SyncSagaMessageDeltaData_V1 extends SyncSagaMessageData_V1, SyncDeltaData {
127
+ /**
128
+ * The "Body" of the sync protocol. Carries the manifests of data to be
129
+ * transferred.
130
+ *
131
+ * If any {@link payloadAddrsDomain} exist, then these will be populated in the
132
+ * {@link SyncSagaContextIbGib_V1}.
133
+ */
134
+ export interface SyncSagaMessageDeltaData_V1 extends SyncSagaMessageData_V1 {
71
135
  stage: typeof SyncStage.delta;
72
136
  requests?: string[];
73
137
  /**
@@ -75,9 +139,29 @@ export interface SyncSagaMessageDeltaData_V1 extends SyncSagaMessageData_V1, Syn
75
139
  * and is ready to commit the transaction.
76
140
  */
77
141
  proposeCommit?: boolean;
142
+ /**
143
+ * Domain ibgib addresses (actual user data being synced).
144
+ * These go to tempSpace ONLY until final commit.
145
+ */
146
+ payloadAddrsDomain?: string[];
78
147
  }
79
148
 
80
- export interface SyncSagaMessageCommitData_V1 extends SyncSagaMessageData_V1, SyncCommitData {
149
+ /**
150
+ * The "Seal" of the sync protocol.
151
+ */
152
+ export interface SyncSagaMessageCommitData_V1 extends SyncSagaMessageData_V1 {
81
153
  stage: typeof SyncStage.commit;
154
+ /**
155
+ * True if the session completed successfully from the sender's perspective.
156
+ */
157
+ success: boolean;
158
+ /**
159
+ * Optional verification metadata (e.g. success count).
160
+ */
161
+ successCount?: number;
162
+ /**
163
+ * If failed, the reasons why.
164
+ */
165
+ errors?: string[];
82
166
  }
83
167
 
@@ -1,10 +1,15 @@
1
+ import { IbGibAddr } from "@ibgib/ts-gib/dist/types.mjs";
1
2
  import { IbGib_V1, IbGibData_V1, IbGibRel8ns_V1 } from "@ibgib/ts-gib/dist/V1/types.mjs";
2
3
 
3
- import { KeystoneIbGib_V1, KeystoneProof } from "../keystone/keystone-types.mjs";
4
- import { SYNC_ATOM, SyncStage } from "./sync-constants.mjs";
4
+ import { SubjectWitness } from "../common/pubsub/subject/subject-types.mjs";
5
+ import { SyncSagaContextIbGib_V1 } from "./sync-saga-context/sync-saga-context-types.mjs";
6
+ import { KeystoneIbGib_V1, } from "../keystone/keystone-types.mjs";
7
+ import { SYNC_ATOM, SYNC_MSG_REL8N_NAME, } from "./sync-constants.mjs";
5
8
  import { IbGibSpaceAny } from "../witness/space/space-base-v1.mjs";
6
9
  import { MetaspaceService } from "../witness/space/metaspace/metaspace-types.mjs";
7
10
  import { SyncPeerWitness } from "./sync-peer/sync-peer-types.mjs";
11
+ import { FlatIbGibGraph } from "../common/other/graph-types.mjs";
12
+ import { SyncSagaConflictInfo } from "./sync-saga-message/sync-saga-message-types.mjs";
8
13
 
9
14
 
10
15
  // #region SyncMode
@@ -34,6 +39,9 @@ export type SyncConflictStrategy =
34
39
  | typeof SYNC_CONFLICT_STRATEGY_ABORT
35
40
  | typeof SYNC_CONFLICT_STRATEGY_OPTIMISTIC
36
41
  | typeof SYNC_CONFLICT_STRATEGY_MANUAL;
42
+ /**
43
+ * @see {@link SyncOptions.conflictStrategy}
44
+ */
37
45
  export const SyncConflictStrategy = {
38
46
  abort: SYNC_CONFLICT_STRATEGY_ABORT,
39
47
  optimistic: SYNC_CONFLICT_STRATEGY_OPTIMISTIC,
@@ -45,6 +53,16 @@ export function isValidSyncConflictStrategy(strategy: string): strategy is SyncC
45
53
  }
46
54
  // #endregion SyncConflictStrategy
47
55
 
56
+ /**
57
+ * Result of handling a saga frame.
58
+ * Separates control and domain payloads.
59
+ */
60
+ export interface HandleSagaFrameResult {
61
+ frame: SyncIbGib_V1;
62
+ payloadIbGibsDomain?: IbGib_V1[];
63
+ conflictInfos?: SyncSagaConflictInfo;
64
+ }
65
+
48
66
  export interface SyncOptions {
49
67
  /**
50
68
  * The peer we are syncing with.
@@ -81,110 +99,71 @@ export interface SyncOptions {
81
99
  */
82
100
  identitySecret?: string;
83
101
  /**
84
- * How to handle conflicts when both Source and Dest have diverged on the same timeline.
102
+ * How to handle conflicts when both Source and Dest have diverged on the
103
+ * same timeline.
104
+ *
85
105
  * @default 'abort'
86
106
  */
87
107
  conflictStrategy?: SyncConflictStrategy;
88
108
  /**
89
- * @deprecated Use `identity` instead if you have a specific identity.
90
- * If true, creates an ephemeral session identity.
109
+ * If true, creates an ephemeral session identity for the sync process to
110
+ * secure the sync transaction itself.
111
+ *
91
112
  * @default true
92
113
  */
93
114
  useSessionIdentity?: boolean;
94
115
  }
95
116
 
96
- // ===========================================================================
97
- // PROTOCOL PAYLOADS
98
- // ===========================================================================
99
-
100
- /**
101
- * The "Hello" of the sync protocol.
102
- * Exchanges knowledge vectors (what I have) and identity (who I am).
103
- */
104
- export interface SyncInitData {
117
+ export interface SyncSagaInfo {
105
118
  /**
106
- * Map of TJP (Temporal Joint Point) to latest known ibGibAddr.
107
- * Use this to calculate what is missing (Delta).
108
- *
109
- * IOW, this is a map of the starting and end points of an ibGib's timeline.
119
+ * The unique ID of the saga.
110
120
  */
111
- knowledgeVector: { [tjp: string]: string };
121
+ sagaId: string;
112
122
 
113
123
  /**
114
- * The Keystone Identity of the sender.
115
- * Required for the first handshake or if the receiver doesn't know the sender.
124
+ * Observable stream of context updates happening during the saga.
125
+ *
126
+ * Subscribe to this to receive real-time progress throughout the sync
127
+ * process, whenever the sync ibgib is evolved (including when receiving a
128
+ * response from the peer).
116
129
  */
117
- identity?: KeystoneIbGib_V1;
130
+ updates$: SubjectWitness<SyncSagaContextIbGib_V1>;
118
131
 
119
132
  /**
120
- * What the sender wants to do.
121
- * e.g. "push" (I have data for you) or "pull" (Give me data).
122
- * @default 'push'
133
+ * Promise that resolves when the saga completes successfully.
123
134
  */
124
- mode?: SyncMode;
125
- conflictStrategy?: SyncConflictStrategy;
135
+ done: Promise<void>;
126
136
  }
127
137
 
128
- /**
129
- * A specific request for data.
130
- * Used for "pull" based deltas or fixing gaps (packet loss).
131
- */
132
- export interface SyncRequestData {
133
- /**
134
- * The ibGib addresses requested.
135
- */
136
- addrs: string[];
138
+ export interface SyncSagaFrameDependencyGraph {
139
+ sagaIbGib: SyncIbGib_V1;
140
+ msgStones: IbGib_V1[];
141
+ identities: KeystoneIbGib_V1[];
137
142
  }
138
143
 
139
144
  /**
140
- * The "Body" of the sync protocol.
141
- * Carries the manifests of data to be transferred.
145
+ * given some group of domain ibgibs, this is info extracted from them.
142
146
  */
143
- export interface SyncDeltaData {
144
- /**
145
- * Control ibgib addresses (sync frames, stones, keystones).
146
- * These go to BOTH destSpace + tempSpace for audit trail.
147
- */
148
- payloadAddrsControl?: string[];
149
-
147
+ export interface DomainIbGibAnalysisInfo {
150
148
  /**
151
- * Domain ibgib addresses (actual user data being synced).
152
- * These go to tempSpace ONLY until final commit.
153
- */
154
- payloadAddrsDomain?: string[];
155
-
156
- /**
157
- * THIS SHOULD NOT EXIST. NOT BE DEPRECATED. JUST REMOVED!!
158
- *
159
- * @deprecated Use payloadAddrsControl + payloadAddrsDomain instead.
160
- * Legacy combined payload addresses.
149
+ * flat array of stones (ibgibs without dna)
161
150
  */
162
- payloadAddrs?: string[];
163
- }
164
-
165
- /**
166
- * The "Seal" of the sync protocol.
167
- * The authority is derived from the `identity` relation on the Keystone Frame.
168
- */
169
- export interface SyncCommitData {
151
+ stones: IbGib_V1[];
170
152
  /**
171
- * True if the session completed successfully from the sender's perspective.
153
+ * map of tjp -> sorted timeline ibgib
172
154
  */
173
- success: boolean;
155
+ timelinesMap: { [tjp: string]: IbGib_V1[] };
174
156
  /**
175
- * Optional verification metadata (e.g. success count).
157
+ * sorted by dependency/interdependency
176
158
  */
177
- successCount?: number;
159
+ topologicallySortedTjpAddrs: IbGibAddr[];
178
160
  /**
179
- * If failed, the reasons why.
161
+ * full dependency graph of domain ibgibs
180
162
  */
181
- errors?: string[];
163
+ fullGraph: FlatIbGibGraph;
182
164
  }
183
165
 
184
- // ===========================================================================
185
- // IBGIB DATA STRUCTURES
186
- // ===========================================================================
187
-
166
+ // #region Sync Ib, Data, Rel8ns, IbGib
188
167
  export interface SyncIb_V1 {
189
168
  atom: typeof SYNC_ATOM;
190
169
  uuid: string;
@@ -218,11 +197,6 @@ export interface SyncData_V1 extends IbGibData_V1 {
218
197
  * 2. Rate limiting / Backpressure (Don't process this old request).
219
198
  */
220
199
  expirationTimestamp?: string;
221
-
222
- /**
223
- * Polymorphic payload based on stage.
224
- */
225
- payload?: SyncInitData | SyncRequestData | SyncDeltaData | SyncCommitData;
226
200
  }
227
201
 
228
202
  export interface SyncRel8ns_V1 extends IbGibRel8ns_V1 {
@@ -231,30 +205,14 @@ export interface SyncRel8ns_V1 extends IbGibRel8ns_V1 {
231
205
  * This MUST point to the specific Keystone Frame that authorizes this sync frame.
232
206
  */
233
207
  identity?: string[];
234
- }
235
-
236
- export interface SyncIbGib_V1 extends IbGib_V1<SyncData_V1, SyncRel8ns_V1> { }
237
-
238
- /**
239
- * Information returned when starting a Sync Saga.
240
- * Allows the caller to subscribe to updates and await completion.
241
- */
242
- import { SubjectWitness } from "../common/pubsub/subject/subject-types.mjs";
243
- import { SyncSagaContextIbGib_V1 } from "./sync-saga-context/sync-saga-context-types.mjs";
244
208
 
245
- export interface SyncSagaInfo {
246
209
  /**
247
- * The unique ID of the saga.
210
+ * The message stone that contains the information about the particular
211
+ * stage of the sync process we are in.
248
212
  */
249
- sagaId: string;
250
- /**
251
- * Stream of context updates happening during the saga.
252
- * Subscribe to this to receive real-time progress.
253
- */
254
- updates$: SubjectWitness<SyncSagaContextIbGib_V1>;
255
-
256
- /**
257
- * Promise that resolves when the saga completes successfully.
258
- */
259
- done: Promise<void>;
213
+ [SYNC_MSG_REL8N_NAME]: IbGibAddr[];
260
214
  }
215
+
216
+ export interface SyncIbGib_V1 extends IbGib_V1<SyncData_V1, SyncRel8ns_V1> { }
217
+
218
+ // #endregion Sync Ib, Data, Rel8ns, IbGib
@@ -27,6 +27,8 @@ import { SpecialIbGibType } from "../common/other/other-types.mjs";
27
27
  import { getSpecialConfigKey, toDto } from "../common/other/ibgib-helper.mjs";
28
28
  import { execInSpaceWithLocking, getFromSpace, persistTransformResult } from "../witness/space/space-helper.mjs";
29
29
  import { TimelineHistoryInfo } from "./timeline-types.mjs";
30
+ import { toFlatGraph } from "../common/other/graph-helper.mjs";
31
+ import { FlatIbGibGraph } from "../common/other/graph-types.mjs";
30
32
 
31
33
  const logalot = GLOBAL_LOG_A_LOT;
32
34
 
@@ -845,7 +847,16 @@ export async function createTimeline<TData extends IbGibData_V1 = IbGibData_V1>(
845
847
  dna: noDna ? false : true,
846
848
  nCounter: true,
847
849
  squash: noDna ? true : false,
848
- tjp: { timestamp: true, uuid: true },
850
+ tjp: {
851
+ /**
852
+ * always use the timestamp to generate a unique timeline
853
+ */
854
+ timestamp: true,
855
+ /**
856
+ * only generate new uuid if it's not in the incoming data
857
+ */
858
+ uuid: !data?.uuid,
859
+ },
849
860
  });
850
861
 
851
862
  // Persist the new timeline and its DNA to the designated space.
@@ -938,21 +949,17 @@ export async function getHistory({
938
949
  space ??= await metaspace.getLocalUserSpace({ lock: false });
939
950
  if (!space) { throw new Error(`(UNEXPECTED) space is required. (E: e3d1c0b1a9a8b7c6d5e4f3a2b1a0b9c8)`); }
940
951
 
941
- const ibGibsToMap = (ibgibs: IbGib_V1[]) => {
942
- const map: { [addr: IbGibAddr]: IbGib_V1 } = {};
943
- ibgibs.forEach(x => { map[getIbGibAddr({ ibGib: x })] = x; });
944
- return map;
945
- }
946
-
947
952
  const headIbGib = getLatest ?
948
953
  await getLatestTimelineIbGibDto_nonLocking({ timeline, metaspace, space }) :
949
954
  toDto({ ibGib: timeline }) as IbGib_V1;
950
955
  const headAddr = getIbGibAddr({ ibGib: headIbGib });
951
956
 
952
- let pastIbGibMap: { [addr: IbGibAddr]: IbGib_V1 } = {};
957
+ let pastIbGibMap: FlatIbGibGraph = {};
953
958
 
954
959
  const dnaMap = includeDna ?
955
- ibGibsToMap(await getDna({ ibGib: headIbGib, metaspace, space })) :
960
+ toFlatGraph({
961
+ ibGibs: await getDna({ ibGib: headIbGib, metaspace, space })
962
+ }) :
956
963
  undefined;
957
964
 
958
965
  const pastAddrs = timeline.rel8ns?.past ?? [];
@@ -971,7 +978,7 @@ export async function getHistory({
971
978
  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)`);
972
979
  }
973
980
 
974
- pastIbGibMap = ibGibsToMap(resGet.ibGibs!);
981
+ pastIbGibMap = toFlatGraph({ ibGibs: resGet.ibGibs! }) ?? {};
975
982
 
976
983
  const orderedPastIbGibs: IbGib_V1[] = [];
977
984
  for (const pastAddr of pastAddrs) {