import { extractErrorMsg, getUUID } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs'; import { Factory_V1 as factory } from '@ibgib/ts-gib/dist/V1/factory.mjs'; import { ROOT } from '@ibgib/ts-gib/dist/V1/constants.mjs'; import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs'; import { KeystoneIbGib_V1 } from '@ibgib/core-gib/dist/keystone/keystone-types.mjs'; import { getGlobalMetaspace_waitIfNeeded } from "@ibgib/web-gib/dist/helpers.mjs"; import { mut8Timeline } from '@ibgib/core-gib/dist/timeline/timeline-api.mjs'; import { graphsAreEquivalent } from '@ibgib/core-gib/dist/common/other/graph-helper.mjs'; import { SpaceGibApiBridge } from '../api/space-gib-api-bridge.mjs'; import { debugState, devLog, lc, setupDomainAndDelegateIdentities, runSyncPass, runSyncPassFromSpace, copyIdentitiesToSpace } from './common.mjs'; // Phase-specific state for items that don't fit in debugState interface Phase45State { targetV2?: any; } const state: Phase45State = {}; const MASTER_SECRET = 'test-sender-secret-phase4-5b'; export function init4_5bSetupButton(): void { const btn = document.getElementById('btn-4-5b-setup') as HTMLButtonElement | null; if (!btn) { return; } btn.addEventListener('click', async () => { try { btn.disabled = true; devLog('4.5B Setup: Generating Domain Keystone (I), target timeline, and seeding server from two spaces...'); const metaspace = await getGlobalMetaspace_waitIfNeeded(); const space = await metaspace.getLocalUserSpace({}); if (!space) { throw new Error("No default space."); } const apiBridge = new SpaceGibApiBridge(); // 1. Create domain + delegate identities (DRY helper) await setupDomainAndDelegateIdentities({ masterSecret: MASTER_SECRET, syncSalt: 'senderidentitysyncsaltphase4-5b', manageSalt: 'senderidentitymanagesaltphase4-5b', metaspace, space, apiBridge, phaseText: '4.5B' }); // 2. Create target timeline root V0 const resV0 = await factory.firstGen({ parentIbGib: ROOT, ib: 'timeline_root_partial_4_5b', data: { type: 'root', label: 'Root4_5b', random: Math.random() }, dna: true, nCounter: true, tjp: { uuid: true, timestamp: true } }); const r1_v0 = resV0.newIbGib; await metaspace.persistTransformResult({ resTransform: resV0, space }); await metaspace.registerNewIbGib({ ibGib: r1_v0, space }); // 3. Mutate V0 → V1 in default space const r1_v1 = await mut8Timeline({ timeline: r1_v0, mut8Opts: { dataToAddOrPatch: { type: 'comment', label: 'V1_4_5b' } }, metaspace, space, }); debugState.targetC1 = r1_v1; devLog(`4.5B Setup: ✓ Local timeline V0 -> V1 created. V1 Tip: ${getIbGibAddr({ ibGib: r1_v1 })}`); // 4. Sync V1 to server from default space (Pass 1 — seeds V1 on the server) devLog('4.5B Setup: Seeding V1 to the server via WebSocket...'); await runSyncPass({ domainIbGibs: [r1_v1], passLabel: 'Seed V1 to server', metaspace, space }); devLog('4.5B Setup: ✓ Pass 1 Sync (V1 to server) complete.'); // 5. Create remoteSpace (simulating a remote client) devLog('4.5B Setup: Creating secondary local space simulating "remote" client...'); const remoteSpaceName = `remote-${await getUUID()}`; const remoteSpace = await metaspace.createNewLocalSpace({ opts: { allowCancel: false, spaceName: remoteSpaceName, getFnPrompt: metaspace.getFnPrompt!, } }); if (!remoteSpace) { throw new Error("Failed to create remote space"); } await remoteSpace.initialized; // 6. Copy V1 and its dependency graph + identity to remoteSpace const graphV1 = await metaspace.getDependencyGraph({ ibGibAddr: getIbGibAddr({ ibGib: r1_v1 }), space }); await metaspace.put({ ibGibs: Object.values(graphV1), space: remoteSpace }); await metaspace.registerNewIbGib({ ibGib: r1_v1, space: remoteSpace }); const domainI = debugState.domainI!; await copyIdentitiesToSpace({ domainI, metaspace, fromSpace: space, toSpace: remoteSpace }); devLog('4.5B Setup: ✓ Copied V1 and identities (domain and delegate) to remoteSpace.'); // 7. Mutate V1 → V2 in remoteSpace ONLY devLog('4.5B Setup: Mutating V1 -> V2 in remoteSpace...'); const r1_v2 = await mut8Timeline({ timeline: r1_v1, mut8Opts: { dataToAddOrPatch: { type: 'comment', label: 'V2_4_5b' } }, metaspace, space: remoteSpace, }); state.targetV2 = r1_v2; devLog(`4.5B Setup: ✓ Mutated to V2 in remoteSpace: ${getIbGibAddr({ ibGib: r1_v2 })}`); // 8. Sync V2 from remoteSpace to server (Pass 2 — server now has V2) devLog('4.5B Setup: Syncing V2 from remoteSpace to the server...'); await runSyncPassFromSpace({ domainIbGibs: [r1_v2], passLabel: 'Seed V2 from remoteSpace', metaspace, space: remoteSpace, primarySpace: space, domainI, masterSecret: MASTER_SECRET }); devLog('4.5B Setup: ✓ Pass 2 Sync (V2 to server) complete. debugState.domainI updated.'); devLog('✓ 4.5B Setup Complete! Server has V2, default local space has V1. Ready for 4.5B Sync.'); btn.textContent = '✓ 4.5B Setup Complete'; const syncBtn = document.getElementById('btn-4-5b-sync') as HTMLButtonElement | null; if (syncBtn) { syncBtn.disabled = false; } } catch (error) { devLog(`✗ 4.5B Setup FAILED: ${extractErrorMsg(error)}`); console.error(error); btn.disabled = false; } }); } export function init4_5bSyncButton(): void { const btn = document.getElementById('btn-4-5b-sync') as HTMLButtonElement | null; if (!btn) { return; } btn.addEventListener('click', async () => { try { btn.disabled = true; devLog('4.5B Sync: Initiating WebSocket Sync from default local space (which has V1, server has V2)...'); const targetV1 = debugState.targetC1; if (!debugState.domainI || !targetV1) { devLog('⚠ 4.5B Sync: Missing setup state. Please run Setup first.'); btn.disabled = false; return; } const metaspace = await getGlobalMetaspace_waitIfNeeded(); const space = await metaspace.getLocalUserSpace({}); if (!space) { throw new Error("No default space."); } // Sync targeting our local tip V1. Since the server is ahead with V2, // the coordinator should pull down V2 via delta resolution. await runSyncPass({ domainIbGibs: [targetV1], passLabel: 'Pull V2 from server', metaspace, space }); devLog('✓ 4.5B Sync Execution Complete! Ready for 4.5B Check.'); btn.textContent = '✓ 4.5B Sync Run'; const checkBtn = document.getElementById('btn-4-5b-check') as HTMLButtonElement | null; if (checkBtn) { checkBtn.disabled = false; } } catch (error) { devLog(`✗ 4.5B Sync FAILED: ${extractErrorMsg(error)}`); console.error(error); btn.disabled = false; } }); } export function init4_5bCheckButton(): void { const btn = document.getElementById('btn-4-5b-check') as HTMLButtonElement | null; if (!btn) { return; } btn.addEventListener('click', async () => { try { btn.disabled = true; devLog('4.5B Check: Verifying that V2 was pulled down to default local space...'); const targetV2 = state.targetV2; if (!targetV2 || !debugState.domainI) { devLog('⚠ 4.5B Check: Missing target V2 in state. Did Setup run?'); btn.disabled = false; return; } const targetV2Addr = getIbGibAddr({ ibGib: targetV2 }); const domainAddr = getIbGibAddr({ ibGib: debugState.domainI }); const metaspace = await getGlobalMetaspace_waitIfNeeded(); const space = await metaspace.getLocalUserSpace({}); if (!space) { throw new Error("No default space."); } // 1. Verify V2 now exists in default local space const resGetV2 = await metaspace.get({ addr: targetV2Addr, space }); if (!resGetV2.success || resGetV2.ibGibs?.length !== 1) { throw new Error(`V2 tip (${targetV2Addr}) is NOT present in local space!`); } const localV2 = resGetV2.ibGibs[0]; devLog(`4.5B Check: ✓ V2 Tip found locally. Label: "${localV2.data?.label}"`); // 2. Fetch full dependency graph of V2 from local space and server, assert equivalence const localGraph = await metaspace.getDependencyGraph({ ibGibAddr: targetV2Addr, space }); devLog('4.5B Check: Fetching V2 dependency graph from server...'); const apiBridge = new SpaceGibApiBridge(); const resServerGraph = await apiBridge.getIbGibGraph(domainAddr, targetV2Addr, true); if (!resServerGraph.success || !resServerGraph.graph) { throw new Error(`Failed to fetch V2 graph from server: ${resServerGraph.message}`); } const equal = graphsAreEquivalent({ graphA: localGraph, graphB: resServerGraph.graph }); if (equal) { devLog('✓ 4.5B Check SUCCESS: V2 and all dependencies are fully equivalent on client and server!'); btn.textContent = '✓ 4.5B Check Success'; } else { throw new Error("Dependency graphs on local space and server are NOT equivalent."); } } catch (error) { devLog(`✗ 4.5B Check FAILED: ${extractErrorMsg(error)}`); console.error(error); btn.disabled = false; } }); }