@ibgib/core-gib 0.1.23 → 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 (67) hide show
  1. package/dist/common/other/graph-helper.d.mts +17 -0
  2. package/dist/common/other/graph-helper.d.mts.map +1 -1
  3. package/dist/common/other/graph-helper.mjs +44 -0
  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 +10 -15
  8. package/dist/sync/sync-conflict.respec.mjs.map +1 -1
  9. package/dist/sync/sync-innerspace-constants.respec.mjs +10 -12
  10. package/dist/sync/sync-innerspace-constants.respec.mjs.map +1 -1
  11. package/dist/sync/sync-innerspace-deep-updates.respec.mjs +10 -12
  12. package/dist/sync/sync-innerspace-deep-updates.respec.mjs.map +1 -1
  13. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs +10 -12
  14. package/dist/sync/sync-innerspace-dest-ahead.respec.mjs.map +1 -1
  15. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs +9 -12
  16. package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs.map +1 -1
  17. package/dist/sync/sync-innerspace-partial-update.respec.mjs +9 -14
  18. package/dist/sync/sync-innerspace-partial-update.respec.mjs.map +1 -1
  19. package/dist/sync/sync-innerspace.respec.mjs +9 -12
  20. package/dist/sync/sync-innerspace.respec.mjs.map +1 -1
  21. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.d.mts +2 -0
  22. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.d.mts.map +1 -1
  23. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs +4 -0
  24. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs.map +1 -1
  25. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts +24 -11
  26. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts.map +1 -1
  27. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs +58 -44
  28. package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs.map +1 -1
  29. package/dist/sync/sync-peer/sync-peer-types.d.mts +29 -6
  30. package/dist/sync/sync-peer/sync-peer-types.d.mts.map +1 -1
  31. package/dist/sync/sync-peer/sync-peer-v1.d.mts +29 -30
  32. package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
  33. package/dist/sync/sync-peer/sync-peer-v1.mjs +105 -198
  34. package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
  35. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts +19 -2
  36. package/dist/sync/sync-saga-context/sync-saga-context-helpers.d.mts.map +1 -1
  37. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs +37 -4
  38. package/dist/sync/sync-saga-context/sync-saga-context-helpers.mjs.map +1 -1
  39. package/dist/sync/sync-saga-coordinator.d.mts +12 -12
  40. package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
  41. package/dist/sync/sync-saga-coordinator.mjs +281 -218
  42. package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
  43. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts +51 -6
  44. package/dist/sync/sync-saga-message/sync-saga-message-types.d.mts.map +1 -1
  45. package/dist/sync/sync-types.d.mts +36 -9
  46. package/dist/sync/sync-types.d.mts.map +1 -1
  47. package/dist/sync/sync-types.mjs +1 -2
  48. package/dist/sync/sync-types.mjs.map +1 -1
  49. package/package.json +1 -1
  50. package/src/common/other/graph-helper.mts +53 -0
  51. package/src/sync/graft-info/graft-info-helpers.mts +3 -3
  52. package/src/sync/sync-conflict.respec.mts +10 -17
  53. package/src/sync/sync-helpers.mts +6 -6
  54. package/src/sync/sync-innerspace-constants.respec.mts +10 -12
  55. package/src/sync/sync-innerspace-deep-updates.respec.mts +10 -12
  56. package/src/sync/sync-innerspace-dest-ahead.respec.mts +10 -12
  57. package/src/sync/sync-innerspace-multiple-timelines.respec.mts +9 -12
  58. package/src/sync/sync-innerspace-partial-update.respec.mts +9 -14
  59. package/src/sync/sync-innerspace.respec.mts +9 -12
  60. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mts +7 -0
  61. package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +75 -50
  62. package/src/sync/sync-peer/sync-peer-types.mts +35 -11
  63. package/src/sync/sync-peer/sync-peer-v1.mts +136 -196
  64. package/src/sync/sync-saga-context/sync-saga-context-helpers.mts +37 -8
  65. package/src/sync/sync-saga-coordinator.mts +318 -260
  66. package/src/sync/sync-saga-message/sync-saga-message-types.mts +56 -4
  67. package/src/sync/sync-types.mts +46 -13
