@ibgib/core-gib 0.1.22 → 0.1.25

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 (86) hide show
  1. package/dist/common/other/graph-helper.d.mts +25 -0
  2. package/dist/common/other/graph-helper.d.mts.map +1 -1
  3. package/dist/common/other/graph-helper.mjs +75 -1
  4. package/dist/common/other/graph-helper.mjs.map +1 -1
  5. package/dist/sync/graft-info/graft-info-helpers.mjs +2 -2
  6. package/dist/sync/graft-info/graft-info-helpers.mjs.map +1 -1
  7. package/dist/sync/sync-conflict.respec.mjs +8 -12
  8. package/dist/sync/sync-conflict.respec.mjs.map +1 -1
  9. package/dist/sync/sync-constants.d.mts +14 -4
  10. package/dist/sync/sync-constants.d.mts.map +1 -1
  11. package/dist/sync/sync-constants.mjs +15 -3
  12. package/dist/sync/sync-constants.mjs.map +1 -1
  13. package/dist/sync/sync-helpers.d.mts +22 -15
  14. package/dist/sync/sync-helpers.d.mts.map +1 -1
  15. package/dist/sync/sync-helpers.mjs +159 -90
  16. package/dist/sync/sync-helpers.mjs.map +1 -1
  17. package/dist/sync/sync-innerspace-constants.respec.mjs +8 -9
  18. package/dist/sync/sync-innerspace-constants.respec.mjs.map +1 -1
  19. package/dist/sync/sync-innerspace-deep-updates.respec.mjs +8 -9
  20. package/dist/sync/sync-innerspace-deep-updates.respec.mjs.map +1 -1
  21. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs +8 -9
  22. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs.map +1 -1
  23. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs +8 -9
  24. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs.map +1 -1
  25. package/dist/sync/sync-innerspace-partial-update.respec.mjs +8 -9
  26. package/dist/sync/sync-innerspace-partial-update.respec.mjs.map +1 -1
  27. package/dist/sync/sync-innerspace.respec.mjs +6 -7
  28. package/dist/sync/sync-innerspace.respec.mjs.map +1 -1
  29. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.d.mts +2 -0
  30. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.d.mts.map +1 -1
  31. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs +4 -0
  32. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs.map +1 -1
  33. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.d.mts +0 -15
  34. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.d.mts.map +1 -1
  35. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts +30 -16
  36. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts.map +1 -1
  37. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs +47 -79
  38. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs.map +1 -1
  39. package/dist/sync/sync-peer/sync-peer-types.d.mts +40 -1
  40. package/dist/sync/sync-peer/sync-peer-types.d.mts.map +1 -1
  41. package/dist/sync/sync-peer/sync-peer-v1.d.mts +47 -14
  42. package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
  43. package/dist/sync/sync-peer/sync-peer-v1.mjs +188 -144
  44. package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
  45. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts +39 -3
  46. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts.map +1 -1
  47. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs +137 -31
  48. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs.map +1 -1
  49. package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts +5 -0
  50. package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts.map +1 -1
  51. package/dist/sync/sync-saga-coordinator.d.mts +81 -77
  52. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  53. package/dist/sync/sync-saga-coordinator.mjs +608 -597
  54. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  55. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts +154 -26
  56. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts.map +1 -1
  57. package/dist/sync/sync-types.d.mts +87 -92
  58. package/dist/sync/sync-types.d.mts.map +1 -1
  59. package/dist/sync/sync-types.mjs +6 -2
  60. package/dist/sync/sync-types.mjs.map +1 -1
  61. package/dist/timeline/timeline-api.d.mts.map +1 -1
  62. package/dist/timeline/timeline-api.mjs +15 -8
  63. package/dist/timeline/timeline-api.mjs.map +1 -1
  64. package/package.json +1 -1
  65. package/src/common/other/graph-helper.mts +79 -1
  66. package/src/sync/graft-info/graft-info-helpers.mts +3 -3
  67. package/src/sync/sync-conflict.respec.mts +8 -14
  68. package/src/sync/sync-constants.mts +15 -4
  69. package/src/sync/sync-helpers.mts +173 -101
  70. package/src/sync/sync-innerspace-constants.respec.mts +8 -9
  71. package/src/sync/sync-innerspace-deep-updates.respec.mts +8 -9
  72. package/src/sync/sync-innerspace-dest-ahead.respec.mts +8 -9
  73. package/src/sync/sync-innerspace-multiple-timelines.respec.mts +8 -9
  74. package/src/sync/sync-innerspace-partial-update.respec.mts +9 -12
  75. package/src/sync/sync-innerspace.respec.mts +6 -7
  76. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mts +7 -0
  77. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.mts +0 -15
  78. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +72 -96
  79. package/src/sync/sync-peer/sync-peer-types.mts +43 -2
  80. package/src/sync/sync-peer/sync-peer-v1.mts +215 -142
  81. package/src/sync/sync-saga-context/sync-saga-context-helpers.mts +145 -37
  82. package/src/sync/sync-saga-context/sync-saga-context-types.mts +5 -0
  83. package/src/sync/sync-saga-coordinator.mts +680 -714
  84. package/src/sync/sync-saga-message/sync-saga-message-types.mts +160 -24
  85. package/src/sync/sync-types.mts +96 -105
  86. package/src/timeline/timeline-api.mts +17 -10
