@ibgib/space-gib 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/bootstrap.mjs +1 -1
- package/dist/client/chunk-2KJC5XKE.mjs +31 -0
- package/dist/client/{chunk-RE7XSMHH.mjs.map → chunk-2KJC5XKE.mjs.map} +4 -4
- package/dist/client/{chunk-RDTAT5G4.mjs → chunk-QNIXTRFO.mjs} +2 -2
- package/dist/client/index.html +7 -5
- package/dist/client/index.mjs +1 -1
- package/dist/client/script.mjs +1 -1
- package/dist/server/server.mjs +537 -107
- package/dist/server/server.mjs.map +4 -4
- package/package.json +1 -1
- package/src/client/AUTO-GENERATED-version.mts +1 -1
- package/src/client/api/space-gib-api-bridge.mts +35 -0
- package/src/client/dev-tools.mts +396 -295
- package/src/client/index.html +7 -5
- package/src/common/keystone-policies.mts +1 -1
- package/src/server/serve-gib/handlers/api/keystone/keystone-evolve.handler.mts +1 -1
- package/src/server/serve-gib/handlers/api/keystone/keystone-get.respec.mts +3 -3
- package/src/server/serve-gib/handlers/api/keystone/keystone-post.handler.mts +1 -1
- package/src/server/serve-gib/handlers/ws/sync-upgrade-handler-base.mts +7 -3
- package/dist/client/chunk-BL2SGXS4.mjs +0 -18994
- package/dist/client/chunk-RE7XSMHH.mjs +0 -31
- package/dist/client/chunk-YUSGN3J4.mjs +0 -23119
- /package/dist/client/{chunk-RDTAT5G4.mjs.map → chunk-QNIXTRFO.mjs.map} +0 -0
package/src/client/dev-tools.mts
CHANGED
|
@@ -19,16 +19,18 @@ import { KeystoneService_V1 } from '@ibgib/core-gib/dist/keystone/keystone-servi
|
|
|
19
19
|
import { KeystoneIbGib_V1, KeystoneReplenishStrategy } from '@ibgib/core-gib/dist/keystone/keystone-types.mjs';
|
|
20
20
|
import { createManagePoolConfig } from '@ibgib/core-gib/dist/keystone/keystone-config-builder.mjs';
|
|
21
21
|
import { KeystoneStrategyFactory } from '@ibgib/core-gib/dist/keystone/strategy/keystone-strategy-factory.mjs';
|
|
22
|
-
import { SyncPeerWebSocketSender_V1 } from '@ibgib/core-gib/dist/sync/sync-peer/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mjs';
|
|
22
|
+
import { SyncPeerWebSocketSender_V1 } from '@ibgib/core-gib/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mjs';
|
|
23
23
|
import { SyncSagaCoordinator } from '@ibgib/core-gib/dist/sync/sync-saga-coordinator.mjs';
|
|
24
24
|
import { KEYSTONE_VERB_CONNECT, POOL_ID_CONNECT, POOL_ID_SYNC } from '@ibgib/core-gib/dist/keystone/keystone-constants.mjs';
|
|
25
25
|
import { getGlobalMetaspace_waitIfNeeded } from "@ibgib/web-gib/dist/helpers.mjs";
|
|
26
|
+
import { graphsAreEquivalent } from '@ibgib/core-gib/dist/common/other/graph-helper.mjs';
|
|
26
27
|
|
|
27
28
|
import { GLOBAL_LOG_A_LOT } from './constants.mjs';
|
|
28
29
|
import {
|
|
29
30
|
SESSION_KEYSTONE_POLICY, getConnectChallenge, getSpaceGibPoolConfig
|
|
30
31
|
} from "../common/keystone-policies.mjs";
|
|
31
32
|
import { SpaceGibApiBridge } from './api/space-gib-api-bridge.mjs';
|
|
33
|
+
import { SyncConflictStrategy } from '@ibgib/core-gib/dist/sync/sync-constants.mjs';
|
|
32
34
|
|
|
33
35
|
const logalot = GLOBAL_LOG_A_LOT
|
|
34
36
|
const lc = '[dev-tools]';
|
|
@@ -120,7 +122,7 @@ function initWsTestButton(): void {
|
|
|
120
122
|
|
|
121
123
|
function initPrintStateButton(): void {
|
|
122
124
|
const btn = document.getElementById('btn-print-dev-state') as HTMLButtonElement | null;
|
|
123
|
-
if (!btn) return;
|
|
125
|
+
if (!btn) { return; }
|
|
124
126
|
btn.addEventListener('click', () => {
|
|
125
127
|
devLog(`Printing debug state to console...`);
|
|
126
128
|
console.dir(debugState);
|
|
@@ -134,7 +136,7 @@ function initPrintStateButton(): void {
|
|
|
134
136
|
function initCreateDomainKeystoneButton(): void {
|
|
135
137
|
const lc_fn = `${lc}[initCreateDomainKeystoneButton]`;
|
|
136
138
|
const btn = document.getElementById('btn-create-domain-keystone') as HTMLButtonElement | null;
|
|
137
|
-
if (!btn) return;
|
|
139
|
+
if (!btn) { return; }
|
|
138
140
|
|
|
139
141
|
btn.addEventListener('click', async () => {
|
|
140
142
|
try {
|
|
@@ -183,7 +185,7 @@ function initCreateDomainKeystoneButton(): void {
|
|
|
183
185
|
|
|
184
186
|
// Enable next step
|
|
185
187
|
const nextBtn = document.getElementById('btn-create-test-ibgib') as HTMLButtonElement;
|
|
186
|
-
if (nextBtn) nextBtn.disabled = false;
|
|
188
|
+
if (nextBtn) { nextBtn.disabled = false; }
|
|
187
189
|
|
|
188
190
|
} catch (error) {
|
|
189
191
|
devLog(`✗ ${extractErrorMsg(error)}`);
|
|
@@ -225,7 +227,7 @@ function initCreateTestIbGibButton(): void {
|
|
|
225
227
|
|
|
226
228
|
// Enable next step
|
|
227
229
|
const nextBtn = document.getElementById('btn-create-session-keystone') as HTMLButtonElement;
|
|
228
|
-
if (nextBtn) nextBtn.disabled = false;
|
|
230
|
+
if (nextBtn) { nextBtn.disabled = false; }
|
|
229
231
|
} catch (error) {
|
|
230
232
|
devLog(`✗ ${extractErrorMsg(error)}`);
|
|
231
233
|
console.error(`${lc_fn} ${extractErrorMsg(error)}`);
|
|
@@ -315,7 +317,7 @@ function initCreateSessionKeystoneButton(): void {
|
|
|
315
317
|
|
|
316
318
|
// Enable next step
|
|
317
319
|
const nextBtn = document.getElementById('btn-evolve-domain-keystone') as HTMLButtonElement;
|
|
318
|
-
if (nextBtn) nextBtn.disabled = false;
|
|
320
|
+
if (nextBtn) { nextBtn.disabled = false; }
|
|
319
321
|
} catch (error) {
|
|
320
322
|
devLog(`✗ ${extractErrorMsg(error)}`);
|
|
321
323
|
console.error(`${lc_fn} ${extractErrorMsg(error)}`);
|
|
@@ -389,7 +391,7 @@ function initEvolveDomainKeystoneButton(): void {
|
|
|
389
391
|
|
|
390
392
|
// Enable next step
|
|
391
393
|
const nextBtn = document.getElementById('btn-perform-sync') as HTMLButtonElement;
|
|
392
|
-
if (nextBtn) nextBtn.disabled = false;
|
|
394
|
+
if (nextBtn) { nextBtn.disabled = false; }
|
|
393
395
|
|
|
394
396
|
} catch (error) {
|
|
395
397
|
devLog(`✗ ${extractErrorMsg(error)}`);
|
|
@@ -406,7 +408,7 @@ function initEvolveDomainKeystoneButton(): void {
|
|
|
406
408
|
function initPerformSyncButton(): void {
|
|
407
409
|
const lc_fn = `${lc}[initPerformSyncButton]`;
|
|
408
410
|
const btn = document.getElementById('btn-perform-sync') as HTMLButtonElement | null;
|
|
409
|
-
if (!btn) return;
|
|
411
|
+
if (!btn) { return; }
|
|
410
412
|
|
|
411
413
|
btn.addEventListener('click', async () => {
|
|
412
414
|
try {
|
|
@@ -527,161 +529,212 @@ function initPerformSyncButton(): void {
|
|
|
527
529
|
// Phase 1B: Standardized Setup / Sync / Check testing loop
|
|
528
530
|
// ---------------------------------------------------------------------------
|
|
529
531
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
532
|
+
interface PhaseSetupOptions {
|
|
533
|
+
phaseText: '1B' | '2B' | '3B';
|
|
534
|
+
btnId: string;
|
|
535
|
+
nextBtnId: string;
|
|
536
|
+
masterSecret: string;
|
|
537
|
+
syncSalt: string;
|
|
538
|
+
manageSalt: string;
|
|
539
|
+
ib: string;
|
|
540
|
+
data: any;
|
|
541
|
+
}
|
|
534
542
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
543
|
+
async function performPhaseSetup(opts: PhaseSetupOptions): Promise<void> {
|
|
544
|
+
const lc_fn = `${lc}[performPhaseSetup(${opts.phaseText})]`;
|
|
545
|
+
const btn = document.getElementById(opts.btnId) as HTMLButtonElement | null;
|
|
546
|
+
if (!btn) { return; }
|
|
539
547
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
548
|
+
try {
|
|
549
|
+
btn.disabled = true;
|
|
550
|
+
devLog(`${opts.phaseText} Setup: Generating Alice's long-lived Domain Keystone (I) and Target (X)...`);
|
|
551
|
+
|
|
552
|
+
const metaspace = await getGlobalMetaspace_waitIfNeeded();
|
|
553
|
+
const space = await metaspace.getLocalUserSpace({});
|
|
554
|
+
if (!space) { throw new Error("No default space found in metaspace."); }
|
|
555
|
+
|
|
556
|
+
const keystoneService = new KeystoneService_V1();
|
|
557
|
+
|
|
558
|
+
// 1. Create Genesis Domain Keystone (I^Itjp) in local space
|
|
559
|
+
const domainI = await keystoneService.genesis({
|
|
560
|
+
masterSecret: opts.masterSecret,
|
|
561
|
+
configs: [
|
|
562
|
+
getSpaceGibPoolConfig('sync', opts.syncSalt),
|
|
563
|
+
getSpaceGibPoolConfig('manage', opts.manageSalt),
|
|
564
|
+
],
|
|
565
|
+
metaspace,
|
|
566
|
+
space,
|
|
567
|
+
frameDetails: { client: 'space-gib-web-dev', timestamp: getTimestamp() }
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
debugState.domainI = domainI;
|
|
571
|
+
debugState.domainIMasterSecret = opts.masterSecret;
|
|
572
|
+
|
|
573
|
+
devLog(`${opts.phaseText} Setup: ✓ Domain Keystone (I) created locally: ${getIbGibAddr({ ibGib: domainI })}`);
|
|
574
|
+
devLog(`${opts.phaseText} Setup: Starting postGenesisKeystone...`);
|
|
575
|
+
|
|
576
|
+
// 2. Post Genesis Domain Keystone to receiver/server
|
|
577
|
+
const apiBridge = new SpaceGibApiBridge();
|
|
578
|
+
const resGenesis = await apiBridge.postGenesisKeystone(domainI);
|
|
579
|
+
if (resGenesis.success) {
|
|
580
|
+
devLog(`${opts.phaseText} Setup: ✓ Domain Keystone registered and stored on receiver (server).`);
|
|
581
|
+
} else {
|
|
582
|
+
devLog(`${opts.phaseText} Setup: X postGenesisKeystone failed: ${resGenesis.message}.`);
|
|
583
|
+
throw new Error(`${opts.phaseText} Setup: Server rejected genesis domain keystone: ${resGenesis.message}`);
|
|
584
|
+
}
|
|
543
585
|
|
|
544
|
-
|
|
545
|
-
|
|
586
|
+
// 3. Create Test IbGib (X) locally
|
|
587
|
+
const resX = await factory.firstGen({
|
|
588
|
+
parentIbGib: ROOT,
|
|
589
|
+
ib: opts.ib,
|
|
590
|
+
data: opts.data,
|
|
591
|
+
dna: true,
|
|
592
|
+
nCounter: true,
|
|
593
|
+
tjp: { uuid: true, timestamp: true }
|
|
594
|
+
});
|
|
595
|
+
const xIbGib = resX.newIbGib;
|
|
546
596
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
configs: [
|
|
551
|
-
getSpaceGibPoolConfig('sync', 'senderidentitysyncsaltphase1'),
|
|
552
|
-
getSpaceGibPoolConfig('manage', 'senderidentitymanagesaltphase1'),
|
|
553
|
-
],
|
|
554
|
-
metaspace,
|
|
555
|
-
space,
|
|
556
|
-
frameDetails: { client: 'space-gib-web-dev', timestamp: getTimestamp() }
|
|
557
|
-
});
|
|
597
|
+
// Persist target X to local space so coordinator can build the sync history
|
|
598
|
+
await metaspace.persistTransformResult({ resTransform: resX, space });
|
|
599
|
+
await metaspace.registerNewIbGib({ ibGib: xIbGib });
|
|
558
600
|
|
|
559
|
-
|
|
560
|
-
|
|
601
|
+
debugState.targetX = xIbGib;
|
|
602
|
+
devLog(`${opts.phaseText} Setup: ✓ Target (X) created and persisted locally: ${getIbGibAddr({ ibGib: xIbGib })}`);
|
|
561
603
|
|
|
562
|
-
|
|
563
|
-
|
|
604
|
+
devLog(`✓ ${opts.phaseText} Setup Complete! Ready for ${opts.phaseText} Sync.`);
|
|
605
|
+
btn.textContent = `✓ ${opts.phaseText} Setup Complete`;
|
|
564
606
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
if (resGenesis.success) {
|
|
569
|
-
devLog(`1B Setup: ✓ Domain Keystone registered and stored on receiver (server).`);
|
|
570
|
-
} else {
|
|
571
|
-
devLog(`1B Setup: X postGenesisKeystone failed: ${resGenesis.message}.`);
|
|
572
|
-
throw new Error(`1B Setup: Server rejected genesis domain keystone: ${resGenesis.message}`);
|
|
573
|
-
}
|
|
607
|
+
// Enable next button in the phase flow
|
|
608
|
+
const syncBtn = document.getElementById(opts.nextBtnId) as HTMLButtonElement | null;
|
|
609
|
+
if (syncBtn) { syncBtn.disabled = false; }
|
|
574
610
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
nCounter: true,
|
|
582
|
-
tjp: { uuid: true, timestamp: true }
|
|
583
|
-
});
|
|
584
|
-
debugState.targetX = resX.newIbGib;
|
|
585
|
-
devLog(`1B Setup: ✓ Target (X) created locally: ${getIbGibAddr({ ibGib: resX.newIbGib })}`);
|
|
611
|
+
} catch (error) {
|
|
612
|
+
devLog(`✗ ${opts.phaseText} Setup FAILED: ${extractErrorMsg(error)}`);
|
|
613
|
+
console.error(`${lc_fn} ${opts.phaseText} Setup error:`, error);
|
|
614
|
+
btn.disabled = false;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
586
617
|
|
|
587
|
-
|
|
588
|
-
|
|
618
|
+
interface PhaseSyncOptions {
|
|
619
|
+
phaseText: '1B' | '2B' | '3B';
|
|
620
|
+
btnId: string;
|
|
621
|
+
nextBtnId: string;
|
|
622
|
+
expectSyncFailure?: boolean;
|
|
623
|
+
failureMessageSuffix?: string;
|
|
624
|
+
}
|
|
589
625
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
626
|
+
async function performPhaseSync(opts: PhaseSyncOptions): Promise<void> {
|
|
627
|
+
const lc_fn = `${lc}[performPhaseSync(${opts.phaseText})]`;
|
|
628
|
+
const btn = document.getElementById(opts.btnId) as HTMLButtonElement | null;
|
|
629
|
+
if (!btn) { return; }
|
|
593
630
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
631
|
+
try {
|
|
632
|
+
btn.disabled = true;
|
|
633
|
+
devLog(`${opts.phaseText} Sync: Executing senderCoordinator.sync(...) using WebSocket Peer...`);
|
|
634
|
+
|
|
635
|
+
const domainI = debugState.domainI;
|
|
636
|
+
const targetX = debugState.targetX;
|
|
637
|
+
if (!domainI || !targetX) {
|
|
638
|
+
devLog(`⚠ ${opts.phaseText} Sync: Missing setup state. Please run Setup first.`);
|
|
597
639
|
btn.disabled = false;
|
|
640
|
+
return;
|
|
598
641
|
}
|
|
599
|
-
});
|
|
600
|
-
}
|
|
601
642
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
643
|
+
const domainAddr = getIbGibAddr({ ibGib: domainI });
|
|
644
|
+
const metaspace = await getGlobalMetaspace_waitIfNeeded();
|
|
645
|
+
const space = await metaspace.getLocalUserSpace({});
|
|
646
|
+
if (!space) { throw new Error("No default space."); }
|
|
647
|
+
|
|
648
|
+
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
649
|
+
const senderPeer = new SyncPeerWebSocketSender_V1({
|
|
650
|
+
classname: 'SyncPeerWebSocketSender_V1',
|
|
651
|
+
httpEvolveUrl: `${location.protocol}//${location.host}/api/keystone/evolve/${encodeURIComponent(domainAddr)}`,
|
|
652
|
+
wsUrl: `${protocol}//${location.host}/api/sync/ws/${encodeURIComponent(domainAddr)}`
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
const coordinator = new SyncSagaCoordinator();
|
|
656
|
+
const sagaId = await getUUID();
|
|
657
|
+
debugState.sagaId = sagaId;
|
|
658
|
+
debugState.senderPeer = senderPeer;
|
|
659
|
+
|
|
660
|
+
await senderPeer.initializeOpts({
|
|
661
|
+
localMetaspace: metaspace,
|
|
662
|
+
localSpace: space,
|
|
663
|
+
senderIdentity: domainI,
|
|
664
|
+
fnSenderSecret: async () => debugState.domainIMasterSecret!,
|
|
665
|
+
sagaId,
|
|
666
|
+
sessionConnectPoolConfig: SESSION_KEYSTONE_POLICY.CONNECT_POOL as any,
|
|
667
|
+
sessionSyncPoolConfig: SESSION_KEYSTONE_POLICY.DEFAULT_POOL as any,
|
|
668
|
+
targetAddrs: [domainAddr]
|
|
669
|
+
});
|
|
606
670
|
|
|
607
|
-
btn.addEventListener('click', async () => {
|
|
608
671
|
try {
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
const domainI = debugState.domainI;
|
|
613
|
-
const targetX = debugState.targetX;
|
|
614
|
-
if (!domainI || !targetX) {
|
|
615
|
-
devLog('⚠ 1B Sync: Missing setup state. Please run Setup first.');
|
|
616
|
-
btn.disabled = false;
|
|
617
|
-
return;
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
const domainAddr = getIbGibAddr({ ibGib: domainI });
|
|
621
|
-
const metaspace = await getGlobalMetaspace_waitIfNeeded();
|
|
622
|
-
const space = await metaspace.getLocalUserSpace({});
|
|
623
|
-
if (!space) { throw new Error("No default space."); }
|
|
624
|
-
|
|
625
|
-
// Instantiate WebSocket sender peer
|
|
626
|
-
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
627
|
-
const senderPeer = new SyncPeerWebSocketSender_V1({
|
|
628
|
-
classname: 'SyncPeerWebSocketSender_V1',
|
|
629
|
-
httpEvolveUrl: `${location.protocol}//${location.host}/api/keystone/evolve/${encodeURIComponent(domainAddr)}`,
|
|
630
|
-
wsUrl: `${protocol}//${location.host}/api/sync/ws/${encodeURIComponent(domainAddr)}`
|
|
631
|
-
});
|
|
632
|
-
|
|
633
|
-
const coordinator = new SyncSagaCoordinator();
|
|
634
|
-
const sagaId = await getUUID();
|
|
635
|
-
debugState.sagaId = sagaId;
|
|
636
|
-
debugState.senderPeer = senderPeer;
|
|
637
|
-
|
|
638
|
-
await senderPeer.initializeOpts({
|
|
639
|
-
localMetaspace: metaspace,
|
|
640
|
-
localSpace: space,
|
|
672
|
+
const syncSaga = await coordinator.sync({
|
|
673
|
+
domainIbGibs: [targetX],
|
|
641
674
|
senderIdentity: domainI,
|
|
642
675
|
fnSenderSecret: async () => debugState.domainIMasterSecret!,
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
676
|
+
peer: senderPeer,
|
|
677
|
+
localSpace: space,
|
|
678
|
+
metaspace,
|
|
679
|
+
conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
|
|
647
680
|
});
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
fnSenderSecret: async () => debugState.domainIMasterSecret!,
|
|
655
|
-
peer: senderPeer,
|
|
656
|
-
localSpace: space,
|
|
657
|
-
metaspace,
|
|
658
|
-
conflictStrategy: 'optimisticWithLCS' as any
|
|
659
|
-
});
|
|
660
|
-
await syncSaga.done;
|
|
661
|
-
} catch (err) {
|
|
662
|
-
// connection/sync error is fine/expected right now since connection is in Phase 2
|
|
663
|
-
devLog(`1B Sync: Coordinator sync executed (establish phase successfully run; connection/sync errors expected in 1B): ${extractErrorMsg(err)}`);
|
|
681
|
+
await syncSaga.done;
|
|
682
|
+
} catch (err) {
|
|
683
|
+
if (opts.expectSyncFailure) {
|
|
684
|
+
devLog(`${opts.phaseText} Sync: Coordinator sync executed (${opts.failureMessageSuffix ?? 'errors expected'}): ${extractErrorMsg(err)}`);
|
|
685
|
+
} else {
|
|
686
|
+
throw err;
|
|
664
687
|
}
|
|
688
|
+
}
|
|
665
689
|
|
|
666
|
-
|
|
667
|
-
|
|
690
|
+
devLog(`✓ ${opts.phaseText} Sync Execution Complete! Ready for State Checks.`);
|
|
691
|
+
btn.textContent = `✓ ${opts.phaseText} Sync Run`;
|
|
668
692
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
if (checkBtn) checkBtn.disabled = false;
|
|
693
|
+
const checkBtn = document.getElementById(opts.nextBtnId) as HTMLButtonElement | null;
|
|
694
|
+
if (checkBtn) { checkBtn.disabled = false; }
|
|
672
695
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
696
|
+
} catch (error) {
|
|
697
|
+
devLog(`✗ ${opts.phaseText} Sync FAILED: ${extractErrorMsg(error)}`);
|
|
698
|
+
console.error(`${lc_fn} ${opts.phaseText} Sync error:`, error);
|
|
699
|
+
btn.disabled = false;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
function init1bSetupButton(): void {
|
|
704
|
+
const btn = document.getElementById('btn-1b-setup') as HTMLButtonElement | null;
|
|
705
|
+
if (!btn) { return; }
|
|
706
|
+
btn.addEventListener('click', () => {
|
|
707
|
+
performPhaseSetup({
|
|
708
|
+
phaseText: '1B',
|
|
709
|
+
btnId: 'btn-1b-setup',
|
|
710
|
+
nextBtnId: 'btn-1b-sync',
|
|
711
|
+
masterSecret: 'test-sender-secret-phase1',
|
|
712
|
+
syncSalt: 'senderidentitysyncsaltphase1',
|
|
713
|
+
manageSalt: 'senderidentitymanagesaltphase1',
|
|
714
|
+
ib: 'test data',
|
|
715
|
+
data: { hello: 'world', random: Math.random() }
|
|
716
|
+
});
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
function init1bSyncButton(): void {
|
|
721
|
+
const btn = document.getElementById('btn-1b-sync') as HTMLButtonElement | null;
|
|
722
|
+
if (!btn) { return; }
|
|
723
|
+
btn.addEventListener('click', () => {
|
|
724
|
+
performPhaseSync({
|
|
725
|
+
phaseText: '1B',
|
|
726
|
+
btnId: 'btn-1b-sync',
|
|
727
|
+
nextBtnId: 'btn-1b-check',
|
|
728
|
+
expectSyncFailure: true,
|
|
729
|
+
failureMessageSuffix: 'establish phase successfully run; connection/sync errors expected in 1B'
|
|
730
|
+
});
|
|
678
731
|
});
|
|
679
732
|
}
|
|
680
733
|
|
|
681
734
|
function init1bCheckButton(): void {
|
|
682
735
|
const lc_fn = `${lc}[init1bCheckButton]`;
|
|
683
736
|
const btn = document.getElementById('btn-1b-check') as HTMLButtonElement | null;
|
|
684
|
-
if (!btn) return;
|
|
737
|
+
if (!btn) { return; }
|
|
685
738
|
|
|
686
739
|
btn.addEventListener('click', async () => {
|
|
687
740
|
try {
|
|
@@ -784,18 +837,18 @@ function init1bCheckButton(): void {
|
|
|
784
837
|
devLog(`✗ Check Server: Failed to fetch session keystone from server: ${resGetSessionSFromServer.message}`);
|
|
785
838
|
}
|
|
786
839
|
|
|
787
|
-
if (hasI) devLog('✓ Check Server: Genesis Domain Keystone (I) registered on server.');
|
|
840
|
+
if (hasI) { devLog('✓ Check Server: Genesis Domain Keystone (I) registered on server.'); }
|
|
788
841
|
else devLog('✗ Check Server: Genesis Domain Keystone (I) missing on server!');
|
|
789
|
-
if (hasI1) devLog('✓ Check Server: Evolved Domain Keystone (I1) accepted and stored on server.');
|
|
842
|
+
if (hasI1) { devLog('✓ Check Server: Evolved Domain Keystone (I1) accepted and stored on server.'); }
|
|
790
843
|
else devLog('✗ Check Server: Evolved Domain Keystone (I1) missing on server!');
|
|
791
|
-
if (hasS) devLog('✓ Check Server: Session Keystone (S) accepted and stored on server.');
|
|
844
|
+
if (hasS) { devLog('✓ Check Server: Session Keystone (S) accepted and stored on server.'); }
|
|
792
845
|
else devLog('✗ Check Server: Session Keystone (S) missing on server!');
|
|
793
846
|
if (hasI && hasI1 && hasS) {
|
|
794
847
|
devLog('🎉 ALL PHASE 1B ESTABLISH CHECKS PASSED FLAWLESSLY! ✓');
|
|
795
848
|
btn.textContent = '✓ 1B All Passed';
|
|
796
849
|
|
|
797
850
|
const btn2bSetup = document.getElementById('btn-2b-setup') as HTMLButtonElement | null;
|
|
798
|
-
if (btn2bSetup) btn2bSetup.disabled = false;
|
|
851
|
+
if (btn2bSetup) { btn2bSetup.disabled = false; }
|
|
799
852
|
}
|
|
800
853
|
|
|
801
854
|
// #endregion 3. Verify Server-Side (receiver) registrations via GET REST API
|
|
@@ -812,160 +865,40 @@ function init1bCheckButton(): void {
|
|
|
812
865
|
// ---------------------------------------------------------------------------
|
|
813
866
|
|
|
814
867
|
function init2bSetupButton(): void {
|
|
815
|
-
const lc_fn = `${lc}[init2bSetupButton]`;
|
|
816
868
|
const btn = document.getElementById('btn-2b-setup') as HTMLButtonElement | null;
|
|
817
|
-
if (!btn) return;
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
btn
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
const keystoneService = new KeystoneService_V1();
|
|
830
|
-
|
|
831
|
-
// 1. Create Genesis Domain Keystone (I^Itjp) in local sourceSpace
|
|
832
|
-
const domainI = await keystoneService.genesis({
|
|
833
|
-
masterSecret,
|
|
834
|
-
configs: [
|
|
835
|
-
getSpaceGibPoolConfig('sync', 'senderidentitysyncsaltphase2'),
|
|
836
|
-
getSpaceGibPoolConfig('manage', 'senderidentitymanagesaltphase2'),
|
|
837
|
-
],
|
|
838
|
-
metaspace,
|
|
839
|
-
space,
|
|
840
|
-
frameDetails: { client: 'space-gib-web-dev', timestamp: getTimestamp() }
|
|
841
|
-
});
|
|
842
|
-
|
|
843
|
-
debugState.domainI = domainI;
|
|
844
|
-
debugState.domainIMasterSecret = masterSecret;
|
|
845
|
-
|
|
846
|
-
devLog(`2B Setup: ✓ Domain Keystone (I) created locally: ${getIbGibAddr({ ibGib: domainI })}`);
|
|
847
|
-
devLog(`2B Setup: Starting postGenesisKeystone...`);
|
|
848
|
-
|
|
849
|
-
// 2. Post Genesis Domain Keystone to receiver/server
|
|
850
|
-
const apiBridge = new SpaceGibApiBridge();
|
|
851
|
-
const resGenesis = await apiBridge.postGenesisKeystone(domainI);
|
|
852
|
-
if (resGenesis.success) {
|
|
853
|
-
devLog(`2B Setup: ✓ Domain Keystone registered and stored on receiver (server).`);
|
|
854
|
-
} else {
|
|
855
|
-
devLog(`2B Setup: X postGenesisKeystone failed: ${resGenesis.message}.`);
|
|
856
|
-
throw new Error(`2B Setup: Server rejected genesis domain keystone: ${resGenesis.message}`);
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
// 3. Create Test IbGib (X) locally
|
|
860
|
-
const resX = await factory.firstGen({
|
|
861
|
-
parentIbGib: ROOT,
|
|
862
|
-
ib: 'test data',
|
|
863
|
-
data: { hello: 'world2', random: Math.random() },
|
|
864
|
-
dna: true,
|
|
865
|
-
nCounter: true,
|
|
866
|
-
tjp: { uuid: true, timestamp: true }
|
|
867
|
-
});
|
|
868
|
-
debugState.targetX = resX.newIbGib;
|
|
869
|
-
devLog(`2B Setup: ✓ Target (X) created locally: ${getIbGibAddr({ ibGib: resX.newIbGib })}`);
|
|
870
|
-
|
|
871
|
-
devLog('✓ 2B Setup Complete! Ready for 2B Sync.');
|
|
872
|
-
btn.textContent = '✓ 2B Setup Complete';
|
|
873
|
-
|
|
874
|
-
// Enable next button in the phase flow
|
|
875
|
-
const syncBtn = document.getElementById('btn-2b-sync') as HTMLButtonElement | null;
|
|
876
|
-
if (syncBtn) syncBtn.disabled = false;
|
|
877
|
-
|
|
878
|
-
} catch (error) {
|
|
879
|
-
devLog(`✗ 2B Setup FAILED: ${extractErrorMsg(error)}`);
|
|
880
|
-
console.error(`${lc_fn} 2B Setup error:`, error);
|
|
881
|
-
btn.disabled = false;
|
|
882
|
-
}
|
|
869
|
+
if (!btn) { return; }
|
|
870
|
+
btn.addEventListener('click', () => {
|
|
871
|
+
performPhaseSetup({
|
|
872
|
+
phaseText: '2B',
|
|
873
|
+
btnId: 'btn-2b-setup',
|
|
874
|
+
nextBtnId: 'btn-2b-sync',
|
|
875
|
+
masterSecret: 'test-sender-secret-phase2',
|
|
876
|
+
syncSalt: 'senderidentitysyncsaltphase2',
|
|
877
|
+
manageSalt: 'senderidentitymanagesaltphase2',
|
|
878
|
+
ib: 'test data',
|
|
879
|
+
data: { hello: 'world2', random: Math.random() }
|
|
880
|
+
});
|
|
883
881
|
});
|
|
884
882
|
}
|
|
885
883
|
|
|
886
884
|
function init2bSyncButton(): void {
|
|
887
|
-
const lc_fn = `${lc}[init2bSyncButton]`;
|
|
888
885
|
const btn = document.getElementById('btn-2b-sync') as HTMLButtonElement | null;
|
|
889
|
-
if (!btn) return;
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
btn
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
if (!domainI || !targetX) {
|
|
899
|
-
devLog('⚠ 2B Sync: Missing setup state. Please run Setup first.');
|
|
900
|
-
btn.disabled = false;
|
|
901
|
-
return;
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
const domainAddr = getIbGibAddr({ ibGib: domainI });
|
|
905
|
-
const metaspace = await getGlobalMetaspace_waitIfNeeded();
|
|
906
|
-
const space = await metaspace.getLocalUserSpace({});
|
|
907
|
-
if (!space) { throw new Error("No default space."); }
|
|
908
|
-
|
|
909
|
-
// Instantiate WebSocket sender peer
|
|
910
|
-
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
911
|
-
const senderPeer = new SyncPeerWebSocketSender_V1({
|
|
912
|
-
classname: 'SyncPeerWebSocketSender_V1',
|
|
913
|
-
httpEvolveUrl: `${location.protocol}//${location.host}/api/keystone/evolve/${encodeURIComponent(domainAddr)}`,
|
|
914
|
-
wsUrl: `${protocol}//${location.host}/api/sync/ws/${encodeURIComponent(domainAddr)}`
|
|
915
|
-
});
|
|
916
|
-
|
|
917
|
-
const coordinator = new SyncSagaCoordinator();
|
|
918
|
-
const sagaId = await getUUID();
|
|
919
|
-
debugState.sagaId = sagaId;
|
|
920
|
-
debugState.senderPeer = senderPeer;
|
|
921
|
-
|
|
922
|
-
await senderPeer.initializeOpts({
|
|
923
|
-
localMetaspace: metaspace,
|
|
924
|
-
localSpace: space,
|
|
925
|
-
senderIdentity: domainI,
|
|
926
|
-
fnSenderSecret: async () => debugState.domainIMasterSecret!,
|
|
927
|
-
sagaId,
|
|
928
|
-
sessionConnectPoolConfig: SESSION_KEYSTONE_POLICY.CONNECT_POOL as any,
|
|
929
|
-
sessionSyncPoolConfig: SESSION_KEYSTONE_POLICY.DEFAULT_POOL as any,
|
|
930
|
-
targetAddrs: [domainAddr]
|
|
931
|
-
});
|
|
932
|
-
|
|
933
|
-
try {
|
|
934
|
-
// Execute sync saga — triggers establishSessionIdentity and connectImpl internally!
|
|
935
|
-
const syncSaga = await coordinator.sync({
|
|
936
|
-
domainIbGibs: [targetX],
|
|
937
|
-
senderIdentity: domainI,
|
|
938
|
-
fnSenderSecret: async () => debugState.domainIMasterSecret!,
|
|
939
|
-
peer: senderPeer,
|
|
940
|
-
localSpace: space,
|
|
941
|
-
metaspace,
|
|
942
|
-
conflictStrategy: 'optimisticWithLCS' as any
|
|
943
|
-
});
|
|
944
|
-
await syncSaga.done;
|
|
945
|
-
} catch (err) {
|
|
946
|
-
// connection/sync error is fine/expected right now since sync protocol (Phase 3) might be incomplete
|
|
947
|
-
devLog(`2B Sync: Coordinator sync executed (connect phase successfully run; subsequent sync errors expected in 2B): ${extractErrorMsg(err)}`);
|
|
948
|
-
}
|
|
949
|
-
|
|
950
|
-
devLog('✓ 2B Sync Execution Complete! Ready for State Checks.');
|
|
951
|
-
btn.textContent = '✓ 2B Sync Run';
|
|
952
|
-
|
|
953
|
-
// Enable check button
|
|
954
|
-
const checkBtn = document.getElementById('btn-2b-check') as HTMLButtonElement | null;
|
|
955
|
-
if (checkBtn) checkBtn.disabled = false;
|
|
956
|
-
|
|
957
|
-
} catch (error) {
|
|
958
|
-
devLog(`✗ 2B Sync FAILED: ${extractErrorMsg(error)}`);
|
|
959
|
-
console.error(`${lc_fn} 2B Sync error:`, error);
|
|
960
|
-
btn.disabled = false;
|
|
961
|
-
}
|
|
886
|
+
if (!btn) { return; }
|
|
887
|
+
btn.addEventListener('click', () => {
|
|
888
|
+
performPhaseSync({
|
|
889
|
+
phaseText: '2B',
|
|
890
|
+
btnId: 'btn-2b-sync',
|
|
891
|
+
nextBtnId: 'btn-2b-check',
|
|
892
|
+
expectSyncFailure: true,
|
|
893
|
+
failureMessageSuffix: 'connect phase successfully run; subsequent sync errors expected in 2B'
|
|
894
|
+
});
|
|
962
895
|
});
|
|
963
896
|
}
|
|
964
897
|
|
|
965
898
|
function init2bCheckButton(): void {
|
|
966
899
|
const lc_fn = `${lc}[init2bCheckButton]`;
|
|
967
900
|
const btn = document.getElementById('btn-2b-check') as HTMLButtonElement | null;
|
|
968
|
-
if (!btn) return;
|
|
901
|
+
if (!btn) { return; }
|
|
969
902
|
|
|
970
903
|
btn.addEventListener('click', async () => {
|
|
971
904
|
try {
|
|
@@ -1070,7 +1003,7 @@ function init2bCheckButton(): void {
|
|
|
1070
1003
|
|
|
1071
1004
|
// Enable Phase 3B setup
|
|
1072
1005
|
const p3SetupBtn = document.getElementById('btn-3b-setup') as HTMLButtonElement | null;
|
|
1073
|
-
if (p3SetupBtn) p3SetupBtn.disabled = false;
|
|
1006
|
+
if (p3SetupBtn) { p3SetupBtn.disabled = false; }
|
|
1074
1007
|
|
|
1075
1008
|
} catch (error) {
|
|
1076
1009
|
devLog(`✗ 2B Check FAILED: ${extractErrorMsg(error)}`);
|
|
@@ -1079,20 +1012,186 @@ function init2bCheckButton(): void {
|
|
|
1079
1012
|
});
|
|
1080
1013
|
}
|
|
1081
1014
|
|
|
1082
|
-
function
|
|
1083
|
-
const
|
|
1084
|
-
|
|
1085
|
-
|
|
1015
|
+
function init3bSetupButton(): void {
|
|
1016
|
+
const btn = document.getElementById('btn-3b-setup') as HTMLButtonElement | null;
|
|
1017
|
+
if (!btn) { return; }
|
|
1018
|
+
btn.addEventListener('click', () => {
|
|
1019
|
+
performPhaseSetup({
|
|
1020
|
+
phaseText: '3B',
|
|
1021
|
+
btnId: 'btn-3b-setup',
|
|
1022
|
+
nextBtnId: 'btn-3b-sync',
|
|
1023
|
+
masterSecret: 'test-sender-secret-phase3',
|
|
1024
|
+
syncSalt: 'senderidentitysyncsaltphase3',
|
|
1025
|
+
manageSalt: 'senderidentitymanagesaltphase3',
|
|
1026
|
+
ib: 'test data 3b',
|
|
1027
|
+
data: { hello: 'world3', random: Math.random() }
|
|
1028
|
+
});
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
1086
1031
|
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1032
|
+
function init3bSyncButton(): void {
|
|
1033
|
+
const btn = document.getElementById('btn-3b-sync') as HTMLButtonElement | null;
|
|
1034
|
+
if (!btn) { return; }
|
|
1035
|
+
btn.addEventListener('click', () => {
|
|
1036
|
+
performPhaseSync({
|
|
1037
|
+
phaseText: '3B',
|
|
1038
|
+
btnId: 'btn-3b-sync',
|
|
1039
|
+
nextBtnId: 'btn-3b-check'
|
|
1040
|
+
});
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
function init3bCheckButton(): void {
|
|
1045
|
+
const lc_fn = `${lc}[init3bCheckButton]`;
|
|
1046
|
+
const btn = document.getElementById('btn-3b-check') as HTMLButtonElement | null;
|
|
1047
|
+
if (!btn) { return; }
|
|
1048
|
+
|
|
1049
|
+
btn.addEventListener('click', async () => {
|
|
1050
|
+
try {
|
|
1051
|
+
debugger; // allow for walkthrough 3B check
|
|
1052
|
+
devLog('3B Check: Asserting cryptographic and WebSocket state expectations...');
|
|
1053
|
+
|
|
1054
|
+
const metaspace = await getGlobalMetaspace_waitIfNeeded();
|
|
1055
|
+
const space = await metaspace.getLocalUserSpace({});
|
|
1056
|
+
if (!space) { throw new Error("No default space."); }
|
|
1057
|
+
|
|
1058
|
+
const domainI = debugState.domainI!;
|
|
1059
|
+
const targetX = debugState.targetX!;
|
|
1060
|
+
const xAddr = getIbGibAddr({ ibGib: targetX });
|
|
1061
|
+
const domainAddr = getIbGibAddr({ ibGib: domainI });
|
|
1062
|
+
|
|
1063
|
+
// 1. Assert Target X exists locally (with evolved timeline) and get latest local graph
|
|
1064
|
+
const latestLocalXAddr = await metaspace.getLatestAddr({
|
|
1065
|
+
addr: xAddr,
|
|
1066
|
+
space
|
|
1067
|
+
});
|
|
1068
|
+
if (!latestLocalXAddr) {
|
|
1069
|
+
devLog('✗ Check: Evolved target X NOT found in local space!');
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1072
|
+
devLog(`✓ Check: Evolved target X found locally at: ${latestLocalXAddr}`);
|
|
1073
|
+
|
|
1074
|
+
const localXGraph = await metaspace.getDependencyGraph({
|
|
1075
|
+
ibGibAddr: latestLocalXAddr,
|
|
1076
|
+
space
|
|
1077
|
+
});
|
|
1078
|
+
if (!localXGraph || Object.keys(localXGraph).length === 0) {
|
|
1079
|
+
devLog('✗ Check: Failed to load target X dependency graph locally.');
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
devLog(`✓ Check: Target X local graph loaded (${Object.keys(localXGraph).length} nodes).`);
|
|
1083
|
+
|
|
1084
|
+
// 2. Fetch server's Target X graph via API bridge
|
|
1085
|
+
const apiBridge = new SpaceGibApiBridge();
|
|
1086
|
+
const serverGetRes = await apiBridge.getIbGibGraph(domainAddr, xAddr, true);
|
|
1087
|
+
if (!serverGetRes.success || !serverGetRes.graph) {
|
|
1088
|
+
devLog(`✗ Check: Failed to fetch target X graph from server: ${serverGetRes.message}`);
|
|
1089
|
+
return;
|
|
1090
|
+
}
|
|
1091
|
+
const serverXGraph = serverGetRes.graph;
|
|
1092
|
+
devLog(`✓ Check: Target X server graph loaded (${Object.keys(serverXGraph).length} nodes).`);
|
|
1093
|
+
|
|
1094
|
+
// 3. Verify graphs are equivalent using graphsAreEquivalent
|
|
1095
|
+
const equal = graphsAreEquivalent({ graphA: localXGraph, graphB: serverXGraph });
|
|
1096
|
+
if (equal) {
|
|
1097
|
+
devLog('✓ Check: Target X dependency graphs are equivalent on client and server.');
|
|
1098
|
+
} else {
|
|
1099
|
+
devLog('✗ Check: Target X dependency graphs mismatch between client and server!');
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
// 4. Assert evolved sender identity I1 exists locally and on server
|
|
1104
|
+
const latestLocalIAddr = await metaspace.getLatestAddr({
|
|
1105
|
+
addr: domainAddr,
|
|
1106
|
+
space
|
|
1107
|
+
});
|
|
1108
|
+
if (!latestLocalIAddr) {
|
|
1109
|
+
devLog('✗ Check: Evolved domain keystone tip I1 NOT found in local space!');
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
1112
|
+
devLog(`✓ Check: Evolved Domain Keystone (I1) exists locally.`);
|
|
1113
|
+
|
|
1114
|
+
const getRes = await metaspace.get({ addrs: [latestLocalIAddr], space });
|
|
1115
|
+
const localI = getRes.ibGibs?.[0] as KeystoneIbGib_V1 | undefined;
|
|
1116
|
+
if (!localI) {
|
|
1117
|
+
devLog('✗ Check: Failed to load I1 from local space.');
|
|
1118
|
+
return;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
const syncProof = localI.data?.proofs?.find(p => p.claim?.verb === 'sync');
|
|
1122
|
+
const sessionIdentityTjpAddr = syncProof?.claim?.target;
|
|
1123
|
+
if (!sessionIdentityTjpAddr) {
|
|
1124
|
+
devLog('✗ Check: I1 sync claim does not target a session keystone.');
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
const serverIGetRes = await apiBridge.getIbGib(domainAddr, latestLocalIAddr);
|
|
1129
|
+
if (!serverIGetRes.success || !serverIGetRes.ibGib) {
|
|
1130
|
+
devLog(`✗ Check: Evolved Domain Keystone (I1) NOT found on server!`);
|
|
1131
|
+
return;
|
|
1132
|
+
}
|
|
1133
|
+
devLog(`✓ Check: Evolved Domain Keystone (I1) exists on server.`);
|
|
1134
|
+
|
|
1135
|
+
// 5. Assert session identity S tip exists locally and on server
|
|
1136
|
+
const latestLocalSAddr = await metaspace.getLatestAddr({
|
|
1137
|
+
addr: sessionIdentityTjpAddr,
|
|
1138
|
+
space
|
|
1139
|
+
});
|
|
1140
|
+
if (!latestLocalSAddr) {
|
|
1141
|
+
devLog('✗ Check: Latest Session Keystone (S) NOT found in local space.');
|
|
1142
|
+
return;
|
|
1143
|
+
}
|
|
1144
|
+
devLog(`✓ Check: Found latest session keystone (S) locally: ${latestLocalSAddr}`);
|
|
1145
|
+
|
|
1146
|
+
const localSRes = await metaspace.get({ addrs: [latestLocalSAddr], space });
|
|
1147
|
+
const sessionS = localSRes.ibGibs?.[0] as KeystoneIbGib_V1 | undefined;
|
|
1148
|
+
if (!sessionS) {
|
|
1149
|
+
devLog('✗ Check: Failed to load latest Session Keystone (S) locally.');
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
// Verify S evolved to correct n (n === 3 or 4)
|
|
1154
|
+
const n = sessionS.data?.n;
|
|
1155
|
+
devLog(`✓ Check: S tip evolved to n = ${n}.`);
|
|
1156
|
+
if (n !== 3 && n !== 4) {
|
|
1157
|
+
devLog(`⚠ Check: Expected S to evolve to n = 3 or 4, got n = ${n}. Continuing anyway...`);
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
const serverSGetRes = await apiBridge.getIbGib(domainAddr, latestLocalSAddr);
|
|
1161
|
+
if (!serverSGetRes.success || !serverSGetRes.ibGib) {
|
|
1162
|
+
devLog(`✗ Check: Latest Session Keystone (S) NOT found on server!`);
|
|
1163
|
+
return;
|
|
1164
|
+
}
|
|
1165
|
+
devLog(`✓ Check: Latest Session Keystone (S) exists on server.`);
|
|
1166
|
+
|
|
1167
|
+
// 6. Assert S graph is identical on client and server
|
|
1168
|
+
const localSGraph = await metaspace.getDependencyGraph({
|
|
1169
|
+
ibGibAddr: latestLocalSAddr,
|
|
1170
|
+
space
|
|
1171
|
+
});
|
|
1172
|
+
const serverSGetGraphRes = await apiBridge.getIbGibGraph(domainAddr, sessionIdentityTjpAddr, true);
|
|
1173
|
+
if (!serverSGetGraphRes.success || !serverSGetGraphRes.graph) {
|
|
1174
|
+
devLog(`✗ Check: Failed to fetch session S graph from server: ${serverSGetGraphRes.message}`);
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
const serverSGraph = serverSGetGraphRes.graph;
|
|
1178
|
+
|
|
1179
|
+
const sGraphsEqual = graphsAreEquivalent({ graphA: localSGraph, graphB: serverSGraph });
|
|
1180
|
+
if (sGraphsEqual) {
|
|
1181
|
+
devLog('✓ Check: Session Keystone (S) dependency graphs are equivalent on client and server.');
|
|
1182
|
+
} else {
|
|
1183
|
+
devLog('✗ Check: Session Keystone (S) dependency graphs mismatch between client and server!');
|
|
1184
|
+
return;
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
devLog('🎉 ALL PHASE 3B TRANSACTION SYNC CHECKS PASSED FLAWLESSLY! ✓');
|
|
1188
|
+
btn.textContent = '✓ 3B All Passed';
|
|
1189
|
+
|
|
1190
|
+
} catch (error) {
|
|
1191
|
+
devLog(`✗ 3B Check FAILED: ${extractErrorMsg(error)}`);
|
|
1192
|
+
console.error(`${lc_fn} 3B Check error:`, error);
|
|
1193
|
+
}
|
|
1194
|
+
});
|
|
1096
1195
|
}
|
|
1097
1196
|
|
|
1098
1197
|
// ---------------------------------------------------------------------------
|
|
@@ -1118,7 +1217,9 @@ export function initDevTools(): void {
|
|
|
1118
1217
|
init2bSetupButton();
|
|
1119
1218
|
init2bSyncButton();
|
|
1120
1219
|
init2bCheckButton();
|
|
1121
|
-
|
|
1220
|
+
init3bSetupButton();
|
|
1221
|
+
init3bSyncButton();
|
|
1222
|
+
init3bCheckButton();
|
|
1122
1223
|
} catch (error) {
|
|
1123
1224
|
console.error(`${lc_fn} ${extractErrorMsg(error)}`);
|
|
1124
1225
|
}
|