@@ -1,17 +1,7 @@
1
1
  /**
2
- * @module SyncPeer_V1 witness class
3
- *
4
- *
5
- * NOTE: All push/pulls in this were done to get to compile. These should mostly
6
- * not be single push/pull calls but should be batched with multiple addresses
7
- * NOTE: All push/pulls in this were done to get to compile. These should mostly
8
- * not be single push/pull calls but should be batched with multiple addresses
9
- * NOTE: All push/pulls in this were done to get to compile. These should mostly
10
- * not be single push/pull calls but should be batched with multiple addresses
11
- * NOTE: All push/pulls in this were done to get to compile. These should mostly
12
- * not be single push/pull calls but should be batched with multiple addresses
13
- * NOTE: All push/pulls in this were done to get to compile. These should mostly
14
- * not be single push/pull calls but should be batched with multiple addresses
2
+ * @module SyncPeer_V1 witness class for base class plumbing of sync peers.
3
+ *
4
+ * You are expected to implement concrete peer classes for concrete architecture.
15
5
  */
16
6
 
17
7
  import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
@@ -24,11 +14,11 @@ import { GLOBAL_LOG_A_LOT } from '../../core-constants.mjs';
24
14
  import { SYNC_MSG_REL8N_NAME, SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN } from '../sync-constants.mjs';
25
15
  import { SubjectWitness } from '../../common/pubsub/subject/subject-types.mjs';
26
16
  import { SyncSagaContextIbGib_V1 } from '../sync-saga-context/sync-saga-context-types.mjs';
27
- import { SyncPeerData_V1, SyncPeerRel8ns_V1, SyncPeerWitness } from './sync-peer-types.mjs';
17
+ import { InitializeSyncPeerOpts, SyncPeerData_V1, SyncPeerRel8ns_V1, SyncPeerWitness } from './sync-peer-types.mjs';
28
18
  import { LightWitnessBase_V1 } from '../../witness/light-witness-base-v1.mjs';
29
19
  import { IbGibSpaceAny } from '../../witness/space/space-base-v1.mjs';
30
20
  import { newupSubject } from '../../common/pubsub/subject/subject-helper.mjs';
31
- import { validateContext } from '../sync-saga-context/sync-saga-context-helpers.mjs';
21
+ import { validateContextAndSagaFrame } from '../sync-saga-context/sync-saga-context-helpers.mjs';
32
22
  import { getFromSpace } from '../../witness/space/space-helper.mjs';
33
23
 
34
24
  const logalot = GLOBAL_LOG_A_LOT || true;
@@ -37,21 +27,21 @@ const lcControlDomain = '[ControlDomain]';
37
27
 
38
28
  /**
39
29
  * Abstract witness for talking to a Sync Peer (e.g. Remote Node or Local Simulator).
40
- *
30
+ *
41
31
  * Takes a SyncSagaContext (Request) and returns a SyncSagaContext (Response).
42
- *
32
+ *
43
33
  * Implements the core "Sync Protocol Transport" logic:
44
34
  * 1. Push Context & Dependencies (Sender -> Receiver)
45
35
  * 2. Send Request (RPC)
46
36
  * 3. Pull Response & Dependencies (Receiver -> Sender)
47
37
  */