@@ -1,8 +1,11 @@
1
1
  import { IbGib_V1, IbGibData_V1, IbGibRel8ns_V1 } from "@ibgib/ts-gib/dist/V1/types.mjs";
2
+ import { IbGibAddr } from "@ibgib/ts-gib/dist/types.mjs";
3
+
2
4
  import { KeystoneIbGib_V1 } from "../../keystone/keystone-types.mjs";
3
5
  import { SyncStage } from "../sync-constants.mjs";
4
- import { SyncMode, SyncConflictStrategy, SyncInitData, SyncRequestData, SyncDeltaData, SyncCommitData } from "../sync-types.mjs";
6
+ import { SyncMode, SyncConflictStrategy, } from "../sync-types.mjs";
5
7
  import { SYNC_SAGA_MSG_ATOM } from "./sync-saga-message-constants.mjs";
8
+ import type { getDeltaDependencyGraph } from '../../common/other/graph-helper.mjs';
6
9
 
7
10
  export interface SyncSagaMessageIb_V1 {
8
11
  atom: typeof SYNC_SAGA_MSG_ATOM;
@@ -33,41 +36,154 @@ export interface SyncSagaMessageIbGib_V1 extends IbGib_V1<SyncSagaMessageData_V1
33
36
  // CONCRETE MESSAGE PAYLOADS (EXTENDING DATA)
34
37
  // ===========================================================================
35
38
 
36
- export interface SyncSagaMessageInitData_V1 extends SyncSagaMessageData_V1, SyncInitData {
39
+ /**
40
+ * The "Hello" of the sync protocol.
41
+ *
42
+ * Exchanges knowledge vectors (what I have) and identity (who I am).
43
+ */
44
+ export interface SyncSagaMessageInitData_V1 extends SyncSagaMessageData_V1 {
37
45
  stage: typeof SyncStage.init;
38
46
  stones: string[];
47
+ /**
48
+ * Map of TJP (Temporal Joint Point) to latest known ibGibAddr.
49
+ * Use this to calculate what is missing (Delta).
50
+ *
51
+ * IOW, this is a map of the starting and end points of an ibGib's timeline.
52
+ */
53
+ knowledgeVector: { [tjp: string]: IbGibAddr };
54
+
55
+ /**
56
+ * The Keystone Identity of the sender.
57
+ * Required for the first handshake or if the receiver doesn't know the sender.
58
+ */
59
+ identity?: KeystoneIbGib_V1;
60
+
61
+ /**
62
+ * What the sender wants to do.
63
+ * e.g. "push" (I have data for you) or "pull" (Give me data).
64
+ * @default 'push'
65
+ */
66
+ mode?: SyncMode;
67
+
68
+ /**
69
+ * This is also in the sync saga ibgib itself now...
70
+ *
71
+ * @see {@link SyncOptions.conflictStrategy}
72
+ */
73
+ conflictStrategy?: SyncConflictStrategy;
74
+ }
75
+
76
+ /**
77
+ * When an endpoing doesn't have a timeline or some part of it, then this info
78
+ * contains sufficient information for the other endpoint to know what addrs to
79
+ * send.
80
+ */
81
+ export interface SyncSagaRequestAddrInfo {
82
+ /**
83
+ * We know this addr exists, but we don't have it. If we don't know anything
84
+ * about this timeline, then this will equal {@link tjpAddr}
85
+ */
86
+ addr: IbGibAddr;
87
+ /**
88
+ * if we're talking about an ibgib with a timeline (with ibgib.rel8ns.tjp),
89
+ * then this will be that timeline's addr (tjpAddr).
90
+ */
91
+ tjpAddr?: IbGibAddr;
92
+ /**
93
+ * If this is truthy, then we already have something from this timeline and
94
+ * this will be the latest addr in that timeline.
95
+ *
96
+ * If falsy, then we are requesting the entire timeline be sent.
97
+ *
98
+ * This is to be used to calculate the delta graph.
99
+ * @see {@link getDeltaDependencyGraph}
100
+ */
101
+ latestAddrAlreadyHave?: IbGibAddr;
102
+ }
103
+
104
+ /**
105
+ * when one endpoint says "hey, i have these that you need", they create this.
106
+ */
107
+ export interface SyncSagaPushOfferInfo {
108
+ /**
109
+ * all addrs to be pushed, should be the entire delta dependency graph.
110
+ * @see {@link getDeltaDependencyGraph}
111
+ */
112
+ addrs: IbGibAddr[];
113
+ /**
114
+ * if we're talking about an ibgib with a timeline (with ibgib.rel8ns.tjp),
115
+ * then this will be that timeline's addr (tjpAddr).
116
+ */
117
+ tjpAddr?: IbGibAddr;
118
+ }
119
+
120
+ export interface SyncSagaConflictInfo {
121
+ tjpAddr: string;
122
+ /**
123
+ * "local" is relative to the POV of the creator of the conflict info
124
+ */
125
+ localAddr: string;
126
+ /**
127
+ * "remote" is relative to the POV of the creator of the conflict info
128
+ */
129
+ remoteAddr: string;
130
+ /**
131
+ * Full history of the timeline from the Receiver's perspective.
132
+ * Used by Sender to find LCA.
133
+ */
134
+ timelineAddrs: string[];
135
+ /**
136
+ * string description
137
+ */
138
+ reason: string;
139
+ /**
140
+ * if true, this conflict should abort the sync
141
+ */
142
+ terminal: boolean;
39
143
  }
40
144
 
41
145
  export interface SyncSagaMessageAckData_V1 extends SyncSagaMessageData_V1 {
42
146
  stage: typeof SyncStage.ack;
43
- deltaReqAddrs: string[];
44
- pushOfferAddrs: string[];
147
+ deltaRequestAddrInfos: SyncSagaRequestAddrInfo[];
148
+ pushOfferInfos: SyncSagaPushOfferInfo[];
45
149
  /**
46
- * Map of group keys (TJP or Constant Addr) to list of known addresses (Full History).
47
- * Used by Sender to calculate differential payloads.
150
+ * Map of group keys (TJP addr/constant addr) to list of known addresses
151
+ * in that timeline.
152
+ *
153
+ * This will be used by Sender to calculate differential payloads. So
154
+ * when the sender goes to get the dependency graph of its tip ibgib,
155
+ * it can skip all of the addrs in this.
156
+ *
157
+ * For example, say sender has A^5 and receiver only has A^3. Sender
158
+ * will see in this map { [A^0]: [A^0, A^1, A^2, A^3] } and know that
159
+ * it needs all of the dependencies of A^5 (including A^4), but it does
160
+ * NOT need to send A^0-A^3 (and dependencies) because receiver already has
161
+ * these.
162
+ *
163
+ * ## notes
164
+ *
165
+ * I dislike this name in my rewrite/cleanup of this algorithm. However, I'm
166
+ * keeping it and am using it right now in handleInitFrame for including
167
+ * the receiver's latest addr/tip for the deltaReqAddrs. But really, I should
48
168
  */
49
- knowledgeVector?: { [groupKey: string]: string[] };
169
+ // knowledgeVector?: { [tjpAddr: string]: string[] };
50
170
  /**
51
171
  * List of identified conflicts.
52
172
  *
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
- }[];
173
+ * If present, the Sender should use the `timelineAddrs` (Receiver's
174
+ * history) to compute the LCA and delta requirements for merging.
175
+ */
176
+ conflicts?: SyncSagaConflictInfo[];
68
177
  }
69
178
 
70
- export interface SyncSagaMessageDeltaData_V1 extends SyncSagaMessageData_V1, SyncDeltaData {
179
+ /**
180
+ * The "Body" of the sync protocol. Carries the manifests of data to be
181
+ * transferred.
182
+ *
183
+ * If any {@link payloadAddrsDomain} exist, then these will be populated in the
184
+ * {@link SyncSagaContextIbGib_V1}.
185
+ */
186
+ export interface SyncSagaMessageDeltaData_V1 extends SyncSagaMessageData_V1 {
71
187
  stage: typeof SyncStage.delta;
72
188
  requests?: string[];
73
189
  /**
@@ -75,9 +191,29 @@ export interface SyncSagaMessageDeltaData_V1 extends SyncSagaMessageData_V1, Syn
75
191
  * and is ready to commit the transaction.
76
192
  */
77
193
  proposeCommit?: boolean;
194
+ /**
195
+ * Domain ibgib addresses (actual user data being synced).
196
+ * These go to tempSpace ONLY until final commit.
197
+ */
198
+ payloadAddrsDomain?: string[];
78
199
  }
79
200
 
80
- export interface SyncSagaMessageCommitData_V1 extends SyncSagaMessageData_V1, SyncCommitData {
201
+ /**
202
+ * The "Seal" of the sync protocol.
203
+ */
204
+ export interface SyncSagaMessageCommitData_V1 extends SyncSagaMessageData_V1 {
81
205
  stage: typeof SyncStage.commit;
206
+ /**
207
+ * True if the session completed successfully from the sender's perspective.
208
+ */
209
+ success: boolean;
210
+ /**
211
+ * Optional verification metadata (e.g. success count).
212
+ */
213
+ successCount?: number;
214
+ /**
215
+ * If failed, the reasons why.
216
+ */
217
+ errors?: string[];
82
218
  }
83
219
 
@@ -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
@@ -29,15 +34,19 @@ export function isValidSyncMode(mode: string): mode is SyncMode {
29
34
  // #region SyncConflictStrategy
30
35
  export const SYNC_CONFLICT_STRATEGY_ABORT = 'abort';
31
36
  export const SYNC_CONFLICT_STRATEGY_OPTIMISTIC = 'optimistic';
32
- export const SYNC_CONFLICT_STRATEGY_MANUAL = 'manual';
37
+ // export const SYNC_CONFLICT_STRATEGY_MANUAL = 'manual'; // not implemented yet
33
38
  export type SyncConflictStrategy =
34
39
  | typeof SYNC_CONFLICT_STRATEGY_ABORT
35
40
  | typeof SYNC_CONFLICT_STRATEGY_OPTIMISTIC
36
- | typeof SYNC_CONFLICT_STRATEGY_MANUAL;
41
+ // | typeof SYNC_CONFLICT_STRATEGY_MANUAL // not implemented yet
42
+ ;
43
+ /**
44
+ * @see {@link SyncOptions.conflictStrategy}
45
+ */
37
46
  export const SyncConflictStrategy = {
38
47
  abort: SYNC_CONFLICT_STRATEGY_ABORT,
39
48
  optimistic: SYNC_CONFLICT_STRATEGY_OPTIMISTIC,
40
- manual: SYNC_CONFLICT_STRATEGY_MANUAL,
49
+ // manual: SYNC_CONFLICT_STRATEGY_MANUAL, // not implemented yet
41
50
  } satisfies { [key in SyncConflictStrategy]: SyncConflictStrategy };
42
51
  export const SYNC_CONFLICT_STRATEGY_VALID_VALUES = Object.values(SyncConflictStrategy);
43
52
  export function isValidSyncConflictStrategy(strategy: string): strategy is SyncConflictStrategy {
@@ -45,6 +54,48 @@ export function isValidSyncConflictStrategy(strategy: string): strategy is SyncC
45
54
  }
46
55
  // #endregion SyncConflictStrategy
47
56
 
57
+ export interface NextSagaFrameInfo_Frame {
58
+ frame: SyncIbGib_V1;
59
+ payloadIbGibsDomain?: IbGib_V1[];
60
+ conflictInfos?: SyncSagaConflictInfo;
61
+ responseWasNull: undefined;
62
+ }
63
+ export interface NextSagaFrameInfo_Null {
64
+ frame: never;
65
+ payloadIbGibsDomain?: never;
66
+ conflictInfos?: never;
67
+ responseWasNull: true;
68
+ }
69
+ /**
70
+ * Result of handling a saga frame.
71
+ *
72
+ * ## notes
73
+ *
74
+ * After commit, this may have been a null response, so `frame` will not be
75
+ * defined, thus the discriminated union type.
76
+ */
77
+ export type NextSagaFrameInfo =
78
+ NextSagaFrameInfo_Frame | NextSagaFrameInfo_Null;
79
+
80
+
81
+ export interface HandleSagaResponseContextResult_Base {
82
+ /**
83
+ * if truthy, handling saga context failed, else it succeeded.
84
+ */
85
+ errorMsg?: string;
86
+ /**
87
+ * inner handling of the frame itself
88
+ */
89
+ nextFrameInfo?: NextSagaFrameInfo;
90
+ }
91
+ export interface HandleSagaResponseContextResult_Frame extends HandleSagaResponseContextResult_Base {
92
+ nextFrameInfo: NextSagaFrameInfo;
93
+ }
94
+ export interface HandleSagaResponseContextResult_Error extends HandleSagaResponseContextResult_Base {
95
+ errorMsg: string;
96
+ }
97
+ export type HandleSagaResponseContextResult = HandleSagaResponseContextResult_Frame | HandleSagaResponseContextResult_Error;
98
+
48
99
  export interface SyncOptions {
49
100
  /**
50
101
  * The peer we are syncing with.
@@ -52,7 +103,7 @@ export interface SyncOptions {
52
103
  peer: SyncPeerWitness;
53
104
  /**
54
105
  * The ibgibs we wish to sync.
55
- *
106
+ *
56
107
  * These should all exist in {@link source}
57
108
  */
58
109
  domainIbGibs: IbGib_V1[],
@@ -81,110 +132,71 @@ export interface SyncOptions {
81
132
  */
82
133
  identitySecret?: string;
83
134
  /**
84
- * How to handle conflicts when both Source and Dest have diverged on the same timeline.
135
+ * How to handle conflicts when both Source and Dest have diverged on the
136
+ * same timeline.
137
+ *
85
138
  * @default 'abort'
86
139
  */
87
140
  conflictStrategy?: SyncConflictStrategy;
88
141
  /**
89
- * @deprecated Use `identity` instead if you have a specific identity.
90
- * If true, creates an ephemeral session identity.
142
+ * If true, creates an ephemeral session identity for the sync process to
143
+ * secure the sync transaction itself.
144
+ *
91
145
  * @default true
92
146
  */
93
147
  useSessionIdentity?: boolean;
94
148
  }
95
149
 
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 {
150
+ export interface SyncSagaInfo {
105
151
  /**
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.
152
+ * The unique ID of the saga.
110
153
  */
111
- knowledgeVector: { [tjp: string]: string };
154
+ sagaId: string;
112
155
 
113
156
  /**
114
- * The Keystone Identity of the sender.
115
- * Required for the first handshake or if the receiver doesn't know the sender.
157
+ * Observable stream of context updates happening during the saga.
158
+ *
159
+ * Subscribe to this to receive real-time progress throughout the sync
160
+ * process, whenever the sync ibgib is evolved (including when receiving a
161
+ * response from the peer).
116
162
  */
117
- identity?: KeystoneIbGib_V1;
163
+ updates$: SubjectWitness<SyncSagaContextIbGib_V1>;
118
164
 
119
165
  /**
120
- * What the sender wants to do.
121
- * e.g. "push" (I have data for you) or "pull" (Give me data).
122
- * @default 'push'
166
+ * Promise that resolves when the saga completes successfully.
123
167
  */
124
- mode?: SyncMode;
125
- conflictStrategy?: SyncConflictStrategy;
168
+ done: Promise<void>;
126
169
  }
127
170
 
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[];
171
+ export interface SyncSagaFrameDependencyGraph {
172
+ sagaIbGib: SyncIbGib_V1;
173
+ msgStones: IbGib_V1[];
174
+ identities: KeystoneIbGib_V1[];
137
175
  }
138
176
 
139
177
  /**
140
- * The "Body" of the sync protocol.
141
- * Carries the manifests of data to be transferred.
178
+ * given some group of domain ibgibs, this is info extracted from them.
142
179
  */
143
- export interface SyncDeltaData {
180
+ export interface DomainIbGibAnalysisInfo {
144
181
  /**
145
- * Control ibgib addresses (sync frames, stones, keystones).
146
- * These go to BOTH destSpace + tempSpace for audit trail.
182
+ * flat array of stones (ibgibs without dna)
147
183
  */
148
- payloadAddrsControl?: string[];
149
-
184
+ stones: IbGib_V1[];
150
185
  /**
151
- * Domain ibgib addresses (actual user data being synced).
152
- * These go to tempSpace ONLY until final commit.
186
+ * map of tjp -> sorted timeline ibgib
153
187
  */
154
- payloadAddrsDomain?: string[];
155
-
188
+ timelinesMap: { [tjp: string]: IbGib_V1[] };
156
189
  /**
157
- * THIS SHOULD NOT EXIST. NOT BE DEPRECATED. JUST REMOVED!!
158
- *
159
- * @deprecated Use payloadAddrsControl + payloadAddrsDomain instead.
160
- * Legacy combined payload addresses.
190
+ * sorted by dependency/interdependency
161
191
  */
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 {
192
+ topologicallySortedTjpAddrs: IbGibAddr[];
170
193
  /**
171
- * True if the session completed successfully from the sender's perspective.
172
- */
173
- success: boolean;
174
- /**
175
- * Optional verification metadata (e.g. success count).
176
- */
177
- successCount?: number;
178
- /**
179
- * If failed, the reasons why.
194
+ * full dependency graph of domain ibgibs
180
195
  */
181
- errors?: string[];
196
+ fullGraph: FlatIbGibGraph;
182
197
  }
183
198
 
184
- // ===========================================================================
185
- // IBGIB DATA STRUCTURES
186
- // ===========================================================================
187
-
199
+ // #region Sync Ib, Data, Rel8ns, IbGib
188
200
  export interface SyncIb_V1 {
189
201
  atom: typeof SYNC_ATOM;
190
202
  uuid: string;
@@ -218,11 +230,6 @@ export interface SyncData_V1 extends IbGibData_V1 {
218
230
  * 2. Rate limiting / Backpressure (Don't process this old request).
219
231
  */
220
232
  expirationTimestamp?: string;
221
-
222
- /**
223
- * Polymorphic payload based on stage.
224
- */
225
- payload?: SyncInitData | SyncRequestData | SyncDeltaData | SyncCommitData;
226
233
  }
227
234
 
228
235
  export interface SyncRel8ns_V1 extends IbGibRel8ns_V1 {
@@ -231,30 +238,14 @@ export interface SyncRel8ns_V1 extends IbGibRel8ns_V1 {
231
238
  * This MUST point to the specific Keystone Frame that authorizes this sync frame.
232
239
  */
233
240
  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
-
245
- export interface SyncSagaInfo {
246
- /**
247
- * The unique ID of the saga.
248
- */
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
241
 
256
242
  /**
257
- * Promise that resolves when the saga completes successfully.
243
+ * The message stone that contains the information about the particular
244
+ * stage of the sync process we are in.
258
245
  */
259
- done: Promise<void>;
246
+ [SYNC_MSG_REL8N_NAME]: IbGibAddr[];
260
247
  }
248
+
249
+ export interface SyncIbGib_V1 extends IbGib_V1<SyncData_V1, SyncRel8ns_V1> { }
250
+
251
+ // #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) {