@ibgib/space-gib 0.0.5 → 0.0.7
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/README.md +20 -0
- package/dist/client/bootstrap.mjs +31 -31
- package/dist/client/bootstrap.mjs.map +3 -3
- package/dist/client/chunk-RXFIBFRK.mjs +42 -0
- package/dist/client/chunk-RXFIBFRK.mjs.map +7 -0
- package/dist/client/chunk-ULFNE26Y.mjs +2216 -0
- package/dist/client/chunk-ULFNE26Y.mjs.map +7 -0
- package/dist/client/index.html +35 -14
- package/dist/client/index.mjs +1 -1
- package/dist/client/script.mjs +1 -1
- package/dist/client/style.css +29 -5
- package/dist/server/server.mjs +1447 -270
- package/dist/server/server.mjs.map +4 -4
- package/package.json +5 -5
- package/space-gib.localhost-1783713259760.log +45 -0
- package/src/client/AUTO-GENERATED-version.mts +1 -1
- package/src/client/bootstrap.mts +9 -0
- package/src/client/components/identity-header/identity-header.css +40 -2
- package/src/client/components/identity-header/identity-header.html +3 -2
- package/src/client/components/identity-header/identity-header.mts +127 -49
- package/src/client/components/identity-manager/identity-manager.css +57 -353
- package/src/client/components/identity-manager/identity-manager.html +0 -94
- package/src/client/components/identity-manager/identity-manager.mts +356 -484
- package/src/client/components/keystone-creator/keystone-creator.mts +90 -13
- package/src/client/components/keystone-details/keystone-details.css +472 -0
- package/src/client/components/keystone-details/keystone-details.html +99 -0
- package/src/client/components/keystone-details/keystone-details.mts +821 -0
- package/src/client/components/keystone-scrubber/SCRUBBER_IMPLEMENTATION.md +33 -0
- package/src/client/components/keystone-scrubber/keystone-scrubber.css +46 -0
- package/src/client/components/keystone-scrubber/keystone-scrubber.html +15 -0
- package/src/client/components/keystone-scrubber/keystone-scrubber.mts +356 -0
- package/src/client/dev-tools/common.mts +505 -10
- package/src/client/dev-tools/phase-4-1.mts +19 -4
- package/src/client/dev-tools/phase-4-10.mts +77 -305
- package/src/client/dev-tools/phase-4-2.mts +46 -212
- package/src/client/dev-tools/phase-4-3.mts +57 -198
- package/src/client/dev-tools/phase-4-4.mts +57 -170
- package/src/client/dev-tools/phase-4-5.mts +48 -204
- package/src/client/dev-tools/phase-4-6.mts +37 -103
- package/src/client/dev-tools/phase-4-7.mts +44 -228
- package/src/client/dev-tools/phase-4-8.mts +33 -136
- package/src/client/dev-tools/phase-4-9.mts +33 -137
- package/src/client/dev-tools/phase-4.mts +30 -6
- package/src/client/dev-tools.mts +18 -0
- package/src/client/index.html +35 -14
- package/src/client/style.css +29 -5
- package/src/client/types.mts +4 -1
- package/src/client/ui/shell/space-gib-shell-service.mts +4 -0
- package/src/server/path-constants.mts +12 -0
- package/src/server/serve-gib/handlers/api/keystone/sso-config.handler.mts +66 -0
- package/src/server/serve-gib/handlers/api/keystone/sso-link.handler.mts +119 -0
- package/src/server/serve-gib/handlers/api/keystone/sso-login.handler.mts +189 -0
- package/src/server/server.mts +6 -0
- package/dist/client/chunk-ANGVYAEK.mjs +0 -42
- package/dist/client/chunk-ANGVYAEK.mjs.map +0 -7
- package/dist/client/chunk-IRGFDQRD.mjs +0 -1920
- package/dist/client/chunk-IRGFDQRD.mjs.map +0 -7
- package/dist/respec-gib.node.mjs +0 -5
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { extractErrorMsg, getTimestamp, getUUID, } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
1
|
+
import { extractErrorMsg, getTimestamp, getUUID, hash } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
2
2
|
import { Factory_V1 as factory } from '@ibgib/ts-gib/dist/V1/factory.mjs';
|
|
3
3
|
import { ROOT } from '@ibgib/ts-gib/dist/V1/constants.mjs';
|
|
4
4
|
import { getIbGibAddr, } from '@ibgib/ts-gib/dist/helper.mjs';
|
|
@@ -10,6 +10,7 @@ import { SyncSagaCoordinator } from '@ibgib/core-gib/dist/sync/sync-saga-coordin
|
|
|
10
10
|
import { getGlobalMetaspace_waitIfNeeded } from "@ibgib/web-gib/dist/helpers.mjs";
|
|
11
11
|
import { SESSION_KEYSTONE_POLICY, getSpaceGibPoolConfig } from "../../common/keystone-policies.mjs";
|
|
12
12
|
import { SpaceGibApiBridge } from '../api/space-gib-api-bridge.mjs';
|
|
13
|
+
import { KEYSTONE_VERB_SYNC } from '@ibgib/core-gib/dist/keystone/keystone-constants.mjs';
|
|
13
14
|
import { SyncConflictStrategy } from '@ibgib/core-gib/dist/sync/sync-constants.mjs';
|
|
14
15
|
import { GLOBAL_LOG_A_LOT } from '../constants.mjs';
|
|
15
16
|
|
|
@@ -57,6 +58,99 @@ export interface PhaseSetupOptions {
|
|
|
57
58
|
data: any;
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
export async function createAndRegisterSyncDelegate({
|
|
62
|
+
domainI,
|
|
63
|
+
masterSecret,
|
|
64
|
+
syncSalt,
|
|
65
|
+
metaspace,
|
|
66
|
+
space,
|
|
67
|
+
apiBridge
|
|
68
|
+
}: {
|
|
69
|
+
domainI: KeystoneIbGib_V1;
|
|
70
|
+
masterSecret: string;
|
|
71
|
+
syncSalt: string;
|
|
72
|
+
metaspace: any;
|
|
73
|
+
space: any;
|
|
74
|
+
apiBridge: SpaceGibApiBridge;
|
|
75
|
+
}): Promise<{ evolvedDomainI: KeystoneIbGib_V1; delegateKeystone: KeystoneIbGib_V1; delegateSecret: string }> {
|
|
76
|
+
const keystoneService = new KeystoneService_V1();
|
|
77
|
+
|
|
78
|
+
// 1. Derive delegate secret
|
|
79
|
+
const delegateSecret = await hash({ s: `${masterSecret}-sync-delegate` });
|
|
80
|
+
|
|
81
|
+
// 2. Genesis the delegate keystone
|
|
82
|
+
const delegateKeystone = await keystoneService.genesis({
|
|
83
|
+
masterSecret: delegateSecret,
|
|
84
|
+
configs: [
|
|
85
|
+
getSpaceGibPoolConfig('sync', `${syncSalt}-delegate`),
|
|
86
|
+
],
|
|
87
|
+
metaspace,
|
|
88
|
+
space,
|
|
89
|
+
frameDetails: { client: 'space-gib-web-dev-delegate', timestamp: getTimestamp() }
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// 3. Register delegate on parent Domain identity
|
|
93
|
+
const evolvedDomainI = await keystoneService.registerDelegate({
|
|
94
|
+
parentKeystone: domainI,
|
|
95
|
+
delegateKeystone,
|
|
96
|
+
masterSecret,
|
|
97
|
+
metaspace,
|
|
98
|
+
space,
|
|
99
|
+
allowedVerbs: [KEYSTONE_VERB_SYNC]
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const domainAddr = getIbGibAddr({ ibGib: domainI });
|
|
103
|
+
|
|
104
|
+
// 4. Sync evolved parent and delegate to server
|
|
105
|
+
const resEvolve = await apiBridge.putEvolveKeystone(
|
|
106
|
+
domainAddr,
|
|
107
|
+
evolvedDomainI,
|
|
108
|
+
[delegateKeystone]
|
|
109
|
+
);
|
|
110
|
+
if (!resEvolve.success) {
|
|
111
|
+
throw new Error(`Server rejected delegate evolution: ${resEvolve.message}`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return { evolvedDomainI, delegateKeystone, delegateSecret };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export async function getSenderIdentityInfo({
|
|
118
|
+
domainI,
|
|
119
|
+
masterSecret,
|
|
120
|
+
metaspace,
|
|
121
|
+
space
|
|
122
|
+
}: {
|
|
123
|
+
domainI: KeystoneIbGib_V1;
|
|
124
|
+
masterSecret: string;
|
|
125
|
+
metaspace: any;
|
|
126
|
+
space: any;
|
|
127
|
+
}): Promise<{ senderIdentity: KeystoneIbGib_V1; fnSenderSecret: () => Promise<string> }> {
|
|
128
|
+
let senderIdentity = domainI;
|
|
129
|
+
let fnSenderSecret = async () => masterSecret;
|
|
130
|
+
|
|
131
|
+
// Find the delegate that is authorized for sync (not just [0] — there may be others)
|
|
132
|
+
const syncDelegateEntry = Object.values(domainI.data?.delegates ?? {}).find(
|
|
133
|
+
d => d.allowedVerbs?.includes(KEYSTONE_VERB_SYNC)
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
if (syncDelegateEntry) {
|
|
137
|
+
const delegateTjpAddr = syncDelegateEntry.delegateTjpAddr;
|
|
138
|
+
if (delegateTjpAddr) {
|
|
139
|
+
// Always resolve the LATEST evolved delegate tip, not the genesis frame
|
|
140
|
+
const latestDelegateAddr = await metaspace.getLatestAddr({ addr: delegateTjpAddr, space });
|
|
141
|
+
if (latestDelegateAddr) {
|
|
142
|
+
const resDel = await metaspace.get({ addr: latestDelegateAddr, space });
|
|
143
|
+
if (resDel.success && resDel.ibGibs && resDel.ibGibs.length > 0) {
|
|
144
|
+
senderIdentity = resDel.ibGibs[0] as KeystoneIbGib_V1;
|
|
145
|
+
const delegateSecret = await hash({ s: `${masterSecret}-sync-delegate` });
|
|
146
|
+
fnSenderSecret = async () => delegateSecret;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return { senderIdentity, fnSenderSecret };
|
|
152
|
+
}
|
|
153
|
+
|
|
60
154
|
export async function performPhaseSetup(opts: PhaseSetupOptions): Promise<void> {
|
|
61
155
|
const lc_fn = `${lc}[performPhaseSetup(${opts.phaseText})]`;
|
|
62
156
|
const btn = document.getElementById(opts.btnId) as HTMLButtonElement | null;
|
|
@@ -72,11 +166,11 @@ export async function performPhaseSetup(opts: PhaseSetupOptions): Promise<void>
|
|
|
72
166
|
|
|
73
167
|
const keystoneService = new KeystoneService_V1();
|
|
74
168
|
|
|
75
|
-
// 1. Create Genesis Domain Keystone (I^Itjp) in local space
|
|
169
|
+
// 1. Create Genesis Domain Keystone (I^Itjp) in local space.
|
|
170
|
+
// The domain identity only needs a 'manage' pool — the delegate gets 'sync'.
|
|
76
171
|
const domainI = await keystoneService.genesis({
|
|
77
172
|
masterSecret: opts.masterSecret,
|
|
78
173
|
configs: [
|
|
79
|
-
getSpaceGibPoolConfig('sync', opts.syncSalt),
|
|
80
174
|
getSpaceGibPoolConfig('manage', opts.manageSalt),
|
|
81
175
|
],
|
|
82
176
|
metaspace,
|
|
@@ -84,9 +178,6 @@ export async function performPhaseSetup(opts: PhaseSetupOptions): Promise<void>
|
|
|
84
178
|
frameDetails: { client: 'space-gib-web-dev', timestamp: getTimestamp() }
|
|
85
179
|
});
|
|
86
180
|
|
|
87
|
-
debugState.domainI = domainI;
|
|
88
|
-
debugState.domainIMasterSecret = opts.masterSecret;
|
|
89
|
-
|
|
90
181
|
devLog(`${opts.phaseText} Setup: ✓ Domain Keystone (I) created locally: ${getIbGibAddr({ ibGib: domainI })}`);
|
|
91
182
|
devLog(`${opts.phaseText} Setup: Starting postGenesisKeystone...`);
|
|
92
183
|
|
|
@@ -100,6 +191,22 @@ export async function performPhaseSetup(opts: PhaseSetupOptions): Promise<void>
|
|
|
100
191
|
throw new Error(`${opts.phaseText} Setup: Server rejected genesis domain keystone: ${resGenesis.message}`);
|
|
101
192
|
}
|
|
102
193
|
|
|
194
|
+
// 2.5 Generate and register delegate
|
|
195
|
+
devLog(`${opts.phaseText} Setup: Generating and registering sync delegate...`);
|
|
196
|
+
const { evolvedDomainI, delegateKeystone } = await createAndRegisterSyncDelegate({
|
|
197
|
+
domainI,
|
|
198
|
+
masterSecret: opts.masterSecret,
|
|
199
|
+
syncSalt: opts.syncSalt,
|
|
200
|
+
metaspace,
|
|
201
|
+
space,
|
|
202
|
+
apiBridge
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
debugState.domainI = evolvedDomainI;
|
|
206
|
+
debugState.domainIMasterSecret = opts.masterSecret;
|
|
207
|
+
|
|
208
|
+
devLog(`${opts.phaseText} Setup: ✓ Registered Sync Delegate: ${getIbGibAddr({ ibGib: delegateKeystone })}`);
|
|
209
|
+
|
|
103
210
|
// 3. Create Test IbGib (X) locally
|
|
104
211
|
const resX = await factory.firstGen({
|
|
105
212
|
parentIbGib: ROOT,
|
|
@@ -173,11 +280,18 @@ export async function performPhaseSync(opts: PhaseSyncOptions): Promise<void> {
|
|
|
173
280
|
debugState.sagaId = sagaId;
|
|
174
281
|
debugState.senderPeer = senderPeer;
|
|
175
282
|
|
|
283
|
+
const { senderIdentity, fnSenderSecret } = await getSenderIdentityInfo({
|
|
284
|
+
domainI,
|
|
285
|
+
masterSecret: debugState.domainIMasterSecret!,
|
|
286
|
+
metaspace,
|
|
287
|
+
space
|
|
288
|
+
});
|
|
289
|
+
|
|
176
290
|
await senderPeer.initializeOpts({
|
|
177
291
|
localMetaspace: metaspace,
|
|
178
292
|
localSpace: space,
|
|
179
|
-
senderIdentity
|
|
180
|
-
fnSenderSecret
|
|
293
|
+
senderIdentity,
|
|
294
|
+
fnSenderSecret,
|
|
181
295
|
sagaId,
|
|
182
296
|
sessionConnectPoolConfig: SESSION_KEYSTONE_POLICY.CONNECT_POOL as any,
|
|
183
297
|
sessionSyncPoolConfig: SESSION_KEYSTONE_POLICY.DEFAULT_POOL as any,
|
|
@@ -187,8 +301,11 @@ export async function performPhaseSync(opts: PhaseSyncOptions): Promise<void> {
|
|
|
187
301
|
try {
|
|
188
302
|
const syncSaga = await coordinator.sync({
|
|
189
303
|
domainIbGibs: [targetX],
|
|
190
|
-
|
|
191
|
-
|
|
304
|
+
senderIdentityInfo: {
|
|
305
|
+
senderIdentity,
|
|
306
|
+
senderDomainAddr: domainAddr,
|
|
307
|
+
},
|
|
308
|
+
fnSenderSecret,
|
|
192
309
|
peer: senderPeer,
|
|
193
310
|
localSpace: space,
|
|
194
311
|
metaspace,
|
|
@@ -215,3 +332,381 @@ export async function performPhaseSync(opts: PhaseSyncOptions): Promise<void> {
|
|
|
215
332
|
btn.disabled = false;
|
|
216
333
|
}
|
|
217
334
|
}
|
|
335
|
+
|
|
336
|
+
export async function getDelegateAndSessionInfo({
|
|
337
|
+
localI,
|
|
338
|
+
metaspace,
|
|
339
|
+
space
|
|
340
|
+
}: {
|
|
341
|
+
localI: KeystoneIbGib_V1;
|
|
342
|
+
metaspace: any;
|
|
343
|
+
space: any;
|
|
344
|
+
}): Promise<{
|
|
345
|
+
delegateTjpAddr?: string;
|
|
346
|
+
latestLocalDelegateAddr?: string;
|
|
347
|
+
localDelegate?: KeystoneIbGib_V1;
|
|
348
|
+
sessionIdentityTjpAddr?: string;
|
|
349
|
+
}> {
|
|
350
|
+
// Find the delegate that is specifically authorized for sync
|
|
351
|
+
const delegateInfo = Object.values(localI.data?.delegates ?? {}).find(
|
|
352
|
+
d => d.allowedVerbs?.includes(KEYSTONE_VERB_SYNC)
|
|
353
|
+
);
|
|
354
|
+
if (!delegateInfo) { return {}; }
|
|
355
|
+
const delegateTjpAddr = delegateInfo.delegateTjpAddr;
|
|
356
|
+
if (!delegateTjpAddr) { return {}; }
|
|
357
|
+
const latestLocalDelegateAddr = await metaspace.getLatestAddr({
|
|
358
|
+
addr: delegateTjpAddr,
|
|
359
|
+
space
|
|
360
|
+
});
|
|
361
|
+
if (!latestLocalDelegateAddr) { return { delegateTjpAddr }; }
|
|
362
|
+
const getDelRes = await metaspace.get({ addrs: [latestLocalDelegateAddr], space });
|
|
363
|
+
const localDelegate = getDelRes.ibGibs?.[0] as KeystoneIbGib_V1 | undefined;
|
|
364
|
+
if (!localDelegate) { return { delegateTjpAddr, latestLocalDelegateAddr }; }
|
|
365
|
+
const syncProof = localDelegate.data?.proofs?.find(p => p.claim?.verb === 'sync');
|
|
366
|
+
const sessionIdentityTjpAddr = syncProof?.claim?.target;
|
|
367
|
+
return {
|
|
368
|
+
delegateTjpAddr,
|
|
369
|
+
latestLocalDelegateAddr,
|
|
370
|
+
localDelegate,
|
|
371
|
+
sessionIdentityTjpAddr
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Executes one sync pass using the delegate keystone as the sender identity.
|
|
377
|
+
* Always resolves the current delegate tip from the domain identity stored in
|
|
378
|
+
* debugState, so it is safe to call in sequence across multiple passes.
|
|
379
|
+
*
|
|
380
|
+
* @param domainIbGibs - The ibgibs to sync in this pass.
|
|
381
|
+
* @param passLabel - Label used in devLog messages (e.g. "Pass 1 (Sync C1)").
|
|
382
|
+
*/
|
|
383
|
+
export async function runSyncPass({
|
|
384
|
+
domainIbGibs,
|
|
385
|
+
passLabel,
|
|
386
|
+
metaspace,
|
|
387
|
+
space,
|
|
388
|
+
}: {
|
|
389
|
+
domainIbGibs: any[];
|
|
390
|
+
passLabel: string;
|
|
391
|
+
metaspace: any;
|
|
392
|
+
space: any;
|
|
393
|
+
}): Promise<void> {
|
|
394
|
+
const domainI = debugState.domainI;
|
|
395
|
+
const masterSecret = debugState.domainIMasterSecret;
|
|
396
|
+
if (!domainI || !masterSecret) {
|
|
397
|
+
throw new Error(`runSyncPass[${passLabel}]: Missing domain identity or secret in debugState. Run Setup first.`);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const domainAddr = getIbGibAddr({ ibGib: domainI });
|
|
401
|
+
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
402
|
+
|
|
403
|
+
const { senderIdentity, fnSenderSecret } = await getSenderIdentityInfo({
|
|
404
|
+
domainI,
|
|
405
|
+
masterSecret,
|
|
406
|
+
metaspace,
|
|
407
|
+
space,
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
devLog(`Sync: ${passLabel} — using sender: ${getIbGibAddr({ ibGib: senderIdentity }).slice(0, 40)}...`);
|
|
411
|
+
|
|
412
|
+
const senderPeer = new SyncPeerWebSocketSender_V1({
|
|
413
|
+
classname: 'SyncPeerWebSocketSender_V1',
|
|
414
|
+
httpEvolveUrl: `${location.protocol}//${location.host}/api/keystone/evolve/${encodeURIComponent(domainAddr)}`,
|
|
415
|
+
wsUrl: `${protocol}//${location.host}/api/sync/ws/${encodeURIComponent(domainAddr)}`
|
|
416
|
+
});
|
|
417
|
+
const coordinator = new SyncSagaCoordinator();
|
|
418
|
+
const sagaId = await getUUID();
|
|
419
|
+
debugState.sagaId = sagaId;
|
|
420
|
+
debugState.senderPeer = senderPeer;
|
|
421
|
+
|
|
422
|
+
await senderPeer.initializeOpts({
|
|
423
|
+
localMetaspace: metaspace,
|
|
424
|
+
localSpace: space,
|
|
425
|
+
senderIdentity,
|
|
426
|
+
fnSenderSecret,
|
|
427
|
+
sagaId,
|
|
428
|
+
sessionConnectPoolConfig: SESSION_KEYSTONE_POLICY.CONNECT_POOL as any,
|
|
429
|
+
sessionSyncPoolConfig: SESSION_KEYSTONE_POLICY.DEFAULT_POOL as any,
|
|
430
|
+
targetAddrs: [domainAddr]
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
const syncSaga = await coordinator.sync({
|
|
434
|
+
domainIbGibs,
|
|
435
|
+
senderIdentityInfo: {
|
|
436
|
+
senderIdentity,
|
|
437
|
+
senderDomainAddr: domainAddr,
|
|
438
|
+
},
|
|
439
|
+
fnSenderSecret,
|
|
440
|
+
peer: senderPeer,
|
|
441
|
+
localSpace: space,
|
|
442
|
+
metaspace,
|
|
443
|
+
conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
|
|
444
|
+
});
|
|
445
|
+
await syncSaga.done;
|
|
446
|
+
|
|
447
|
+
// After each pass the domain identity may have evolved — refresh debugState
|
|
448
|
+
const latestDomainAddr = await metaspace.getLatestAddr({ addr: domainAddr, space });
|
|
449
|
+
if (latestDomainAddr && latestDomainAddr !== getIbGibAddr({ ibGib: domainI })) {
|
|
450
|
+
const res = await metaspace.get({ addrs: [latestDomainAddr], space });
|
|
451
|
+
if (res.ibGibs?.[0]) { debugState.domainI = res.ibGibs[0] as KeystoneIbGib_V1; }
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Like `runSyncPass` but accepts an explicit space, domainI, and masterSecret.
|
|
457
|
+
* Use this when syncing from a secondary (e.g., "remote") space that is NOT
|
|
458
|
+
* the current default local user space.
|
|
459
|
+
*
|
|
460
|
+
* After the sync, copies the evolved domain identity tip back to `primarySpace`
|
|
461
|
+
* (if provided) and updates debugState.domainI.
|
|
462
|
+
*/
|
|
463
|
+
export async function runSyncPassFromSpace({
|
|
464
|
+
domainIbGibs,
|
|
465
|
+
passLabel,
|
|
466
|
+
metaspace,
|
|
467
|
+
space,
|
|
468
|
+
primarySpace,
|
|
469
|
+
domainI,
|
|
470
|
+
masterSecret,
|
|
471
|
+
}: {
|
|
472
|
+
domainIbGibs: any[];
|
|
473
|
+
passLabel: string;
|
|
474
|
+
metaspace: any;
|
|
475
|
+
space: any;
|
|
476
|
+
/** If provided, the evolved domain identity is copied back here after sync. */
|
|
477
|
+
primarySpace?: any;
|
|
478
|
+
domainI: KeystoneIbGib_V1;
|
|
479
|
+
masterSecret: string;
|
|
480
|
+
}): Promise<void> {
|
|
481
|
+
const domainAddr = getIbGibAddr({ ibGib: domainI });
|
|
482
|
+
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
483
|
+
|
|
484
|
+
const { senderIdentity, fnSenderSecret } = await getSenderIdentityInfo({
|
|
485
|
+
domainI,
|
|
486
|
+
masterSecret,
|
|
487
|
+
metaspace,
|
|
488
|
+
space,
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
devLog(`Sync: ${passLabel} — using sender: ${getIbGibAddr({ ibGib: senderIdentity }).slice(0, 40)}...`);
|
|
492
|
+
|
|
493
|
+
const senderPeer = new SyncPeerWebSocketSender_V1({
|
|
494
|
+
classname: 'SyncPeerWebSocketSender_V1',
|
|
495
|
+
httpEvolveUrl: `${location.protocol}//${location.host}/api/keystone/evolve/${encodeURIComponent(domainAddr)}`,
|
|
496
|
+
wsUrl: `${protocol}//${location.host}/api/sync/ws/${encodeURIComponent(domainAddr)}`
|
|
497
|
+
});
|
|
498
|
+
const coordinator = new SyncSagaCoordinator();
|
|
499
|
+
const sagaId = await getUUID();
|
|
500
|
+
debugState.sagaId = sagaId;
|
|
501
|
+
debugState.senderPeer = senderPeer;
|
|
502
|
+
|
|
503
|
+
await senderPeer.initializeOpts({
|
|
504
|
+
localMetaspace: metaspace,
|
|
505
|
+
localSpace: space,
|
|
506
|
+
senderIdentity,
|
|
507
|
+
fnSenderSecret,
|
|
508
|
+
sagaId,
|
|
509
|
+
sessionConnectPoolConfig: SESSION_KEYSTONE_POLICY.CONNECT_POOL as any,
|
|
510
|
+
sessionSyncPoolConfig: SESSION_KEYSTONE_POLICY.DEFAULT_POOL as any,
|
|
511
|
+
targetAddrs: [domainAddr]
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
const syncSaga = await coordinator.sync({
|
|
515
|
+
domainIbGibs,
|
|
516
|
+
senderIdentityInfo: {
|
|
517
|
+
senderIdentity,
|
|
518
|
+
senderDomainAddr: domainAddr,
|
|
519
|
+
},
|
|
520
|
+
fnSenderSecret,
|
|
521
|
+
peer: senderPeer,
|
|
522
|
+
localSpace: space,
|
|
523
|
+
metaspace,
|
|
524
|
+
conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
|
|
525
|
+
});
|
|
526
|
+
await syncSaga.done;
|
|
527
|
+
|
|
528
|
+
// After sync, refresh evolved domain identity
|
|
529
|
+
const latestDomainAddr = await metaspace.getLatestAddr({ addr: domainAddr, space });
|
|
530
|
+
if (latestDomainAddr) {
|
|
531
|
+
const res = await metaspace.get({ addrs: [latestDomainAddr], space });
|
|
532
|
+
const evolved = res.ibGibs?.[0] as KeystoneIbGib_V1 | undefined;
|
|
533
|
+
if (evolved) {
|
|
534
|
+
debugState.domainI = evolved;
|
|
535
|
+
// If a primary space was provided, copy the evolved domain and delegate identities back there
|
|
536
|
+
if (primarySpace) {
|
|
537
|
+
await copyIdentitiesToSpace({
|
|
538
|
+
domainI: evolved,
|
|
539
|
+
metaspace,
|
|
540
|
+
fromSpace: space,
|
|
541
|
+
toSpace: primarySpace
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
export async function setupDomainAndDelegateIdentities({
|
|
549
|
+
masterSecret,
|
|
550
|
+
syncSalt,
|
|
551
|
+
manageSalt,
|
|
552
|
+
metaspace,
|
|
553
|
+
space,
|
|
554
|
+
apiBridge,
|
|
555
|
+
phaseText
|
|
556
|
+
}: {
|
|
557
|
+
masterSecret: string;
|
|
558
|
+
syncSalt: string;
|
|
559
|
+
manageSalt: string;
|
|
560
|
+
metaspace: any;
|
|
561
|
+
space: any;
|
|
562
|
+
apiBridge: SpaceGibApiBridge;
|
|
563
|
+
phaseText: string;
|
|
564
|
+
}): Promise<{ domainI: KeystoneIbGib_V1; delegateKeystone: KeystoneIbGib_V1 }> {
|
|
565
|
+
const keystoneService = new KeystoneService_V1();
|
|
566
|
+
|
|
567
|
+
// 1. Create Genesis Domain Keystone (I^Itjp) in local space.
|
|
568
|
+
// The domain identity only needs a 'manage' pool — the delegate gets 'sync'.
|
|
569
|
+
const domainI = await keystoneService.genesis({
|
|
570
|
+
masterSecret,
|
|
571
|
+
configs: [
|
|
572
|
+
getSpaceGibPoolConfig('manage', manageSalt),
|
|
573
|
+
],
|
|
574
|
+
metaspace,
|
|
575
|
+
space,
|
|
576
|
+
frameDetails: { client: 'space-gib-web-dev', timestamp: getTimestamp() }
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
devLog(`${phaseText} Setup: ✓ Domain Keystone (I) created locally: ${getIbGibAddr({ ibGib: domainI })}`);
|
|
580
|
+
devLog(`${phaseText} Setup: Starting postGenesisKeystone...`);
|
|
581
|
+
|
|
582
|
+
// 2. Post Genesis Domain Keystone to receiver/server
|
|
583
|
+
const resGenesis = await apiBridge.postGenesisKeystone(domainI);
|
|
584
|
+
if (resGenesis.success) {
|
|
585
|
+
devLog(`${phaseText} Setup: ✓ Domain Keystone registered and stored on receiver (server).`);
|
|
586
|
+
} else {
|
|
587
|
+
devLog(`${phaseText} Setup: X postGenesisKeystone failed: ${resGenesis.message}.`);
|
|
588
|
+
throw new Error(`${phaseText} Setup: Server rejected genesis domain keystone: ${resGenesis.message}`);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// 3. Generate and register delegate
|
|
592
|
+
devLog(`${phaseText} Setup: Generating and registering sync delegate...`);
|
|
593
|
+
const { evolvedDomainI, delegateKeystone } = await createAndRegisterSyncDelegate({
|
|
594
|
+
domainI,
|
|
595
|
+
masterSecret,
|
|
596
|
+
syncSalt,
|
|
597
|
+
metaspace,
|
|
598
|
+
space,
|
|
599
|
+
apiBridge
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
debugState.domainI = evolvedDomainI;
|
|
603
|
+
debugState.domainIMasterSecret = masterSecret;
|
|
604
|
+
|
|
605
|
+
return { domainI: evolvedDomainI, delegateKeystone };
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
export async function verifyIdentitiesOnServer({
|
|
609
|
+
localI,
|
|
610
|
+
metaspace,
|
|
611
|
+
space,
|
|
612
|
+
apiBridge,
|
|
613
|
+
domainAddr
|
|
614
|
+
}: {
|
|
615
|
+
localI: KeystoneIbGib_V1;
|
|
616
|
+
metaspace: any;
|
|
617
|
+
space: any;
|
|
618
|
+
apiBridge: SpaceGibApiBridge;
|
|
619
|
+
domainAddr: string;
|
|
620
|
+
}): Promise<{
|
|
621
|
+
latestLocalIAddr: string;
|
|
622
|
+
latestLocalDelegateAddr: string;
|
|
623
|
+
sessionIdentityTjpAddr: string;
|
|
624
|
+
}> {
|
|
625
|
+
const latestLocalIAddr = await metaspace.getLatestAddr({
|
|
626
|
+
addr: domainAddr,
|
|
627
|
+
space
|
|
628
|
+
});
|
|
629
|
+
if (!latestLocalIAddr) {
|
|
630
|
+
throw new Error('Evolved domain keystone tip NOT found in local space!');
|
|
631
|
+
}
|
|
632
|
+
devLog(`✓ Check: Evolved Domain Keystone exists locally.`);
|
|
633
|
+
|
|
634
|
+
const {
|
|
635
|
+
latestLocalDelegateAddr,
|
|
636
|
+
sessionIdentityTjpAddr
|
|
637
|
+
} = await getDelegateAndSessionInfo({ localI, metaspace, space });
|
|
638
|
+
|
|
639
|
+
if (!latestLocalDelegateAddr) {
|
|
640
|
+
throw new Error('Evolved delegate keystone tip NOT found in local space!');
|
|
641
|
+
}
|
|
642
|
+
if (!sessionIdentityTjpAddr) {
|
|
643
|
+
throw new Error('Delegate sync claim does not target a session keystone.');
|
|
644
|
+
}
|
|
645
|
+
devLog(`✓ Check: Delegate Keystone and Sync Claim to Session verified locally.`);
|
|
646
|
+
|
|
647
|
+
const serverDelGetRes = await apiBridge.getIbGib(domainAddr, latestLocalDelegateAddr);
|
|
648
|
+
if (!serverDelGetRes.success || !serverDelGetRes.ibGib) {
|
|
649
|
+
throw new Error(`Evolved Delegate Keystone NOT found on server!`);
|
|
650
|
+
}
|
|
651
|
+
devLog(`✓ Check: Evolved Delegate Keystone exists on server.`);
|
|
652
|
+
|
|
653
|
+
const serverIGetRes = await apiBridge.getIbGib(domainAddr, latestLocalIAddr);
|
|
654
|
+
if (!serverIGetRes.success || !serverIGetRes.ibGib) {
|
|
655
|
+
throw new Error(`Evolved Domain Keystone NOT found on server!`);
|
|
656
|
+
}
|
|
657
|
+
devLog(`✓ Check: Evolved Domain Keystone exists on server.`);
|
|
658
|
+
|
|
659
|
+
return {
|
|
660
|
+
latestLocalIAddr,
|
|
661
|
+
latestLocalDelegateAddr,
|
|
662
|
+
sessionIdentityTjpAddr
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
export async function copyIdentitiesToSpace({
|
|
667
|
+
domainI,
|
|
668
|
+
metaspace,
|
|
669
|
+
fromSpace,
|
|
670
|
+
toSpace
|
|
671
|
+
}: {
|
|
672
|
+
domainI: KeystoneIbGib_V1;
|
|
673
|
+
metaspace: any;
|
|
674
|
+
fromSpace: any;
|
|
675
|
+
toSpace: any;
|
|
676
|
+
}): Promise<void> {
|
|
677
|
+
const domainAddr = getIbGibAddr({ ibGib: domainI });
|
|
678
|
+
|
|
679
|
+
// 1. Get latest Domain I and its graph, put and register
|
|
680
|
+
const latestDomainAddr = await metaspace.getLatestAddr({ addr: domainAddr, space: fromSpace });
|
|
681
|
+
if (!latestDomainAddr) { throw new Error("Could not find latest domain I address."); }
|
|
682
|
+
|
|
683
|
+
const resDomain = await metaspace.get({ addrs: [latestDomainAddr], space: fromSpace });
|
|
684
|
+
const latestDomainI = resDomain.ibGibs?.[0] as KeystoneIbGib_V1 | undefined;
|
|
685
|
+
if (!latestDomainI) { throw new Error("Could not get latest domain I."); }
|
|
686
|
+
|
|
687
|
+
const graphI = await metaspace.getDependencyGraph({ ibGibAddr: latestDomainAddr, space: fromSpace });
|
|
688
|
+
await metaspace.put({ ibGibs: Object.values(graphI), space: toSpace });
|
|
689
|
+
await metaspace.registerNewIbGib({ ibGib: latestDomainI, space: toSpace });
|
|
690
|
+
|
|
691
|
+
// 2. Find and copy delegate(s)
|
|
692
|
+
const syncDelegateEntry = Object.values(latestDomainI.data?.delegates ?? {}).find(
|
|
693
|
+
d => d.allowedVerbs?.includes(KEYSTONE_VERB_SYNC)
|
|
694
|
+
);
|
|
695
|
+
|
|
696
|
+
if (syncDelegateEntry) {
|
|
697
|
+
const delegateTjpAddr = syncDelegateEntry.delegateTjpAddr;
|
|
698
|
+
if (delegateTjpAddr) {
|
|
699
|
+
const latestDelegateAddr = await metaspace.getLatestAddr({ addr: delegateTjpAddr, space: fromSpace });
|
|
700
|
+
if (latestDelegateAddr) {
|
|
701
|
+
const resDel = await metaspace.get({ addrs: [latestDelegateAddr], space: fromSpace });
|
|
702
|
+
const latestDelegate = resDel.ibGibs?.[0] as KeystoneIbGib_V1 | undefined;
|
|
703
|
+
if (latestDelegate) {
|
|
704
|
+
const graphDel = await metaspace.getDependencyGraph({ ibGibAddr: latestDelegateAddr, space: fromSpace });
|
|
705
|
+
await metaspace.put({ ibGibs: Object.values(graphDel), space: toSpace });
|
|
706
|
+
await metaspace.registerNewIbGib({ ibGib: latestDelegate, space: toSpace });
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
@@ -13,7 +13,7 @@ import { SyncConflictStrategy } from '@ibgib/core-gib/dist/sync/sync-constants.m
|
|
|
13
13
|
import { SESSION_KEYSTONE_POLICY, getSpaceGibPoolConfig } from "../../common/keystone-policies.mjs";
|
|
14
14
|
import { SpaceGibApiBridge } from '../api/space-gib-api-bridge.mjs';
|
|
15
15
|
|
|
16
|
-
import { debugState, devLog, lc, performPhaseSetup, performPhaseSync } from './common.mjs';
|
|
16
|
+
import { debugState, devLog, lc, performPhaseSetup, performPhaseSync, getDelegateAndSessionInfo } from './common.mjs';
|
|
17
17
|
|
|
18
18
|
export function init4_1bSetupButton(): void {
|
|
19
19
|
const btn = document.getElementById('btn-4-1b-setup') as HTMLButtonElement | null;
|
|
@@ -120,12 +120,27 @@ export function init4_1bCheckButton(): void {
|
|
|
120
120
|
return;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
const
|
|
124
|
-
|
|
123
|
+
const {
|
|
124
|
+
latestLocalDelegateAddr,
|
|
125
|
+
sessionIdentityTjpAddr
|
|
126
|
+
} = await getDelegateAndSessionInfo({ localI, metaspace, space });
|
|
127
|
+
|
|
128
|
+
if (!latestLocalDelegateAddr) {
|
|
129
|
+
devLog('✗ Check: Evolved delegate keystone tip NOT found in local space!');
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
125
132
|
if (!sessionIdentityTjpAddr) {
|
|
126
|
-
devLog('✗ Check:
|
|
133
|
+
devLog('✗ Check: Delegate sync claim does not target a session keystone.');
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
devLog(`✓ Check: Delegate Keystone and Sync Claim to Session verified locally.`);
|
|
137
|
+
|
|
138
|
+
const serverDelGetRes = await apiBridge.getIbGib(domainAddr, latestLocalDelegateAddr);
|
|
139
|
+
if (!serverDelGetRes.success || !serverDelGetRes.ibGib) {
|
|
140
|
+
devLog(`✗ Check: Evolved Delegate Keystone NOT found on server!`);
|
|
127
141
|
return;
|
|
128
142
|
}
|
|
143
|
+
devLog(`✓ Check: Evolved Delegate Keystone exists on server.`);
|
|
129
144
|
|
|
130
145
|
const serverIGetRes = await apiBridge.getIbGib(domainAddr, latestLocalIAddr);
|
|
131
146
|
if (!serverIGetRes.success || !serverIGetRes.ibGib) {
|