48
- export abstract class SyncPeer_V1 extends LightWitnessBase_V1<SyncPeerData_V1, SyncPeerRel8ns_V1>
49
- implements SyncPeerWitness {
38
+ export abstract class SyncPeer_V1<TInitializeOpts extends InitializeSyncPeerOpts = InitializeSyncPeerOpts>
39
+ extends LightWitnessBase_V1<SyncPeerData_V1, SyncPeerRel8ns_V1>
40
+ implements SyncPeerWitness<TInitializeOpts> {
50
41
 
51
42
  protected lc: string = `[${SyncPeer_V1.name}]`;
52
43
 
53
- public senderSpace: IbGibSpaceAny;
54
- public senderTempSpace: IbGibSpaceAny;
44
+ public opts: TInitializeOpts | undefined;
55
45
  public payloadIbGibsDomainReceived$!: SubjectWitness<IbGib_V1>;
56
46
 
57
47
  get classname(): string {
@@ -60,24 +50,79 @@ export abstract class SyncPeer_V1 extends LightWitnessBase_V1<SyncPeerData_V1, S
60
50
  return this.data.classname;
61
51
  }
62
52
 
63
- constructor(senderSpace: IbGibSpaceAny, senderTempSpace: IbGibSpaceAny, initialData: SyncPeerData_V1, initialRel8ns?: SyncPeerRel8ns_V1) {
53
+ constructor(initialData: SyncPeerData_V1, initialRel8ns?: SyncPeerRel8ns_V1) {
64
54
  super(initialData, initialRel8ns);
65
- this.senderSpace = senderSpace;
66
- this.senderTempSpace = senderTempSpace;
67
55
  }
68
56
 
69
- async initialize(): Promise<void> {
57
+ public async initialize(): Promise<void> {
70
58
  this.payloadIbGibsDomainReceived$ = await newupSubject<IbGib_V1>();
71
59
  }
72
60
 
61
+ /**
62
+ * base implementation just sets the opts property.
63
+ *
64
+ * override this in concrete classes for further initialization code
65
+ * specific to the sender.
66
+ *
67
+ * @see {@link SyncPeerWitness.opts}
68
+ */
69
+ public async initializeSender(opts: TInitializeOpts): Promise<void> {
70
+ const lc = `${this.lc}[${this.initializeSender.name}]`;
71
+ try {
72
+ if (logalot) { console.log(`${lc} starting... (I: 31bd5fda37c89fa37fbaf14daf5fe726)`); }
73
+ this.opts = opts;
74
+ } catch (error) {
75
+ console.error(`${lc} ${extractErrorMsg(error)}`);
76
+ throw error;
77
+ } finally {
78
+ if (logalot) { console.log(`${lc} complete.`); }
79
+ }
80
+ }
81
+
82
+ public setOptionalOpts(arg: Partial<TInitializeOpts>): void {
83
+ const lc = `${this.lc}[${this.setOptionalOpts.name}]`;
84
+ try {
85
+ if (logalot) { console.log(`${lc} starting... (I: ae5ddbd3577db267f84743175a736626)`); }
86
+ if (!this.opts) { throw new Error(`(UNEXPECTED) this.opts falsy? (E: 0dd4d6080a6e2f31d86cf4d86e11b826)`); }
87
+
88
+ if (logalot) { console.log(`${lc} updating opts. arg keys: ${Object.keys(arg)} (I: 452d78a558f8fc3468c8e2e68c70b226)`); }
89
+
90
+ this.opts = { ...this.opts, ...arg };
91
+ } catch (error) {
92
+ console.error(`${lc} ${extractErrorMsg(error)}`);
93
+ throw error;
94
+ } finally {
95
+ if (logalot) { console.log(`${lc} complete.`); }
96
+ }
97
+ }
98
+
99
+ // public setOptionalOpts({
100
+ // senderTempSpace,
101
+ // }: {
102
+ // senderTempSpace: IbGibSpaceAny,
103
+ // }): void {
104
+ // const lc = `${this.lc}[${this.setOptionalOpts.name}]`;
105
+ // try {
106
+ // if (logalot) { console.log(`${lc} starting... (I: a17188953e38f07b1884e498ac490b26)`); }
107
+ // if (!this.opts) { throw new Error(`(UNEXPECTED) this.opts falsy? (E: bdf00fe4b89b07ea78860d6ebe922e26)`); }
108
+
109
+ // this.opts.senderTempSpace = senderTempSpace;
110
+ // } catch (error) {
111
+ // console.error(`${lc} ${extractErrorMsg(error)}`);
112
+ // throw error;
113
+ // } finally {
114
+ // if (logalot) { console.log(`${lc} complete.`); }
115
+ // }
116
+ // }
117
+
73
118
  protected abstract ensureReceiverTempSpace(): Promise<IbGibSpaceAny>;
74
119
 
75
120
  /**
76
121
  * Witness the synchronization context (Send/Receive).
77
- *
122
+ *
78
123
  * At this point in code, we are sending the context OUTGOING. The {@link context} should
79
124
  * have a fully populated {@link SyncSagaContextIbGib_V1.sagaFrame}
80
- *
125
+ *
81
126
  * @param arg The OUTGOING context (Request).
82
127
  * @returns The INCOMING context (Response), or undefined if failed/empty.
83
128
  */
@@ -86,27 +131,34 @@ export abstract class SyncPeer_V1 extends LightWitnessBase_V1<SyncPeerData_V1, S
86
131
  try {
87
132
  if (logalot) { console.log(`${lc} starting...`); }
88
133
 
89
- if (logalot) { console.log(`${lc} starting...`); }
90
-
91
- // validate, authenticate, and authorize the context, sagaFrame, and identity(s)
92
- const validationErrors = await validateContext({ context });
93
- if (validationErrors.length > 0) {
94
- throw new Error(`invalid context received. validationErrors: ${validationErrors} (E: 8b34c875c968af29bc433138e57a7826)`);
95
- }
96
- const authenticationErrors = await this.authenticateContext({ context });
97
- if (authenticationErrors.length > 0) {
98
- throw new Error(`invalid context authentication. authenticationErrors: ${authenticationErrors} (E: da89da5ee1269aeb78952d475d607526)`);
99
- }
100
- const authorizationErrors = await this.authorizeContext({ context });
101
- if (authorizationErrors.length > 0) {
102
- throw new Error(`invalid context authorization. authorizationErrors: ${authorizationErrors} (E: 8ddc284a758cf10ba829334c1babb826)`);
103
- }
104
-
105
- // at this point, we have a valid, authenticated, authorized context
134
+ if (!this.opts) { throw new Error(`(UNEXPECTED) this.opts falsy? Concrete class should have initialized sender opts by now. (E: 0b9e28287318fdf8bf9f5a6886a24826)`); }
135
+
136
+ // NOTE: There are two basic types of peers:
137
+ // * local-only (peer)
138
+ // * this peer is both sender/receiver peer
139
+ // * for local merges and relatively fast spaces
140
+ // * proxy to remote space
141
+ // * this peer is both sender/receiver peer
142
+ // * works directly with remote/outerspaces
143
+ // * Less efficient over-the-wire xfer due to chatiness
144
+ // * symmetric node sender/receiver peers
145
+ // * separate sender/receiver classes
146
+ // * e.g., SyncPeerClient[Substrate]Sender_V1,
147
+ // SyncPeerClient[Substrate]Receiver_V1
148
+ // * More efficient over-the-wire xfer
149
+ // * Most difficult to mentally model
150
+ // * sender.witness does the pushing out
151
+ // * what the sender/initiator's coordinator has a reference to
152
+ // * receiver.witness does the coming in
153
+ // * lives on a server/remote instance with its own coordinator
154
+ // instance
155
+ // * must do its own validation/authn/authz for possible MITM
156
+ // issues
157
+ // The following is a sketch where some of these may be blurred
106
158
 
107
159
  // persist the context, sagaframe, identity(s) ONLY in the receiver's durable space
108
160
  // if sending domain ibgibs...
109
- // verify the domain ibgibs intrinsically.
161
+ // verify the domain ibgibs intrinsically.
110
162
  // persist the domain ibgibs in the receiver's temp space (push all addrs?)
111
163
  // await until all domain ibgibs are in receiver's temp space
112
164
  // process the context with the receiver's coordinator to get a new response context
@@ -114,15 +166,28 @@ export abstract class SyncPeer_V1 extends LightWitnessBase_V1<SyncPeerData_V1, S
114
166
  // validate context intrinsically
115
167
  // validate return identity if present
116
168
  // persist the response context's dependency graph (context, saga frame and msg(s), identities)
117
- // if response has payload domain ibgibs,
169
+ // if response has payload domain ibgibs,
118
170
  // spin off...
119
171
  // pull domain ibgibs to local temp space
120
172
  // publish domain ibgibs to observable
121
173
  // when all domain ibgibs are pulled, publish complete to the observable
122
174
  // return resulting context ibgib (which the caller should get BEFORE the domain ibgibs observable completes)
123
175
 
124
- // 1. PUSH: Ensure Request Data is available on Receiver
125
- await this.pushContextGraph({ context }); // ???
176
+ // validate, authenticate, and authorize the context, sagaFrame, and identity(s)
177
+ const validationErrors = await validateContextAndSagaFrame({ context });
178
+ if (validationErrors.length > 0) {
179
+ throw new Error(`invalid context received. validationErrors: ${validationErrors} (E: 8b34c875c968af29bc433138e57a7826)`);
180
+ }
181
+ const authenticationErrors = await this.authenticateContext({ context });
182
+ if (authenticationErrors.length > 0) {
183
+ throw new Error(`invalid context authentication. authenticationErrors: ${authenticationErrors} (E: da89da5ee1269aeb78952d475d607526)`);
184
+ }
185
+ const authorizationErrors = await this.authorizeContext({ context });
186
+ if (authorizationErrors.length > 0) {
187
+ throw new Error(`invalid context authorization. authorizationErrors: ${authorizationErrors} (E: 8ddc284a758cf10ba829334c1babb826)`);
188
+ }
189
+
190
+ // at this point, we have a valid, authenticated, authorized context
126
191
 
127
192
  // 2. EXECUTE: Trigger Remote Processing
128
193
  const response = await this.sendContextRequest(context);
@@ -132,14 +197,12 @@ export abstract class SyncPeer_V1 extends LightWitnessBase_V1<SyncPeerData_V1, S
132
197
  return undefined;
133
198
  }
134
199
 
135
- // at this point, we have received the response context, sync saga
136
- // frame/msg stones, and any keystones should be evolved. Depending
200
+ // at this point, all outgoing payload domain ibgibs have been sent.
201
+ // we have received the response context, wherein the sync saga
202
+ // frame/msg stone(s) and any keystones should be evolved. Depending
137
203
  // on the concrete implementation, if there are domain ibgibs to
138
- // receive, they may already be coming.
139
-
140
- // todo: this pull is a
141
- // 3. PULL: Ensure Response Data is available on Sender (Local)
142
- await this.pullContextGraph({ context: response });
204
+ // receive, they may still be transferring. These will be published
205
+ // to this.payloadIbGibsDomainReceived$
143
206
 
144
207
  return response;
145
208
 
@@ -152,13 +215,25 @@ export abstract class SyncPeer_V1 extends LightWitnessBase_V1<SyncPeerData_V1, S
152
215
  }
153
216
 
154
217
  /**
155
- * Transmits the Context IbGib itself to the Peer.
218
+ * This is responsible for:
219
+ *
220
+ * * sending outgoing {@link context}, the sync saga frame and msg stone(s),
221
+ * and identities...
222
+ * * AND sending OUTGOING domain ibgibs
223
+ * {@link SyncSagaContextIbGib_V1.payloadIbGibsDomain}
224
+ * * getting back the other end's resultant context ibgib, sync saga frame
225
+ * and msg stone(s), and identities in their entirety...
226
+ * * AND stream/receiving the RESPONSE payload domain ibgibs, publishing
227
+ * these to this.payloadIbGibsDomainReceived$.
228
+ *
229
+ * So this returns the RESPONSE context, possibly BEFORE the RESPONSE domain
230
+ * ibgibs have been completely received/streamed. The coordinator is responsible
156
231
  */
157
232
  protected abstract sendContextRequest(context: SyncSagaContextIbGib_V1): Promise<SyncSagaContextIbGib_V1 | undefined>;
158
233
 
159
234
  /**
160
235
  * Pushes specific IbGib(s) (by address) from Local to Remote.
161
- *
236
+ *
162
237
  * Should NOT have to handle identifying if the remote already has it
163
238
  * (optimization), because the sync coordinator should be doing this in
164
239
  * its diffing algorithm.
@@ -210,146 +285,10 @@ export abstract class SyncPeer_V1 extends LightWitnessBase_V1<SyncPeerData_V1, S
210
285
  }
211
286
  }
212
287
 
213
- /**
214
- * Helper to orchestrate the PUSH of a Context's dependency graph.
215
- */
216
- protected async pushContextGraph({ context }: { context: SyncSagaContextIbGib_V1 }): Promise<void> {
217
- const lc = `[${SyncPeer_V1.name}][pushContextGraph]`;
218
-
219
- // A. Push Context Envelope
220
- const contextAddr = getIbGibAddr({ ibGib: context });
221
- if (logalotControlDomain) { console.log(`${lc}${lcControlDomain} PUSH Context Envelope -> ${contextAddr} (I: 3f4e5a6b7c8d9e0f)`); }
222
- await this.push([contextAddr]);
223
-
224
- // B. Push Saga Frame & Immediate Deps (Msg, Identity)
225
- const frameAddr = context.rel8ns?.sagaFrame?.[0];
226
- if (frameAddr) {
227
- if (logalotControlDomain) { console.log(`${lc}${lcControlDomain} PUSH CONTROL: Saga Frame -> ${frameAddr} (I: 4a5b6c7d8e9f0a1b)`); }
228
- await this.push([frameAddr]);
229
- // We inspect the local frame to find its immediate deps
230
- const frame = await this.getLocalIbGib(frameAddr);
231
- if (frame) {
232
- // Msg Stone
233
- const msgAddrs = frame.rel8ns?.[SYNC_MSG_REL8N_NAME];
234
- if (msgAddrs) {
235
- for (const addr of msgAddrs) {
236
- if (logalotControlDomain) { console.log(`${lc}${lcControlDomain} PUSH CONTROL: Msg Stone -> ${addr} (I: 5b6c7d8e9f0a1b2c)`); }
237
- await this.push([addr]);
238
- }
239
- }
240
- // Identity
241
- const idAddrs = frame.rel8ns?.identity;
242
- if (idAddrs) {
243
- for (const addr of idAddrs) {
244
- if (logalotControlDomain) { console.log(`${lc}${lcControlDomain} PUSH CONTROL: Identity -> ${addr} (I: 6c7d8e9f0a1b2c3d)`); }
245
- await this.push([addr]);
246
- }
247
- }
248
- }
249
- }
250
-
251
- // C. Push Session Identity
252
- const sessionKeystoneAddr = context.rel8ns?.sessionKeystone?.[0];
253
- if (sessionKeystoneAddr) {
254
- if (logalotControlDomain) { console.log(`${lc}${lcControlDomain} PUSH CONTROL: Session Keystone -> ${sessionKeystoneAddr} (I: 7d8e9f0a1b2c3d4e)`); }
255
- await this.push([sessionKeystoneAddr]);
256
- }
257
-
258
- // D. Push Payloads (Deep/Soft)
259
- // For payloads, the Peer is just a transport. It doesn't know the structure.
260
- // It relies on "push" handling the "deep" transfer if needed, or we explicitly iterate if we had a graph.
261
- // But since we are "Witnessing", we usually assume "push(addr)" acts like "copy(addr, recursive=true)"?
262
- // Or do we need to be explicit?
263
- // User said: "payloads should be flat... sync coordinator is the one doing the heavy lifting".
264
- // So we just push the addrs listed.
265
-
266
- // 1. Control Payloads
267
- // const controlAddrs = context.data?.[SYNC_SAGA_PAYLOAD_ADDRS_CONTROL];
268
- // if (controlAddrs && controlAddrs.length > 0) {
269
- // if (logalotControlDomain) { console.log(`${lc}${lcControlDomain} PUSH CONTROL PAYLOADS (${controlAddrs.length}): ${controlAddrs.join(', ')} (I: 8e9f0a1b2c3d4e5f)`); }
270
- // for (const addr of controlAddrs) {
271
- // await this.push(addr);
272
- // }
273
- // }
274
-
275
- // 2. Domain Payloads
276
- const domainAddrs = context.data?.[SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN];
277
- if (domainAddrs && domainAddrs.length > 0) {
278
- if (logalotControlDomain) { console.log(`${lc}${lcControlDomain} PUSH DOMAIN PAYLOADS (${domainAddrs.length}): ${domainAddrs.join(', ')} (I: 9f0a1b2c3d4e5f6a)`); }
279
- for (const addr of domainAddrs) {
280
- await this.push([addr]);
281
- }
282
- }
283
-
284
- if (logalotControlDomain) { console.log(`${lc}${lcControlDomain} PUSH COMPLETE for context ${contextAddr} (I: a0b1c2d3e4f5a6b7)`); }
285
- }
286
-
287
- /**
288
- * Helper to orchestrate the PULL of a Context's dependency graph.
289
- */
290
- protected async pullContextGraph({ context }: { context: SyncSagaContextIbGib_V1 }): Promise<void> {
291
- const lc = `[${SyncPeer_V1.name}][pullContextGraph]`;
292
-
293
- // A. Pull Context Envelope
294
- const contextAddr = getIbGibAddr({ ibGib: context });
295
- if (logalotControlDomain) { console.log(`${lc}${lcControlDomain} PULL Context Envelope <- ${contextAddr} (I: b1c2d3e4f5a6b7c8)`); }
296
- await this.pull([contextAddr]);
297
-
298
- // B. Pull Saga Frame & Immediate Deps
299
- const frameAddr = context.rel8ns?.sagaFrame?.[0];
300
- if (frameAddr) {
301
- if (logalotControlDomain) { console.log(`${lc}${lcControlDomain} PULL CONTROL: Saga Frame <- ${frameAddr} (I: c2d3e4f5a6b7c8d9)`); }
302
- await this.pull([frameAddr]);
303
- // Inspect REMOTE frame? We need to have pulled it first.
304
- const frame = await this.getLocalIbGib(frameAddr); // Should be local now
305
- if (frame) {
306
- const msgAddrs = frame.rel8ns?.[SYNC_MSG_REL8N_NAME];
307
- if (msgAddrs) {
308
- for (const addr of msgAddrs) {
309
- if (logalotControlDomain) { console.log(`${lc}${lcControlDomain} PULL CONTROL: Msg Stone <- ${addr} (I: d3e4f5a6b7c8d9e0)`); }
310
- await this.pull([addr]);
311
- }
312
- }
313
- const idAddrs = frame.rel8ns?.identity;
314
- if (idAddrs) {
315
- for (const addr of idAddrs) {
316
- if (logalotControlDomain) { console.log(`${lc}${lcControlDomain} PULL CONTROL: Identity <- ${addr} (I: e4f5a6b7c8d9e0f1)`); }
317
- await this.pull([addr]);
318
- }
319
- }
320
- }
321
- }
322
-
323
- // C. Pull Session Identity
324
- const sessionKeystoneAddr = context.rel8ns?.sessionKeystone?.[0];
325
- if (sessionKeystoneAddr) {
326
- if (logalotControlDomain) { console.log(`${lc}${lcControlDomain} PULL CONTROL: Session Keystone <- ${sessionKeystoneAddr} (I: f5a6b7c8d9e0f1a2)`); }
327
- await this.pull([sessionKeystoneAddr]);
328
- }
329
-
330
- // D. Pull Payloads
331
- // const controlAddrs = context.data?.[SYNC_SAGA_PAYLOAD_ADDRS_CONTROL];
332
- // if (controlAddrs && controlAddrs.length > 0) {
333
- // if (logalotControlDomain) { console.log(`${lc}${lcControlDomain} PULL CONTROL PAYLOADS (${controlAddrs.length}): ${controlAddrs.join(', ')} (I: a6b7c8d9e0f1a2b3)`); }
334
- // for (const addr of controlAddrs) {
335
- // await this.pull(addr);
336
- // }
337
- // }
338
- const domainAddrs = context.data?.[SYNC_SAGA_PAYLOAD_ADDRS_DOMAIN];
339
- if (domainAddrs && domainAddrs.length > 0) {
340
- if (logalotControlDomain) { console.log(`${lc}${lcControlDomain} PULL DOMAIN PAYLOADS (${domainAddrs.length}): ${domainAddrs.join(', ')} (I: b7c8d9e0f1a2b3c4)`); }
341
- for (const addr of domainAddrs) {
342
- await this.pull([addr]);
343
- }
344
- }
345
-
346
- if (logalotControlDomain) { console.log(`${lc}${lcControlDomain} PULL COMPLETE for context ${contextAddr} (I: c8d9e0f1a2b3c4d5)`); }
347
- }
348
-
349
288
  /**
350
289
  * Abstract accessor to get an IbGib from the Local space/store.
351
290
  * Needed for inspecting rela8ns during the graph walk.
352
- *
291
+ *
353
292
  * Default implementation simply looks in senderSpace
354
293
  */
355
294
  protected async getLocalIbGib(addr: string): Promise<IbGib_V1 | undefined> {
@@ -358,14 +297,15 @@ export abstract class SyncPeer_V1 extends LightWitnessBase_V1<SyncPeerData_V1, S
358
297
  if (logalot) { console.log(`${lc} starting... (I: 27b248cb9801eeb2386b71485389a826)`); }
359
298
 
360
299
  console.warn(`${lc} possibly a bottleneck here, getLocalIbGib only gets a single ibgib... (W: 2fd448a435480e6b128f6b8bcbef4826)`);
300
+ if (!this.opts) { throw new Error(`(UNEXPECTED) this.opts falsy? (E: cfb9431f2fb851f24a6c88e80c3b3326)`); }
361
301
 
362
- const resGet = await getFromSpace({ space: this.senderSpace, addr });
302
+ const resGet = await getFromSpace({ space: this.opts.senderSpace, addr });
363
303
 
364
304
  if (resGet.success && resGet.ibGibs && resGet.ibGibs.length === 1) {
365
305
  const ibGib = resGet.ibGibs[0];
366
306
  return ibGib;
367
307
  } else {
368
- throw new Error(`couldn't get addr (${addr}) from local space ${this.senderSpace}. reason: ${resGet.errorMsg ?? 'unknown error (E: 926ef8bf4fcc299ab89dba34ea691a26)'} (E: d8a89807e471d3f8b938ab21df44cb26)`);
308
+ throw new Error(`couldn't get addr (${addr}) from local space ${this.opts.senderSpace}. reason: ${resGet.errorMsg ?? 'unknown error (E: 926ef8bf4fcc299ab89dba34ea691a26)'} (E: d8a89807e471d3f8b938ab21df44cb26)`);
369
309
  }
370
310
  } catch (error) {
371
311
  console.error(`${lc} ${extractErrorMsg(error)}`);
@@ -111,13 +111,13 @@ export async function parseSyncSagaContextIb({
111
111
  /**
112
112
  * Creates new SyncSagaContext stone. Puts/registers in {@link localSpace}
113
113
  * immediately after creation.
114
- *
114
+ *
115
115
  * @returns The context ibGib.
116
- *
116
+ *
117
117
  * ## notes
118
- *
118
+ *
119
119
  * the other ibgibs that are related to this context stone should already be
120
- * put/registered in {@link localSpace}.
120
+ * put/registered in {@link localSpace}.
121
121
  */
122
122
  export async function createSyncSagaContext({
123
123
  sagaFrame,
@@ -138,7 +138,7 @@ export async function createSyncSagaContext({
138
138
  timestampMs,
139
139
  };
140
140
 
141
- // Domain Payloads
141
+ // Domain Payloads
142
142
  const payloadAddrsDomain = payloadIbGibsDomain ?
143
143
  payloadIbGibsDomain?.map(x => getIbGibAddr({ ibGib: x })) :
144
144
  undefined;
@@ -189,10 +189,19 @@ export async function createSyncSagaContext({
189
189
  }
190
190
 
191
191
  /**
192
- * move to sync-peer-helpers.mts as a pure function?
192
+ * Validates ONLY the {@link context} ibgib itself and saga frame/msg stone(s)
193
+ * ({@link SyncSagaContextIbGib_V1.sagaFrame}).
194
+ *
195
+ * Does NOT...
196
+ * * validate keystones (authn or authz)
197
+ * * validate domain payload ibgibs...
198
+ * * intrinsically
199
+ * * in relation to this context (addrs match up)
200
+ *
201
+ * @returns empty array if valid, else validation errors
193
202
  */
194
- export async function validateContext({ context }: { context: SyncSagaContextIbGib_V1 }): Promise<string[]> {
195
- const lc = `[${validateContext.name}]`;
203
+ export async function validateContextAndSagaFrame({ context }: { context: SyncSagaContextIbGib_V1 }): Promise<string[]> {
204
+ const lc = `[${validateContextAndSagaFrame.name}]`;
196
205
  try {
197
206
  if (logalot) { console.log(`${lc} starting... (I: 7797f8294bd8f7e5089cb722ad468226)`); }
198
207
 
@@ -226,4 +235,24 @@ export async function validateContext({ context }: { context: SyncSagaContextIbG
226
235
  } finally {
227
236
  if (logalot) { console.log(`${lc} complete.`); }
228
237
  }
238
+ }
239
+
240
+
241
+ /**
242
+ * validates the payload ibgibs ({@link SyncSagaContextIbGib_V1.payloadIbGibsDomain}) intrinsically
243
+ *
244
+ * @returns empty array if valid, else validation errors
245
+ */
246
+ export async function validateContextDomainPayloadIbGibs({ context }: { context: SyncSagaContextIbGib_V1 }): Promise<string[]> {
247
+ const lc = `[${validateContextDomainPayloadIbGibs.name}]`;
248
+ try {
249
+ if (logalot) { console.log(`${lc} starting... (I: 9f9fe835bcc80c75aa7fd6d887fc0826)`); }
250
+ console.error(`${lc} NAG MESSAGE (NOT THROWN). not implemented (E: bfe02ab36a227291a8f17ffc08f2ef26)`)
251
+ return [];
252
+ } catch (error) {
253
+ console.error(`${lc} ${extractErrorMsg(error)}`);
254
+ throw error;
255
+ } finally {
256
+ if (logalot) { console.log(`${lc} complete.`); }
257
+ }
229
258
  }