@ibgib/core-gib 0.1.55 → 0.1.58
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/CHANGELOG.md +1 -0
- package/dist/keystone/keystone-config-builder.d.mts +12 -1
- package/dist/keystone/keystone-config-builder.d.mts.map +1 -1
- package/dist/keystone/keystone-config-builder.mjs +58 -4
- package/dist/keystone/keystone-config-builder.mjs.map +1 -1
- package/dist/keystone/keystone-constants.d.mts +40 -5
- package/dist/keystone/keystone-constants.d.mts.map +1 -1
- package/dist/keystone/keystone-constants.mjs +39 -5
- package/dist/keystone/keystone-constants.mjs.map +1 -1
- package/dist/keystone/keystone-helpers.d.mts +11 -1
- package/dist/keystone/keystone-helpers.d.mts.map +1 -1
- package/dist/keystone/keystone-helpers.mjs +37 -1
- package/dist/keystone/keystone-helpers.mjs.map +1 -1
- package/dist/keystone/keystone-policy-types.d.mts +23 -0
- package/dist/keystone/keystone-policy-types.d.mts.map +1 -0
- package/dist/keystone/keystone-policy-types.mjs +2 -0
- package/dist/keystone/keystone-policy-types.mjs.map +1 -0
- package/dist/sync/graft-info/graft-info-helpers.respec.mjs +8 -8
- package/dist/sync/graft-info/graft-info-helpers.respec.mjs.map +1 -1
- package/dist/sync/sync-conflict-adv-multitimelines.respec.mjs +22 -22
- package/dist/sync/sync-conflict-adv-multitimelines.respec.mjs.map +1 -1
- package/dist/sync/sync-conflict-basic-divergence.respec.mjs +3 -3
- package/dist/sync/sync-conflict-basic-divergence.respec.mjs.map +1 -1
- package/dist/sync/sync-conflict-basic-multitimelines.respec.mjs +6 -6
- package/dist/sync/sync-conflict-basic-multitimelines.respec.mjs.map +1 -1
- package/dist/sync/sync-conflict-text-merge.respec.mjs +26 -26
- package/dist/sync/sync-conflict-text-merge.respec.mjs.map +1 -1
- package/dist/sync/sync-helpers.d.mts +19 -0
- package/dist/sync/sync-helpers.d.mts.map +1 -1
- package/dist/sync/sync-helpers.mjs +51 -1
- package/dist/sync/sync-helpers.mjs.map +1 -1
- package/dist/sync/sync-innerspace-constants.respec.mjs +2 -2
- package/dist/sync/sync-innerspace-constants.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-deep-updates.respec.mjs +2 -2
- package/dist/sync/sync-innerspace-deep-updates.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-dest-ahead.respec.mjs +4 -4
- package/dist/sync/sync-innerspace-dest-ahead.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs +2 -2
- package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-partial-update.respec.mjs +3 -3
- package/dist/sync/sync-innerspace-partial-update.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace.respec.mjs +4 -4
- package/dist/sync/sync-innerspace.respec.mjs.map +1 -1
- package/dist/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.d.mts +5 -0
- package/dist/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.mjs +18 -0
- package/dist/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.mjs.map +1 -1
- package/dist/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-v1.d.mts +5 -0
- package/dist/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-v1.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-v1.mjs +21 -3
- package/dist/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-v1.mjs.map +1 -1
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts +12 -0
- 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 +34 -0
- 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 +69 -1
- package/dist/sync/sync-peer/sync-peer-types.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-v1.d.mts +30 -0
- package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-v1.mjs +88 -1
- package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
- package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-types.d.mts +30 -0
- package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-types.d.mts.map +1 -0
- package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-types.mjs +2 -0
- package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-types.mjs.map +1 -0
- package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.d.mts +66 -0
- package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.d.mts.map +1 -0
- package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.mjs +280 -0
- package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.mjs.map +1 -0
- package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-websocket-peer-helpers.d.mts +85 -0
- package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-websocket-peer-helpers.d.mts.map +1 -0
- package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs +332 -0
- package/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs.map +1 -0
- package/dist/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-types.d.mts +29 -0
- package/dist/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-types.d.mts.map +1 -0
- package/dist/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-types.mjs +2 -0
- package/dist/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-types.mjs.map +1 -0
- package/dist/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.d.mts +42 -0
- package/dist/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.d.mts.map +1 -0
- package/dist/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mjs +282 -0
- package/dist/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mjs.map +1 -0
- package/dist/sync/sync-saga-coordinator.d.mts +35 -1
- package/dist/sync/sync-saga-coordinator.d.mts.map +1 -1
- package/dist/sync/sync-saga-coordinator.mjs +62 -1
- package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
- package/dist/sync/sync-withid.connect.respec.d.mts +12 -0
- package/dist/sync/sync-withid.connect.respec.d.mts.map +1 -0
- package/dist/sync/sync-withid.connect.respec.mjs +205 -0
- package/dist/sync/sync-withid.connect.respec.mjs.map +1 -0
- package/dist/sync/sync-withid.establish.respec.d.mts +19 -0
- package/dist/sync/sync-withid.establish.respec.d.mts.map +1 -0
- package/dist/sync/sync-withid.establish.respec.mjs +322 -0
- package/dist/sync/sync-withid.establish.respec.mjs.map +1 -0
- package/package.json +1 -1
- package/src/keystone/keystone-config-builder.mts +73 -4
- package/src/keystone/keystone-constants.mts +42 -6
- package/src/keystone/keystone-helpers.mts +44 -2
- package/src/keystone/keystone-policy-types.mts +25 -0
- package/src/keystone/keystone-policy.schema.json +51 -0
- package/src/keystone/keystone-service-v1.mts +3 -3
- package/src/sync/README.md +1 -104
- package/src/sync/docs/architecture.md +28 -8
- package/src/sync/docs/security.md +380 -0
- package/src/sync/graft-info/graft-info-helpers.respec.mts +7 -7
- package/src/sync/sync-conflict-adv-multitimelines.respec.mts +21 -21
- package/src/sync/sync-conflict-basic-divergence.respec.mts +2 -2
- package/src/sync/sync-conflict-basic-multitimelines.respec.mts +5 -5
- package/src/sync/sync-conflict-text-merge.respec.mts +25 -25
- package/src/sync/sync-helpers.mts +51 -1
- package/src/sync/sync-innerspace-constants.respec.mts +1 -1
- package/src/sync/sync-innerspace-deep-updates.respec.mts +1 -1
- package/src/sync/sync-innerspace-dest-ahead.respec.mts +3 -3
- package/src/sync/sync-innerspace-multiple-timelines.respec.mts +1 -1
- package/src/sync/sync-innerspace-partial-update.respec.mts +2 -2
- package/src/sync/sync-innerspace.respec.mts +3 -3
- package/src/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.mts +20 -0
- package/src/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-v1.mts +23 -3
- package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +38 -1
- package/src/sync/sync-peer/sync-peer-types.mts +70 -1
- package/src/sync/sync-peer/sync-peer-v1.mts +94 -1
- package/src/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-types.mts +36 -0
- package/src/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.mts +337 -0
- package/src/sync/sync-peer/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mts +388 -0
- package/src/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-types.mts +35 -0
- package/src/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mts +321 -0
- package/src/sync/sync-saga-coordinator.mts +84 -0
- package/src/sync/sync-withid.connect.respec.mts +243 -0
- package/src/sync/sync-withid.establish.respec.mts +361 -0
- package/src/sync/unused-identity-backup.mts.md +1 -1
- package/dist/sync/sync-innerspace-dest-ahead-withid.respec.d.mts +0 -2
- package/dist/sync/sync-innerspace-dest-ahead-withid.respec.d.mts.map +0 -1
- package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs +0 -310
- package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs.map +0 -1
- package/src/sync/sync-innerspace-dest-ahead-withid.respec.mts +0 -364
|
@@ -9,6 +9,7 @@ import { SyncSagaContextData_V1, SyncSagaContextIbGib_V1, SyncSagaContextRel8ns_
|
|
|
9
9
|
import { Witness_V1 } from '../../witness/witness-types.mjs';
|
|
10
10
|
import { IbGibSpaceAny } from '../../witness/space/space-base-v1.mjs';
|
|
11
11
|
import { MetaspaceService } from '../../witness/space/metaspace/metaspace-types.mjs';
|
|
12
|
+
import { KeystoneIbGib_V1, KeystonePoolConfig } from '../../keystone/keystone-types.mjs';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Data for the SyncPeer witness.
|
|
@@ -36,13 +37,29 @@ export interface SyncPeerIbGib_V1 extends IbGib_V1<SyncPeerData_V1, SyncPeerRel8
|
|
|
36
37
|
* opts used in `connect(opts)`
|
|
37
38
|
*/
|
|
38
39
|
export interface ConnectSyncPeerOpts {
|
|
40
|
+
/**
|
|
41
|
+
* TODO: sagaId is now also on {@link InitializeSyncPeerOpts} since a peer
|
|
42
|
+
* is scoped to a single sync saga. Evaluate whether this duplicate is still
|
|
43
|
+
* needed when implementing the connect phase (Phase 2).
|
|
44
|
+
*/
|
|
39
45
|
sagaId: string;
|
|
40
46
|
}
|
|
41
47
|
|
|
42
48
|
/**
|
|
43
|
-
* base initialization opts
|
|
49
|
+
* base initialization opts.
|
|
50
|
+
*
|
|
51
|
+
* A sync peer is scoped to exactly one sync saga. A new peer instance must be
|
|
52
|
+
* created for each `sync(...)` call. Reusing a peer across multiple sagas is
|
|
53
|
+
* not supported and would compromise the identity security model.
|
|
44
54
|
*/
|
|
45
55
|
export interface InitializeSyncPeerOpts {
|
|
56
|
+
/**
|
|
57
|
+
* Unique id for the sync saga this peer is servicing.
|
|
58
|
+
* Generated by `SyncSagaCoordinator.sync()` and passed here so that
|
|
59
|
+
* `establishSessionIdentity` can derive the session secret via
|
|
60
|
+
* `KDF(senderSecret, sagaId)`.
|
|
61
|
+
*/
|
|
62
|
+
sagaId?: string;
|
|
46
63
|
/**
|
|
47
64
|
* reference to the local metaspace
|
|
48
65
|
*/
|
|
@@ -62,6 +79,44 @@ export interface InitializeSyncPeerOpts {
|
|
|
62
79
|
* received/created throughout the transaction until commit.
|
|
63
80
|
*/
|
|
64
81
|
localTempSpace?: IbGibSpaceAny;
|
|
82
|
+
/**
|
|
83
|
+
* The sender's long-lived Domain Keystone (I) — Alice's identity.
|
|
84
|
+
* Optional; if omitted the sync runs without identity (anonymous).
|
|
85
|
+
* Must be the current tip frame of I's timeline.
|
|
86
|
+
*
|
|
87
|
+
* Both {@link senderIdentity} and {@link fnSenderSecret} must be provided
|
|
88
|
+
* together or omitted together.
|
|
89
|
+
*/
|
|
90
|
+
senderIdentity?: KeystoneIbGib_V1;
|
|
91
|
+
/**
|
|
92
|
+
* Returns the plaintext secret corresponding to {@link senderIdentity}.
|
|
93
|
+
* Wrapped in a function to avoid holding the secret in memory longer than needed.
|
|
94
|
+
*
|
|
95
|
+
* Both {@link senderIdentity} and {@link fnSenderSecret} must be provided
|
|
96
|
+
* together or omitted together.
|
|
97
|
+
*/
|
|
98
|
+
fnSenderSecret?: () => Promise<string>;
|
|
99
|
+
/**
|
|
100
|
+
* Pool config for the session keystone's transport connect handshake pool.
|
|
101
|
+
* Required when {@link senderIdentity} is provided.
|
|
102
|
+
*
|
|
103
|
+
* @see {@link POOL_ID_CONNECT}
|
|
104
|
+
*/
|
|
105
|
+
sessionConnectPoolConfig?: KeystonePoolConfig;
|
|
106
|
+
/**
|
|
107
|
+
* Pool config for the session keystone's per-turn signing pool (`sync`).
|
|
108
|
+
* Required when {@link senderIdentity} is provided.
|
|
109
|
+
*
|
|
110
|
+
* @see {@link POOL_ID_SYNC}
|
|
111
|
+
*/
|
|
112
|
+
sessionSyncPoolConfig?: KeystonePoolConfig;
|
|
113
|
+
/**
|
|
114
|
+
* Addresses of the synced domains (ibgibs).
|
|
115
|
+
* Used during `establishSessionIdentity` to bind the session keystone (S)
|
|
116
|
+
* strictly to these domains, preventing S from acting as a "blank check"
|
|
117
|
+
* for unauthorized domains.
|
|
118
|
+
*/
|
|
119
|
+
targetAddrs?: string[];
|
|
65
120
|
}
|
|
66
121
|
|
|
67
122
|
/**
|
|
@@ -107,6 +162,20 @@ export interface SyncPeerWitness<TInitializeOpts extends InitializeSyncPeerOpts
|
|
|
107
162
|
*/
|
|
108
163
|
payloadIbGibsDomainReceived$: SubjectWitness<IbGib_V1>;
|
|
109
164
|
|
|
165
|
+
/**
|
|
166
|
+
* Pre-connect phase: creates the session keystone (S) locally, evolves
|
|
167
|
+
* `senderIdentity` (I → I1) with a `sync` claim targeting S, and posts
|
|
168
|
+
* both to the receiver's domain registry.
|
|
169
|
+
*
|
|
170
|
+
* Must be called before `connect()`. No-op if `senderIdentity` was not
|
|
171
|
+
* provided in {@link InitializeSyncPeerOpts}.
|
|
172
|
+
*
|
|
173
|
+
* @returns The session keystone genesis (S^Stjp). The coordinator holds
|
|
174
|
+
* this reference for the remainder of the saga. The name `newSenderIdentity`
|
|
175
|
+
* (I1) is intentionally scoped only within this method to avoid confusion.
|
|
176
|
+
*/
|
|
177
|
+
establishSessionIdentity(): Promise<KeystoneIbGib_V1 | undefined>;
|
|
178
|
+
|
|
110
179
|
/**
|
|
111
180
|
* Establishes the connection context.
|
|
112
181
|
*
|
|
@@ -23,8 +23,11 @@ import { IbGibSpaceAny } from '../../witness/space/space-base-v1.mjs';
|
|
|
23
23
|
import { newupSubject } from '../../common/pubsub/subject/subject-helper.mjs';
|
|
24
24
|
import { authenticateContext, authorizeContext, validateContextAndSagaFrame } from '../sync-saga-context/sync-saga-context-helpers.mjs';
|
|
25
25
|
import { getFromSpace } from '../../witness/space/space-helper.mjs';
|
|
26
|
-
import { getFullSyncSagaHistory } from '../sync-helpers.mjs';
|
|
26
|
+
import { getFullSyncSagaHistory, deriveSessionSecret } from '../sync-helpers.mjs';
|
|
27
27
|
import { SyncSagaFrameDependencyGraph } from '../sync-types.mjs';
|
|
28
|
+
import { KeystoneService_V1 } from '../../keystone/keystone-service-v1.mjs';
|
|
29
|
+
import { KeystoneIbGib_V1 } from '../../keystone/keystone-types.mjs';
|
|
30
|
+
import { KEYSTONE_VERB_SYNC } from '../../keystone/keystone-constants.mjs';
|
|
28
31
|
|
|
29
32
|
const logalot = GLOBAL_LOG_A_LOT;
|
|
30
33
|
const logalotControlDomain = false;
|
|
@@ -107,6 +110,96 @@ export abstract class SyncPeer_V1<
|
|
|
107
110
|
*/
|
|
108
111
|
protected abstract connectImpl(opts: TConnectOpts): Promise<void>;
|
|
109
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Pre-connect phase: establishes session identity.
|
|
115
|
+
*
|
|
116
|
+
* Shared base implementation:
|
|
117
|
+
* 1. Derives `sessionSecret = KDF(senderSecret, sagaId)`.
|
|
118
|
+
* 2. Creates session keystone genesis S (connect + sync pools) in `localSpace`.
|
|
119
|
+
* 3. Evolves `senderIdentity` → `newSenderIdentity` (I1) with a `sync`
|
|
120
|
+
* claim targeting S^Stjp, stored in `localSpace`.
|
|
121
|
+
* 4. Delegates posting of both keystones to the receiver via the abstract
|
|
122
|
+
* hook {@link postEstablishToReceiver} (peer-specific transport).
|
|
123
|
+
*
|
|
124
|
+
* Returns `undefined` (no-op) if no `senderIdentity` was provided in opts.
|
|
125
|
+
*
|
|
126
|
+
* @returns The session keystone genesis (S^Stjp) so the coordinator can
|
|
127
|
+
* hold a reference for subsequent per-turn signing. The name
|
|
128
|
+
* `newSenderIdentity` (I1) is scoped only within this method.
|
|
129
|
+
*/
|
|
130
|
+
public async establishSessionIdentity(): Promise<KeystoneIbGib_V1 | undefined> {
|
|
131
|
+
const lc = `${this.lc}[${this.establishSessionIdentity.name}]`;
|
|
132
|
+
try {
|
|
133
|
+
if (logalot) { console.log(`${lc} starting... (I: f2a1b3c4d5e6f7a8b9c0d1e2f3a4b526)`); }
|
|
134
|
+
|
|
135
|
+
if (!this.opts) { throw new Error(`(UNEXPECTED) this.opts falsy? Call initializeOpts first. (E: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c526)`); }
|
|
136
|
+
|
|
137
|
+
const { senderIdentity, fnSenderSecret, sagaId, localMetaspace, localSpace } = this.opts;
|
|
138
|
+
|
|
139
|
+
// No identity provided — anonymous sync, nothing to establish.
|
|
140
|
+
if (!senderIdentity || !fnSenderSecret) {
|
|
141
|
+
if (logalot) { console.log(`${lc} no senderIdentity/fnSenderSecret — skipping establish (I: f29348a77d1542326d14043ea4b69126)`); }
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (!sagaId) { throw new Error(`(UNEXPECTED) sagaId falsy? Must be set in initializeOpts before calling establishSessionIdentity. (E: c6ba389d51b8af07d82458f875cf9826)`); }
|
|
146
|
+
|
|
147
|
+
const senderSecret = await fnSenderSecret();
|
|
148
|
+
if (!senderSecret) { throw new Error(`senderSecret falsy. senderSecret required. (E: 1a8b0298bf78cbdf284b7988983b9826)`); }
|
|
149
|
+
const sessionSecret = await deriveSessionSecret({ senderSecret, sagaId });
|
|
150
|
+
|
|
151
|
+
const keystoneSvc = new KeystoneService_V1();
|
|
152
|
+
|
|
153
|
+
// Step 1: Create S genesis in localSpace.
|
|
154
|
+
// Pool configs must be provided via opts (set by coordinator before calling establish).
|
|
155
|
+
if (!this.opts.sessionConnectPoolConfig) { throw new Error(`(UNEXPECTED) opts.sessionConnectPoolConfig falsy? (E: 3351fd566eb8bbd2f821bb08c4419826)`); }
|
|
156
|
+
if (!this.opts.sessionSyncPoolConfig) { throw new Error(`(UNEXPECTED) opts.sessionSyncPoolConfig falsy? (E: dbffa810d9e7ff6079088deb5b8e7826)`); }
|
|
157
|
+
|
|
158
|
+
const sessionIdentity = await keystoneSvc.genesis({
|
|
159
|
+
masterSecret: sessionSecret,
|
|
160
|
+
configs: [this.opts.sessionConnectPoolConfig, this.opts.sessionSyncPoolConfig],
|
|
161
|
+
frameDetails: this.opts.targetAddrs ? { targetAddrs: this.opts.targetAddrs } : undefined,
|
|
162
|
+
metaspace: localMetaspace,
|
|
163
|
+
space: localSpace,
|
|
164
|
+
});
|
|
165
|
+
const sessionIdentityAddr = getIbGibAddr({ ibGib: sessionIdentity });
|
|
166
|
+
|
|
167
|
+
// Step 2: Evolve senderIdentity → newSenderIdentity (I1) with sync claim.
|
|
168
|
+
const newSenderIdentity = await keystoneSvc.sign({
|
|
169
|
+
latestKeystone: senderIdentity,
|
|
170
|
+
masterSecret: senderSecret,
|
|
171
|
+
claim: {
|
|
172
|
+
verb: KEYSTONE_VERB_SYNC,
|
|
173
|
+
target: sessionIdentityAddr,
|
|
174
|
+
},
|
|
175
|
+
metaspace: localMetaspace,
|
|
176
|
+
space: localSpace,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Step 3: Post both to the receiver (peer-specific).
|
|
180
|
+
await this.postEstablishToReceiver({ newSenderIdentity, sessionIdentity });
|
|
181
|
+
|
|
182
|
+
return sessionIdentity;
|
|
183
|
+
} catch (error) {
|
|
184
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
185
|
+
throw error;
|
|
186
|
+
} finally {
|
|
187
|
+
if (logalot) { console.log(`${lc} complete.`); }
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Peer-specific hook: transmits `newSenderIdentity` (I1) and
|
|
193
|
+
* `sessionIdentity` (S) to the receiver's domain registry.
|
|
194
|
+
*
|
|
195
|
+
* - **Innerspace**: puts both into `receiverMetaspace` / `receiverSpace`.
|
|
196
|
+
* - **WebSocket**: HTTP POST to the domain provider's keystone endpoint.
|
|
197
|
+
*/
|
|
198
|
+
protected abstract postEstablishToReceiver(opts: {
|
|
199
|
+
newSenderIdentity: KeystoneIbGib_V1;
|
|
200
|
+
sessionIdentity: KeystoneIbGib_V1;
|
|
201
|
+
}): Promise<void>;
|
|
202
|
+
|
|
110
203
|
/**
|
|
111
204
|
* base implementation just sets the opts property.
|
|
112
205
|
*
|
package/src/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-types.mts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module sync-peer-websocket-receiver-types
|
|
3
|
+
*/
|
|
4
|
+
import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
|
|
5
|
+
import {
|
|
6
|
+
SyncPeerData_V1, SyncPeerRel8ns_V1, SyncPeerWitness,
|
|
7
|
+
InitializeSyncPeerOpts, ConnectSyncPeerOpts
|
|
8
|
+
} from '../sync-peer-types.mjs';
|
|
9
|
+
import { SyncSagaCoordinator } from '../../sync-saga-coordinator.mjs';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Data for the SyncPeerWebSocketReceiver witness.
|
|
13
|
+
*/
|
|
14
|
+
export interface SyncPeerWebSocketReceiverData_V1 extends SyncPeerData_V1 {
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Relations for the SyncPeerWebSocketReceiver witness.
|
|
19
|
+
*/
|
|
20
|
+
export interface SyncPeerWebSocketReceiverRel8ns_V1 extends SyncPeerRel8ns_V1 {
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The SyncPeerWebSocketReceiver witness IbGib.
|
|
25
|
+
*/
|
|
26
|
+
export interface SyncPeerWebSocketReceiverIbGib_V1 extends IbGib_V1<SyncPeerWebSocketReceiverData_V1, SyncPeerWebSocketReceiverRel8ns_V1> { }
|
|
27
|
+
|
|
28
|
+
export interface ConnectSyncPeerWebSocketReceiverOpts extends ConnectSyncPeerOpts {
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface InitializeSyncPeerWebSocketReceiverOpts extends InitializeSyncPeerOpts {
|
|
32
|
+
/**
|
|
33
|
+
* The local SyncSagaCoordinator instance running on the receiver/server.
|
|
34
|
+
*/
|
|
35
|
+
localCoordinator: SyncSagaCoordinator;
|
|
36
|
+
}
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module sync-peer-websocket-receiver-v1
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { extractErrorMsg, getUUID } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
6
|
+
import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
|
|
7
|
+
import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
|
|
8
|
+
|
|
9
|
+
import { GLOBAL_LOG_A_LOT } from '../../../core-constants.mjs';
|
|
10
|
+
import { SyncPeer_V1 } from '../sync-peer-v1.mjs';
|
|
11
|
+
import { SyncSagaContextIbGib_V1 } from '../../sync-saga-context/sync-saga-context-types.mjs';
|
|
12
|
+
import { authenticateContext } from '../../sync-saga-context/sync-saga-context-helpers.mjs';
|
|
13
|
+
import { IbGibSpaceAny } from '../../../witness/space/space-base-v1.mjs';
|
|
14
|
+
import { putInSpace, registerNewIbGib } from '../../../witness/space/space-helper.mjs';
|
|
15
|
+
import {
|
|
16
|
+
ConnectSyncPeerWebSocketReceiverOpts,
|
|
17
|
+
InitializeSyncPeerWebSocketReceiverOpts,
|
|
18
|
+
SyncPeerWebSocketReceiverData_V1, SyncPeerWebSocketReceiverRel8ns_V1,
|
|
19
|
+
SyncPeerWebSocketReceiverIbGib_V1
|
|
20
|
+
} from './sync-peer-websocket-receiver-types.mjs';
|
|
21
|
+
import { KeystoneIbGib_V1 } from '../../../keystone/keystone-types.mjs';
|
|
22
|
+
import { SESSION_KEYSTONE_POLICY, verifyConnectProof } from './sync-websocket-peer-helpers.mjs';
|
|
23
|
+
|
|
24
|
+
const logalot = GLOBAL_LOG_A_LOT || true;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A platform-agnostic interface wrapping runtime-specific WebSocket stream operations.
|
|
28
|
+
*/
|
|
29
|
+
export interface IWebSocketWrapper {
|
|
30
|
+
send(data: string): void;
|
|
31
|
+
onMessage(callback: (data: string) => void): void;
|
|
32
|
+
onClose(callback: () => void): void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Platform-agnostic WebSocket Receiver Peer.
|
|
37
|
+
*
|
|
38
|
+
* Fully encapsulates the multi-turn cryptographic challenge connect and runtime
|
|
39
|
+
* turn routing.
|
|
40
|
+
*/
|
|
41
|
+
export class SyncPeerWebSocketReceiver_V1
|
|
42
|
+
extends SyncPeer_V1<ConnectSyncPeerWebSocketReceiverOpts, InitializeSyncPeerWebSocketReceiverOpts>
|
|
43
|
+
implements SyncPeerWebSocketReceiverIbGib_V1 {
|
|
44
|
+
|
|
45
|
+
protected override lc: string = `[${SyncPeerWebSocketReceiver_V1.name}]`;
|
|
46
|
+
|
|
47
|
+
override get classname(): string {
|
|
48
|
+
return SyncPeerWebSocketReceiver_V1.name;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
declare data: SyncPeerWebSocketReceiverData_V1 | undefined;
|
|
52
|
+
declare rel8ns: SyncPeerWebSocketReceiverRel8ns_V1 | undefined;
|
|
53
|
+
|
|
54
|
+
protected socketWrapper?: IWebSocketWrapper;
|
|
55
|
+
|
|
56
|
+
// Connect State Machine variables
|
|
57
|
+
protected isAuthenticated = false;
|
|
58
|
+
protected challengeUuid?: string;
|
|
59
|
+
protected demandedIds?: string[];
|
|
60
|
+
protected sessionS_tjpAddr?: string;
|
|
61
|
+
|
|
62
|
+
constructor(
|
|
63
|
+
initialData: SyncPeerWebSocketReceiverData_V1,
|
|
64
|
+
initialRel8ns?: SyncPeerWebSocketReceiverRel8ns_V1,
|
|
65
|
+
) {
|
|
66
|
+
super(initialData, initialRel8ns);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Wires the peer receiver to the platform-specific socket stream and
|
|
71
|
+
* triggers the connect.
|
|
72
|
+
*/
|
|
73
|
+
public async bindSocket(socketWrapper: IWebSocketWrapper): Promise<void> {
|
|
74
|
+
const lc = `${this.lc}[${this.bindSocket.name}]`;
|
|
75
|
+
this.socketWrapper = socketWrapper;
|
|
76
|
+
socketWrapper.onMessage((data) => this.handleIncomingMessage(data));
|
|
77
|
+
|
|
78
|
+
// Immediately trigger multi-turn challenge connection
|
|
79
|
+
try {
|
|
80
|
+
this.challengeUuid = await getUUID();
|
|
81
|
+
socketWrapper.send(JSON.stringify({
|
|
82
|
+
type: 'auth-challenge-init',
|
|
83
|
+
challengeUuid: this.challengeUuid
|
|
84
|
+
}));
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error(`${lc} failed triggering challenge init: ${extractErrorMsg(error)}`);
|
|
87
|
+
socketWrapper.send(JSON.stringify({
|
|
88
|
+
type: 'auth-fail',
|
|
89
|
+
message: 'Internal server connect error'
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
protected override async preConnectCheck(opts: ConnectSyncPeerWebSocketReceiverOpts): Promise<void> {
|
|
95
|
+
// Handled dynamically on upgrade
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
protected override async connectImpl(opts: ConnectSyncPeerWebSocketReceiverOpts): Promise<void> {
|
|
99
|
+
// Handled dynamically on upgrade
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
protected override async postEstablishToReceiver(opts: {
|
|
103
|
+
newSenderIdentity: KeystoneIbGib_V1;
|
|
104
|
+
sessionIdentity: KeystoneIbGib_V1;
|
|
105
|
+
}): Promise<void> {
|
|
106
|
+
throw new Error(`postEstablishToReceiver is not supported on Receiver Peer (E: 309f3cf8e7c813d338394f28c576da26)`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
protected override async sendContextRequest(context: SyncSagaContextIbGib_V1): Promise<SyncSagaContextIbGib_V1 | undefined> {
|
|
110
|
+
throw new Error(`sendContextRequest is not supported on Receiver Peer (E: e5327ed6c64883e12ef95984f1409926)`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Helper to load a Session Keystone from storage */
|
|
114
|
+
protected async getSessionKeystone(sAddr: string): Promise<KeystoneIbGib_V1> {
|
|
115
|
+
const metaspace = this.opts!.localMetaspace;
|
|
116
|
+
const space = this.opts!.localSpace;
|
|
117
|
+
const resGet = await metaspace.get({ addrs: [sAddr], space });
|
|
118
|
+
if (resGet.success && resGet.ibGibs && resGet.ibGibs.length === 1) {
|
|
119
|
+
return resGet.ibGibs[0] as KeystoneIbGib_V1;
|
|
120
|
+
}
|
|
121
|
+
throw new Error(`Session keystone not found in storage: ${sAddr} (E: 42315837e3b1deb5b81072f8601e6a26)`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
protected async ensureLocalTempSpace(): Promise<IbGibSpaceAny> {
|
|
125
|
+
const lc = `${this.lc}[${this.ensureLocalTempSpace.name}]`;
|
|
126
|
+
try {
|
|
127
|
+
if (!this.opts) { throw new Error(`opts not initialized. (E: c4929fb1596833a7186d119855bb7e26)`); }
|
|
128
|
+
|
|
129
|
+
if (!this.opts.localTempSpace) {
|
|
130
|
+
const { localMetaspace } = this.opts;
|
|
131
|
+
|
|
132
|
+
const uuid = crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36);
|
|
133
|
+
const tempSpaceName = `tmp_sync_recv_${uuid.substring(0, 8)}`;
|
|
134
|
+
const localTempSpace = await localMetaspace.createNewLocalSpace({
|
|
135
|
+
opts: {
|
|
136
|
+
allowCancel: false,
|
|
137
|
+
spaceName: tempSpaceName,
|
|
138
|
+
getFnPrompt: localMetaspace.getFnPrompt!,
|
|
139
|
+
logalot
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
if (!localTempSpace) { throw new Error(`couldn't create a temp space (E: d82461769b4bbb35df5d6a8a9c665426)`); }
|
|
143
|
+
await localTempSpace.initialized;
|
|
144
|
+
this.opts.localTempSpace = localTempSpace;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return this.opts.localTempSpace;
|
|
148
|
+
} catch (error) {
|
|
149
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Entry point for processing raw text frames received over the active WebSocket connection.
|
|
156
|
+
*/
|
|
157
|
+
public async handleIncomingMessage(messageText: string): Promise<void> {
|
|
158
|
+
const lc = `${this.lc}[${this.handleIncomingMessage.name}]`;
|
|
159
|
+
try {
|
|
160
|
+
if (!this.socketWrapper) {
|
|
161
|
+
throw new Error(`WebSocket wrapper not bound to receiver peer (E: ad4c5838d1b87259586b21a89b2c7726)`);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const msg = JSON.parse(messageText);
|
|
165
|
+
if (logalot) { console.log(`${lc} received frame: ${msg.type}`); }
|
|
166
|
+
|
|
167
|
+
// 1. Connect Phase Route Guard
|
|
168
|
+
if (!this.isAuthenticated) {
|
|
169
|
+
await this.handleConnectFrame(msg);
|
|
170
|
+
return; /* <<<< returns early */
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// 2. Authenticated Runtime Sync Route
|
|
174
|
+
if (msg.type === 'domain-payload') {
|
|
175
|
+
const ibGib = msg.ibGib as IbGib_V1;
|
|
176
|
+
const tempSpace = await this.ensureLocalTempSpace();
|
|
177
|
+
await putInSpace({ space: tempSpace, ibGibs: [ibGib] });
|
|
178
|
+
} else if (msg.type === 'sync-frame') {
|
|
179
|
+
const context = msg.context as SyncSagaContextIbGib_V1;
|
|
180
|
+
|
|
181
|
+
// Process turn through coordinator
|
|
182
|
+
const responseCtx = await this.handleIncomingSyncRequest({ context });
|
|
183
|
+
|
|
184
|
+
if (responseCtx) {
|
|
185
|
+
// Send outgoing payload domain ibgibs first
|
|
186
|
+
const responsePayloads = responseCtx.payloadIbGibsDomain ?? [];
|
|
187
|
+
for (const ibGib of responsePayloads) {
|
|
188
|
+
this.socketWrapper.send(JSON.stringify({
|
|
189
|
+
type: 'domain-payload',
|
|
190
|
+
ibGib
|
|
191
|
+
}));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Send evolved context turn response
|
|
195
|
+
this.socketWrapper.send(JSON.stringify({
|
|
196
|
+
type: 'sync-frame-response',
|
|
197
|
+
context: responseCtx
|
|
198
|
+
}));
|
|
199
|
+
} else {
|
|
200
|
+
if (logalot) { console.log(`${lc} synchronization session completed successfully.`); }
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
} catch (error) {
|
|
204
|
+
console.error(`${lc} message frame handling failed: ${extractErrorMsg(error)}`);
|
|
205
|
+
this.socketWrapper?.send(JSON.stringify({
|
|
206
|
+
type: this.isAuthenticated ? 'sync-error' : 'auth-fail',
|
|
207
|
+
message: extractErrorMsg(error)
|
|
208
|
+
}));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Handles the multi-turn cryptographic challenge connect messages.
|
|
214
|
+
*/
|
|
215
|
+
protected async handleConnectFrame(msg: any): Promise<void> {
|
|
216
|
+
const lc = `${this.lc}[${this.handleConnectFrame.name}]`;
|
|
217
|
+
const metaspace = this.opts!.localMetaspace;
|
|
218
|
+
const space = this.opts!.localSpace;
|
|
219
|
+
|
|
220
|
+
if (msg.type === 'auth-init') {
|
|
221
|
+
const { sAddr } = msg;
|
|
222
|
+
if (logalot) { console.log(`${lc} auth-init for ${sAddr}`); }
|
|
223
|
+
|
|
224
|
+
const authorizedS = await this.getSessionKeystone(sAddr);
|
|
225
|
+
const connectPool = (authorizedS.data?.challengePools ?? [])
|
|
226
|
+
.find(p => p.id === SESSION_KEYSTONE_POLICY.CONNECT_POOL.ID);
|
|
227
|
+
if (!connectPool) {
|
|
228
|
+
throw new Error(`Session keystone missing "${SESSION_KEYSTONE_POLICY.CONNECT_POOL.ID}" pool (E: 66b2a2e32db8f03168f6f2a8b746cb26)`);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Demand random challenges
|
|
232
|
+
const challengeIds = Object.keys(connectPool.challenges);
|
|
233
|
+
this.demandedIds = challengeIds.sort(() => 0.5 - Math.random()).slice(0, SESSION_KEYSTONE_POLICY.CONNECT_POOL.SERVER_DEMAND_COUNT);
|
|
234
|
+
|
|
235
|
+
// Resolve secure S TJP
|
|
236
|
+
const past = authorizedS.rel8ns?.past;
|
|
237
|
+
this.sessionS_tjpAddr = (past && past.length > 0) ? past[0] : getIbGibAddr({ ibGib: authorizedS });
|
|
238
|
+
|
|
239
|
+
this.socketWrapper!.send(JSON.stringify({
|
|
240
|
+
type: 'auth-challenge',
|
|
241
|
+
challengeUuid: this.challengeUuid,
|
|
242
|
+
demandedIds: this.demandedIds
|
|
243
|
+
}));
|
|
244
|
+
|
|
245
|
+
} else if (msg.type === 'auth-proof') {
|
|
246
|
+
const { proofFrame } = msg;
|
|
247
|
+
if (logalot) { console.log(`${lc} verifying auth-proof...`); }
|
|
248
|
+
|
|
249
|
+
if (!this.sessionS_tjpAddr) {
|
|
250
|
+
throw new Error(`Missing active connect session TJP address (E: bf271853de61a04b6d05d6889263f826)`);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const sAddr_latest = await metaspace.getLatestAddr({ tjpAddr: this.sessionS_tjpAddr, space });
|
|
254
|
+
if (!sAddr_latest) {
|
|
255
|
+
throw new Error(`Authorized session keystone tip not found (E: b8cda5cdc058903318db536f59e8e826)`);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const sKeystone_latest = await this.getSessionKeystone(sAddr_latest);
|
|
259
|
+
|
|
260
|
+
// Crytographically verify proof evolution and demand solutions
|
|
261
|
+
await verifyConnectProof({
|
|
262
|
+
proofFrame,
|
|
263
|
+
sKeystone_latest,
|
|
264
|
+
challengeUuid: this.challengeUuid!,
|
|
265
|
+
demandedIds: this.demandedIds!
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
// Persist the newly validated evolved session keystone tip
|
|
269
|
+
await metaspace.put({ ibGibs: [proofFrame], space });
|
|
270
|
+
|
|
271
|
+
if (logalot) { console.log(`${lc} connect validation successful! Connection upgraded to active sync session.`); }
|
|
272
|
+
this.isAuthenticated = true;
|
|
273
|
+
|
|
274
|
+
this.socketWrapper!.send(JSON.stringify({
|
|
275
|
+
type: 'auth-ok'
|
|
276
|
+
}));
|
|
277
|
+
} else {
|
|
278
|
+
throw new Error(`Unexpected message type ${msg.type} during connect phase (E: f67a0f47f8426c2b01af5bc3d0146b26)`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Executes the transaction turn through the local SyncSagaCoordinator.
|
|
284
|
+
*/
|
|
285
|
+
public async handleIncomingSyncRequest({
|
|
286
|
+
context,
|
|
287
|
+
payloadIbGibsControl = [],
|
|
288
|
+
}: {
|
|
289
|
+
context: SyncSagaContextIbGib_V1;
|
|
290
|
+
payloadIbGibsControl?: IbGib_V1[];
|
|
291
|
+
}): Promise<SyncSagaContextIbGib_V1 | undefined> {
|
|
292
|
+
const lc = `${this.lc}[${this.handleIncomingSyncRequest.name}]`;
|
|
293
|
+
try {
|
|
294
|
+
if (logalot) { console.log(`${lc} starting incoming sync turn...`); }
|
|
295
|
+
|
|
296
|
+
if (!this.opts) { throw new Error(`opts not initialized. (E: 0c98186714e85b9a08bb9d98daada826)`); }
|
|
297
|
+
const { localCoordinator, localMetaspace, localSpace } = this.opts;
|
|
298
|
+
const localTempSpace = await this.ensureLocalTempSpace();
|
|
299
|
+
|
|
300
|
+
// Put control ibgibs into durable space
|
|
301
|
+
const allControlIbGibs = [context, ...payloadIbGibsControl];
|
|
302
|
+
for (const ibGib of allControlIbGibs) {
|
|
303
|
+
await putInSpace({ space: localSpace, ibGibs: [ibGib] });
|
|
304
|
+
await registerNewIbGib({ space: localSpace, ibGib });
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Authenticate context signature
|
|
308
|
+
const authErrors = await authenticateContext({
|
|
309
|
+
context,
|
|
310
|
+
space: localSpace,
|
|
311
|
+
});
|
|
312
|
+
if (authErrors.length > 0) {
|
|
313
|
+
throw new Error(`Context authentication failed: ${authErrors.join(', ')} (E: 424bd9b03ff8a42df8b1a438ed393726)`);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Put incoming domain payloads into temp space
|
|
317
|
+
if (context.payloadIbGibsDomain && context.payloadIbGibsDomain.length > 0) {
|
|
318
|
+
for (const ibGib of context.payloadIbGibsDomain) {
|
|
319
|
+
await putInSpace({ space: localTempSpace, ibGibs: [ibGib] });
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Evolve frame and run next coordinator sync turn
|
|
324
|
+
const responseCtx = await localCoordinator.continueSync({
|
|
325
|
+
sagaContext: context,
|
|
326
|
+
metaspace: localMetaspace,
|
|
327
|
+
mySpace: localSpace,
|
|
328
|
+
myTempSpace: localTempSpace,
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
return responseCtx || undefined;
|
|
332
|
+
} catch (error) {
|
|
333
|
+
console.error(`${lc} handleIncomingSyncRequest turn execution failed: ${extractErrorMsg(error)}`);
|
|
334
|
+
throw error;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|