@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.
- package/dist/common/other/graph-helper.d.mts +25 -0
- package/dist/common/other/graph-helper.d.mts.map +1 -1
- package/dist/common/other/graph-helper.mjs +75 -1
- package/dist/common/other/graph-helper.mjs.map +1 -1
- package/dist/sync/graft-info/graft-info-helpers.mjs +2 -2
- package/dist/sync/graft-info/graft-info-helpers.mjs.map +1 -1
- package/dist/sync/sync-conflict.respec.mjs +8 -12
- package/dist/sync/sync-conflict.respec.mjs.map +1 -1
- package/dist/sync/sync-constants.d.mts +14 -4
- package/dist/sync/sync-constants.d.mts.map +1 -1
- package/dist/sync/sync-constants.mjs +15 -3
- package/dist/sync/sync-constants.mjs.map +1 -1
- package/dist/sync/sync-helpers.d.mts +22 -15
- package/dist/sync/sync-helpers.d.mts.map +1 -1
- package/dist/sync/sync-helpers.mjs +159 -90
- package/dist/sync/sync-helpers.mjs.map +1 -1
- package/dist/sync/sync-innerspace-constants.respec.mjs +8 -9
- package/dist/sync/sync-innerspace-constants.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-deep-updates.respec.mjs +8 -9
- package/dist/sync/sync-innerspace-deep-updates.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-dest-ahead.respec.mjs +8 -9
- package/dist/sync/sync-innerspace-dest-ahead.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs +8 -9
- package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-partial-update.respec.mjs +8 -9
- package/dist/sync/sync-innerspace-partial-update.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace.respec.mjs +6 -7
- package/dist/sync/sync-innerspace.respec.mjs.map +1 -1
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.d.mts +2 -0
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs +4 -0
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs.map +1 -1
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.d.mts +0 -15
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts +30 -16
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs +47 -79
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs.map +1 -1
- package/dist/sync/sync-peer/sync-peer-types.d.mts +40 -1
- package/dist/sync/sync-peer/sync-peer-types.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-v1.d.mts +47 -14
- package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-v1.mjs +188 -144
- package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
- package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts +39 -3
- package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts.map +1 -1
- package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs +137 -31
- package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs.map +1 -1
- package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts +5 -0
- package/dist/sync/sync-saga-context/sync-saga-context-types.d.mts.map +1 -1
- package/dist/sync/sync-saga-coordinator.d.mts +81 -77
- package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
- package/dist/sync/sync-saga-coordinator.mjs +608 -597
- package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
- package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts +154 -26
- package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts.map +1 -1
- package/dist/sync/sync-types.d.mts +87 -92
- package/dist/sync/sync-types.d.mts.map +1 -1
- package/dist/sync/sync-types.mjs +6 -2
- package/dist/sync/sync-types.mjs.map +1 -1
- package/dist/timeline/timeline-api.d.mts.map +1 -1
- package/dist/timeline/timeline-api.mjs +15 -8
- package/dist/timeline/timeline-api.mjs.map +1 -1
- package/package.json +1 -1
- package/src/common/other/graph-helper.mts +79 -1
- package/src/sync/graft-info/graft-info-helpers.mts +3 -3
- package/src/sync/sync-conflict.respec.mts +8 -14
- package/src/sync/sync-constants.mts +15 -4
- package/src/sync/sync-helpers.mts +173 -101
- package/src/sync/sync-innerspace-constants.respec.mts +8 -9
- package/src/sync/sync-innerspace-deep-updates.respec.mts +8 -9
- package/src/sync/sync-innerspace-dest-ahead.respec.mts +8 -9
- package/src/sync/sync-innerspace-multiple-timelines.respec.mts +8 -9
- package/src/sync/sync-innerspace-partial-update.respec.mts +9 -12
- package/src/sync/sync-innerspace.respec.mts +6 -7
- package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mts +7 -0
- package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.mts +0 -15
- package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +72 -96
- package/src/sync/sync-peer/sync-peer-types.mts +43 -2
- package/src/sync/sync-peer/sync-peer-v1.mts +215 -142
- package/src/sync/sync-saga-context/sync-saga-context-helpers.mts +145 -37
- package/src/sync/sync-saga-context/sync-saga-context-types.mts +5 -0
- package/src/sync/sync-saga-coordinator.mts +680 -714
- package/src/sync/sync-saga-message/sync-saga-message-types.mts +160 -24
- package/src/sync/sync-types.mts +96 -105
- 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,
|
|
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
|
-
|
|
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
|
-
|
|
44
|
-
|
|
147
|
+
deltaRequestAddrInfos: SyncSagaRequestAddrInfo[];
|
|
148
|
+
pushOfferInfos: SyncSagaPushOfferInfo[];
|
|
45
149
|
/**
|
|
46
|
-
* Map of group keys (TJP
|
|
47
|
-
*
|
|
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?: { [
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
package/src/sync/sync-types.mts
CHANGED
|
@@ -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 {
|
|
4
|
-
import {
|
|
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
|
|
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
|
-
*
|
|
90
|
-
*
|
|
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
|
-
*
|
|
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
|
-
|
|
154
|
+
sagaId: string;
|
|
112
155
|
|
|
113
156
|
/**
|
|
114
|
-
*
|
|
115
|
-
*
|
|
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
|
-
|
|
163
|
+
updates$: SubjectWitness<SyncSagaContextIbGib_V1>;
|
|
118
164
|
|
|
119
165
|
/**
|
|
120
|
-
*
|
|
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
|
-
|
|
125
|
-
conflictStrategy?: SyncConflictStrategy;
|
|
168
|
+
done: Promise<void>;
|
|
126
169
|
}
|
|
127
170
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
-
*
|
|
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
|
|
180
|
+
export interface DomainIbGibAnalysisInfo {
|
|
144
181
|
/**
|
|
145
|
-
*
|
|
146
|
-
* These go to BOTH destSpace + tempSpace for audit trail.
|
|
182
|
+
* flat array of stones (ibgibs without dna)
|
|
147
183
|
*/
|
|
148
|
-
|
|
149
|
-
|
|
184
|
+
stones: IbGib_V1[];
|
|
150
185
|
/**
|
|
151
|
-
*
|
|
152
|
-
* These go to tempSpace ONLY until final commit.
|
|
186
|
+
* map of tjp -> sorted timeline ibgib
|
|
153
187
|
*/
|
|
154
|
-
|
|
155
|
-
|
|
188
|
+
timelinesMap: { [tjp: string]: IbGib_V1[] };
|
|
156
189
|
/**
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
* @deprecated Use payloadAddrsControl + payloadAddrsDomain instead.
|
|
160
|
-
* Legacy combined payload addresses.
|
|
190
|
+
* sorted by dependency/interdependency
|
|
161
191
|
*/
|
|
162
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
243
|
+
* The message stone that contains the information about the particular
|
|
244
|
+
* stage of the sync process we are in.
|
|
258
245
|
*/
|
|
259
|
-
|
|
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: {
|
|
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:
|
|
957
|
+
let pastIbGibMap: FlatIbGibGraph = {};
|
|
953
958
|
|
|
954
959
|
const dnaMap = includeDna ?
|
|
955
|
-
|
|
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 =
|
|
981
|
+
pastIbGibMap = toFlatGraph({ ibGibs: resGet.ibGibs! }) ?? {};
|
|
975
982
|
|
|
976
983
|
const orderedPastIbGibs: IbGib_V1[] = [];
|
|
977
984
|
for (const pastAddr of pastAddrs) {
|