import { extractErrorMsg, getTimestamp, getUUID, hash } 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 { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs'; import { KeystoneService_V1 } from '@ibgib/core-gib/dist/keystone/keystone-service-v1.mjs'; import { KeystoneIbGib_V1 } from '@ibgib/core-gib/dist/keystone/keystone-types.mjs'; import { SyncPeerWebSocketSender_V1 } from '@ibgib/core-gib/dist/sync/sync-peer/sync-peer-websocket/sync-peer-websocket-sender/sync-peer-websocket-sender-v1.mjs'; import { SyncSagaCoordinator } from '@ibgib/core-gib/dist/sync/sync-saga-coordinator.mjs'; import { getGlobalMetaspace_waitIfNeeded } from "@ibgib/web-gib/dist/helpers.mjs"; import { SESSION_KEYSTONE_POLICY, getSpaceGibPoolConfig } from "../../common/keystone-policies.mjs"; import { SpaceGibApiBridge } from '../api/space-gib-api-bridge.mjs'; import { KEYSTONE_VERB_SYNC } from '@ibgib/core-gib/dist/keystone/keystone-constants.mjs'; import { SyncConflictStrategy } from '@ibgib/core-gib/dist/sync/sync-constants.mjs'; import { GLOBAL_LOG_A_LOT } from '../constants.mjs'; export const logalot = GLOBAL_LOG_A_LOT; export const lc = '[dev-tools]'; export interface DebugState { domainI?: KeystoneIbGib_V1; domainIMasterSecret?: string; targetX?: IbGib_V1; targetC1?: IbGib_V1; targetC2?: IbGib_V1; sessionS?: KeystoneIbGib_V1; sessionSecret?: string; senderPeer?: SyncPeerWebSocketSender_V1; sagaId?: string; } export const debugState: DebugState = {}; (window as any).ibgibDebugState = debugState; // --------------------------------------------------------------------------- // Dev panel log helper // --------------------------------------------------------------------------- export function devLog(msg: string): void { const logEl = document.getElementById('dev-panel-log') as HTMLPreElement | null; if (!logEl) { return; } const timestamp = new Date().toISOString().slice(11, 23); // HH:MM:SS.mmm logEl.textContent = `[${timestamp}] ${msg}\n` + logEl.textContent; } // --------------------------------------------------------------------------- // Phase Setup / Sync common runners // --------------------------------------------------------------------------- export interface PhaseSetupOptions { phaseText: '1B' | '2B' | '3B' | '4.1B' | '4.2B' | '4.3B'; btnId: string; nextBtnId: string; masterSecret: string; syncSalt: string; manageSalt: string; ib: string; data: any; } export async function createAndRegisterSyncDelegate({ domainI, masterSecret, syncSalt, metaspace, space, apiBridge }: { domainI: KeystoneIbGib_V1; masterSecret: string; syncSalt: string; metaspace: any; space: any; apiBridge: SpaceGibApiBridge; }): Promise<{ evolvedDomainI: KeystoneIbGib_V1; delegateKeystone: KeystoneIbGib_V1; delegateSecret: string }> { const keystoneService = new KeystoneService_V1(); // 1. Derive delegate secret const delegateSecret = await hash({ s: `${masterSecret}-sync-delegate` }); // 2. Genesis the delegate keystone const delegateKeystone = await keystoneService.genesis({ masterSecret: delegateSecret, configs: [ getSpaceGibPoolConfig('sync', `${syncSalt}-delegate`), ], metaspace, space, frameDetails: { client: 'space-gib-web-dev-delegate', timestamp: getTimestamp() } }); // 3. Register delegate on parent Domain identity const evolvedDomainI = await keystoneService.registerDelegate({ parentKeystone: domainI, delegateKeystone, masterSecret, signingPoolId: 'manage', metaspace, space, allowedVerbs: [KEYSTONE_VERB_SYNC] }); const domainAddr = getIbGibAddr({ ibGib: domainI }); // 4. Sync evolved parent and delegate to server const resEvolve = await apiBridge.putEvolveKeystone({ domainAddr, keystoneIbGib: evolvedDomainI, relatedKeystoneIbGibs: [delegateKeystone] }); if (!resEvolve.success) { throw new Error(`Server rejected delegate evolution: ${resEvolve.message}`); } return { evolvedDomainI, delegateKeystone, delegateSecret }; } export async function getSenderIdentityInfo({ domainI, masterSecret, metaspace, space }: { domainI: KeystoneIbGib_V1; masterSecret: string; metaspace: any; space: any; }): Promise<{ senderIdentity: KeystoneIbGib_V1; fnSenderSecret: () => Promise }> { let senderIdentity = domainI; let fnSenderSecret = async () => masterSecret; // Find the delegate that is authorized for sync (not just [0] — there may be others) const syncDelegateEntry = Object.values(domainI.data?.delegates ?? {}).find( d => d.allowedVerbs?.includes(KEYSTONE_VERB_SYNC) ); if (syncDelegateEntry) { const delegateTjpAddr = syncDelegateEntry.delegateTjpAddr; if (delegateTjpAddr) { // Always resolve the LATEST evolved delegate tip, not the genesis frame const latestDelegateAddr = await metaspace.getLatestAddr({ addr: delegateTjpAddr, space }); if (latestDelegateAddr) { const resDel = await metaspace.get({ addr: latestDelegateAddr, space }); if (resDel.success && resDel.ibGibs && resDel.ibGibs.length > 0) { senderIdentity = resDel.ibGibs[0] as KeystoneIbGib_V1; const delegateSecret = await hash({ s: `${masterSecret}-sync-delegate` }); fnSenderSecret = async () => delegateSecret; } } } } return { senderIdentity, fnSenderSecret }; } export async function performPhaseSetup(opts: PhaseSetupOptions): Promise { const lc_fn = `${lc}[performPhaseSetup(${opts.phaseText})]`; const btn = document.getElementById(opts.btnId) as HTMLButtonElement | null; if (!btn) { return; } try { btn.disabled = true; devLog(`${opts.phaseText} Setup: Generating Alice's long-lived Domain Keystone (I) and Target (X)...`); const metaspace = await getGlobalMetaspace_waitIfNeeded(); const space = await metaspace.getLocalUserSpace({}); if (!space) { throw new Error("No default space found in metaspace."); } const keystoneService = new KeystoneService_V1(); // 1. Create Genesis Domain Keystone (I^Itjp) in local space. // The domain identity only needs a 'manage' pool — the delegate gets 'sync'. const domainI = await keystoneService.genesis({ masterSecret: opts.masterSecret, configs: [ getSpaceGibPoolConfig('manage', opts.manageSalt), ], metaspace, space, frameDetails: { client: 'space-gib-web-dev', timestamp: getTimestamp() } }); devLog(`${opts.phaseText} Setup: ✓ Domain Keystone (I) created locally: ${getIbGibAddr({ ibGib: domainI })}`); devLog(`${opts.phaseText} Setup: Starting postGenesisKeystone...`); // 2. Post Genesis Domain Keystone to receiver/server const apiBridge = new SpaceGibApiBridge(); const resGenesis = await apiBridge.postGenesisKeystone(domainI); if (resGenesis.success) { devLog(`${opts.phaseText} Setup: ✓ Domain Keystone registered and stored on receiver (server).`); } else { devLog(`${opts.phaseText} Setup: X postGenesisKeystone failed: ${resGenesis.message}.`); throw new Error(`${opts.phaseText} Setup: Server rejected genesis domain keystone: ${resGenesis.message}`); } // 2.5 Generate and register delegate devLog(`${opts.phaseText} Setup: Generating and registering sync delegate...`); const { evolvedDomainI, delegateKeystone } = await createAndRegisterSyncDelegate({ domainI, masterSecret: opts.masterSecret, syncSalt: opts.syncSalt, metaspace, space, apiBridge }); debugState.domainI = evolvedDomainI; debugState.domainIMasterSecret = opts.masterSecret; devLog(`${opts.phaseText} Setup: ✓ Registered Sync Delegate: ${getIbGibAddr({ ibGib: delegateKeystone })}`); // 3. Create Test IbGib (X) locally const resX = await factory.firstGen({ parentIbGib: ROOT, ib: opts.ib, data: opts.data, dna: true, nCounter: true, tjp: { uuid: true, timestamp: true } }); const xIbGib = resX.newIbGib; // Persist target X to local space so coordinator can build the sync history await metaspace.persistTransformResult({ resTransform: resX, space }); await metaspace.registerNewIbGib({ ibGib: xIbGib }); debugState.targetX = xIbGib; devLog(`${opts.phaseText} Setup: ✓ Target (X) created and persisted locally: ${getIbGibAddr({ ibGib: xIbGib })}`); devLog(`✓ ${opts.phaseText} Setup Complete! Ready for ${opts.phaseText} Sync.`); btn.textContent = `✓ ${opts.phaseText} Setup Complete`; const syncBtn = document.getElementById(opts.nextBtnId) as HTMLButtonElement | null; if (syncBtn) { syncBtn.disabled = false; } } catch (error) { devLog(`✗ ${opts.phaseText} Setup FAILED: ${extractErrorMsg(error)}`); console.error(`${lc_fn} ${opts.phaseText} Setup error:`, error); btn.disabled = false; } } export interface PhaseSyncOptions { phaseText: '1B' | '2B' | '3B' | '4.1B' | '4.2B' | '4.3B'; btnId: string; nextBtnId: string; expectSyncFailure?: boolean; failureMessageSuffix?: string; } export async function performPhaseSync(opts: PhaseSyncOptions): Promise { const lc_fn = `${lc}[performPhaseSync(${opts.phaseText})]`; const btn = document.getElementById(opts.btnId) as HTMLButtonElement | null; if (!btn) { return; } try { btn.disabled = true; devLog(`${opts.phaseText} Sync: Executing senderCoordinator.sync(...) using WebSocket Peer...`); const domainI = debugState.domainI; const targetX = debugState.targetX; if (!domainI || !targetX) { devLog(`⚠ ${opts.phaseText} Sync: Missing setup state. Please run Setup first.`); btn.disabled = false; return; } const domainAddr = getIbGibAddr({ ibGib: domainI }); const metaspace = await getGlobalMetaspace_waitIfNeeded(); const space = await metaspace.getLocalUserSpace({}); if (!space) { throw new Error("No default space."); } const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:'; const senderPeer = new SyncPeerWebSocketSender_V1({ classname: 'SyncPeerWebSocketSender_V1', httpEvolveUrl: `${location.protocol}//${location.host}/api/keystone/evolve/${encodeURIComponent(domainAddr)}`, wsUrl: `${protocol}//${location.host}/api/sync/ws/${encodeURIComponent(domainAddr)}` }); const coordinator = new SyncSagaCoordinator(); const sagaId = await getUUID(); debugState.sagaId = sagaId; debugState.senderPeer = senderPeer; const { senderIdentity, fnSenderSecret } = await getSenderIdentityInfo({ domainI, masterSecret: debugState.domainIMasterSecret!, metaspace, space }); await senderPeer.initializeOpts({ localMetaspace: metaspace, localSpace: space, senderIdentity, fnSenderSecret, sagaId, sessionConnectPoolConfig: SESSION_KEYSTONE_POLICY.CONNECT_POOL as any, sessionSyncPoolConfig: SESSION_KEYSTONE_POLICY.DEFAULT_POOL as any, targetAddrs: [domainAddr] }); try { const syncSaga = await coordinator.sync({ domainIbGibs: [targetX], senderIdentityInfo: { senderIdentity, senderDomainAddr: domainAddr, }, fnSenderSecret, peer: senderPeer, localSpace: space, metaspace, conflictStrategy: SyncConflictStrategy.optimisticWithLCS, }); await syncSaga.done; } catch (err) { if (opts.expectSyncFailure) { devLog(`${opts.phaseText} Sync: Coordinator sync executed (${opts.failureMessageSuffix ?? 'errors expected'}): ${extractErrorMsg(err)}`); } else { throw err; } } devLog(`✓ ${opts.phaseText} Sync Execution Complete! Ready for State Checks.`); btn.textContent = `✓ ${opts.phaseText} Sync Run`; const checkBtn = document.getElementById(opts.nextBtnId) as HTMLButtonElement | null; if (checkBtn) { checkBtn.disabled = false; } } catch (error) { devLog(`✗ ${opts.phaseText} Sync FAILED: ${extractErrorMsg(error)}`); console.error(`${lc_fn} ${opts.phaseText} Sync error:`, error); btn.disabled = false; } } export async function getDelegateAndSessionInfo({ localI, metaspace, space }: { localI: KeystoneIbGib_V1; metaspace: any; space: any; }): Promise<{ delegateTjpAddr?: string; latestLocalDelegateAddr?: string; localDelegate?: KeystoneIbGib_V1; sessionIdentityTjpAddr?: string; }> { // Find the delegate that is specifically authorized for sync const delegateInfo = Object.values(localI.data?.delegates ?? {}).find( d => d.allowedVerbs?.includes(KEYSTONE_VERB_SYNC) ); if (!delegateInfo) { return {}; } const delegateTjpAddr = delegateInfo.delegateTjpAddr; if (!delegateTjpAddr) { return {}; } const latestLocalDelegateAddr = await metaspace.getLatestAddr({ addr: delegateTjpAddr, space }); if (!latestLocalDelegateAddr) { return { delegateTjpAddr }; } const getDelRes = await metaspace.get({ addrs: [latestLocalDelegateAddr], space }); const localDelegate = getDelRes.ibGibs?.[0] as KeystoneIbGib_V1 | undefined; if (!localDelegate) { return { delegateTjpAddr, latestLocalDelegateAddr }; } const syncProof = localDelegate.data?.proofs?.find(p => p.claim?.verb === 'sync'); const sessionIdentityTjpAddr = syncProof?.claim?.target; return { delegateTjpAddr, latestLocalDelegateAddr, localDelegate, sessionIdentityTjpAddr }; } /** * Executes one sync pass using the delegate keystone as the sender identity. * Always resolves the current delegate tip from the domain identity stored in * debugState, so it is safe to call in sequence across multiple passes. * * @param domainIbGibs - The ibgibs to sync in this pass. * @param passLabel - Label used in devLog messages (e.g. "Pass 1 (Sync C1)"). */ export async function runSyncPass({ domainIbGibs, passLabel, metaspace, space, }: { domainIbGibs: any[]; passLabel: string; metaspace: any; space: any; }): Promise { const domainI = debugState.domainI; const masterSecret = debugState.domainIMasterSecret; if (!domainI || !masterSecret) { throw new Error(`runSyncPass[${passLabel}]: Missing domain identity or secret in debugState. Run Setup first.`); } const domainAddr = getIbGibAddr({ ibGib: domainI }); const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:'; const { senderIdentity, fnSenderSecret } = await getSenderIdentityInfo({ domainI, masterSecret, metaspace, space, }); devLog(`Sync: ${passLabel} — using sender: ${getIbGibAddr({ ibGib: senderIdentity }).slice(0, 40)}...`); const senderPeer = new SyncPeerWebSocketSender_V1({ classname: 'SyncPeerWebSocketSender_V1', httpEvolveUrl: `${location.protocol}//${location.host}/api/keystone/evolve/${encodeURIComponent(domainAddr)}`, wsUrl: `${protocol}//${location.host}/api/sync/ws/${encodeURIComponent(domainAddr)}` }); const coordinator = new SyncSagaCoordinator(); const sagaId = await getUUID(); debugState.sagaId = sagaId; debugState.senderPeer = senderPeer; await senderPeer.initializeOpts({ localMetaspace: metaspace, localSpace: space, senderIdentity, fnSenderSecret, sagaId, sessionConnectPoolConfig: SESSION_KEYSTONE_POLICY.CONNECT_POOL as any, sessionSyncPoolConfig: SESSION_KEYSTONE_POLICY.DEFAULT_POOL as any, targetAddrs: [domainAddr] }); const syncSaga = await coordinator.sync({ domainIbGibs, senderIdentityInfo: { senderIdentity, senderDomainAddr: domainAddr, }, fnSenderSecret, peer: senderPeer, localSpace: space, metaspace, conflictStrategy: SyncConflictStrategy.optimisticWithLCS, }); await syncSaga.done; // After each pass the domain identity may have evolved — refresh debugState const latestDomainAddr = await metaspace.getLatestAddr({ addr: domainAddr, space }); if (latestDomainAddr && latestDomainAddr !== getIbGibAddr({ ibGib: domainI })) { const res = await metaspace.get({ addrs: [latestDomainAddr], space }); if (res.ibGibs?.[0]) { debugState.domainI = res.ibGibs[0] as KeystoneIbGib_V1; } } } /** * Like `runSyncPass` but accepts an explicit space, domainI, and masterSecret. * Use this when syncing from a secondary (e.g., "remote") space that is NOT * the current default local user space. * * After the sync, copies the evolved domain identity tip back to `primarySpace` * (if provided) and updates debugState.domainI. */ export async function runSyncPassFromSpace({ domainIbGibs, passLabel, metaspace, space, primarySpace, domainI, masterSecret, }: { domainIbGibs: any[]; passLabel: string; metaspace: any; space: any; /** If provided, the evolved domain identity is copied back here after sync. */ primarySpace?: any; domainI: KeystoneIbGib_V1; masterSecret: string; }): Promise { const domainAddr = getIbGibAddr({ ibGib: domainI }); const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:'; const { senderIdentity, fnSenderSecret } = await getSenderIdentityInfo({ domainI, masterSecret, metaspace, space, }); devLog(`Sync: ${passLabel} — using sender: ${getIbGibAddr({ ibGib: senderIdentity }).slice(0, 40)}...`); const senderPeer = new SyncPeerWebSocketSender_V1({ classname: 'SyncPeerWebSocketSender_V1', httpEvolveUrl: `${location.protocol}//${location.host}/api/keystone/evolve/${encodeURIComponent(domainAddr)}`, wsUrl: `${protocol}//${location.host}/api/sync/ws/${encodeURIComponent(domainAddr)}` }); const coordinator = new SyncSagaCoordinator(); const sagaId = await getUUID(); debugState.sagaId = sagaId; debugState.senderPeer = senderPeer; await senderPeer.initializeOpts({ localMetaspace: metaspace, localSpace: space, senderIdentity, fnSenderSecret, sagaId, sessionConnectPoolConfig: SESSION_KEYSTONE_POLICY.CONNECT_POOL as any, sessionSyncPoolConfig: SESSION_KEYSTONE_POLICY.DEFAULT_POOL as any, targetAddrs: [domainAddr] }); const syncSaga = await coordinator.sync({ domainIbGibs, senderIdentityInfo: { senderIdentity, senderDomainAddr: domainAddr, }, fnSenderSecret, peer: senderPeer, localSpace: space, metaspace, conflictStrategy: SyncConflictStrategy.optimisticWithLCS, }); await syncSaga.done; // After sync, refresh evolved domain identity const latestDomainAddr = await metaspace.getLatestAddr({ addr: domainAddr, space }); if (latestDomainAddr) { const res = await metaspace.get({ addrs: [latestDomainAddr], space }); const evolved = res.ibGibs?.[0] as KeystoneIbGib_V1 | undefined; if (evolved) { debugState.domainI = evolved; // If a primary space was provided, copy the evolved domain and delegate identities back there if (primarySpace) { await copyIdentitiesToSpace({ domainI: evolved, metaspace, fromSpace: space, toSpace: primarySpace }); } } } } export async function setupDomainAndDelegateIdentities({ masterSecret, syncSalt, manageSalt, metaspace, space, apiBridge, phaseText }: { masterSecret: string; syncSalt: string; manageSalt: string; metaspace: any; space: any; apiBridge: SpaceGibApiBridge; phaseText: string; }): Promise<{ domainI: KeystoneIbGib_V1; delegateKeystone: KeystoneIbGib_V1 }> { const keystoneService = new KeystoneService_V1(); // 1. Create Genesis Domain Keystone (I^Itjp) in local space. // The domain identity only needs a 'manage' pool — the delegate gets 'sync'. const domainI = await keystoneService.genesis({ masterSecret, configs: [ getSpaceGibPoolConfig('manage', manageSalt), ], metaspace, space, frameDetails: { client: 'space-gib-web-dev', timestamp: getTimestamp() } }); devLog(`${phaseText} Setup: ✓ Domain Keystone (I) created locally: ${getIbGibAddr({ ibGib: domainI })}`); devLog(`${phaseText} Setup: Starting postGenesisKeystone...`); // 2. Post Genesis Domain Keystone to receiver/server const resGenesis = await apiBridge.postGenesisKeystone(domainI); if (resGenesis.success) { devLog(`${phaseText} Setup: ✓ Domain Keystone registered and stored on receiver (server).`); } else { devLog(`${phaseText} Setup: X postGenesisKeystone failed: ${resGenesis.message}.`); throw new Error(`${phaseText} Setup: Server rejected genesis domain keystone: ${resGenesis.message}`); } // 3. Generate and register delegate devLog(`${phaseText} Setup: Generating and registering sync delegate...`); const { evolvedDomainI, delegateKeystone } = await createAndRegisterSyncDelegate({ domainI, masterSecret, syncSalt, metaspace, space, apiBridge }); debugState.domainI = evolvedDomainI; debugState.domainIMasterSecret = masterSecret; return { domainI: evolvedDomainI, delegateKeystone }; } export async function verifyIdentitiesOnServer({ localI, metaspace, space, apiBridge, domainAddr }: { localI: KeystoneIbGib_V1; metaspace: any; space: any; apiBridge: SpaceGibApiBridge; domainAddr: string; }): Promise<{ latestLocalIAddr: string; latestLocalDelegateAddr: string; sessionIdentityTjpAddr: string; }> { const latestLocalIAddr = await metaspace.getLatestAddr({ addr: domainAddr, space }); if (!latestLocalIAddr) { throw new Error('Evolved domain keystone tip NOT found in local space!'); } devLog(`✓ Check: Evolved Domain Keystone exists locally.`); const { latestLocalDelegateAddr, sessionIdentityTjpAddr } = await getDelegateAndSessionInfo({ localI, metaspace, space }); if (!latestLocalDelegateAddr) { throw new Error('Evolved delegate keystone tip NOT found in local space!'); } if (!sessionIdentityTjpAddr) { throw new Error('Delegate sync claim does not target a session keystone.'); } devLog(`✓ Check: Delegate Keystone and Sync Claim to Session verified locally.`); const serverDelGetRes = await apiBridge.getIbGib(domainAddr, latestLocalDelegateAddr); if (!serverDelGetRes.success || !serverDelGetRes.ibGib) { throw new Error(`Evolved Delegate Keystone NOT found on server!`); } devLog(`✓ Check: Evolved Delegate Keystone exists on server.`); const serverIGetRes = await apiBridge.getIbGib(domainAddr, latestLocalIAddr); if (!serverIGetRes.success || !serverIGetRes.ibGib) { throw new Error(`Evolved Domain Keystone NOT found on server!`); } devLog(`✓ Check: Evolved Domain Keystone exists on server.`); return { latestLocalIAddr, latestLocalDelegateAddr, sessionIdentityTjpAddr }; } export async function copyIdentitiesToSpace({ domainI, metaspace, fromSpace, toSpace }: { domainI: KeystoneIbGib_V1; metaspace: any; fromSpace: any; toSpace: any; }): Promise { const domainAddr = getIbGibAddr({ ibGib: domainI }); // 1. Get latest Domain I and its graph, put and register const latestDomainAddr = await metaspace.getLatestAddr({ addr: domainAddr, space: fromSpace }); if (!latestDomainAddr) { throw new Error("Could not find latest domain I address."); } const resDomain = await metaspace.get({ addrs: [latestDomainAddr], space: fromSpace }); const latestDomainI = resDomain.ibGibs?.[0] as KeystoneIbGib_V1 | undefined; if (!latestDomainI) { throw new Error("Could not get latest domain I."); } const graphI = await metaspace.getDependencyGraph({ ibGibAddr: latestDomainAddr, space: fromSpace }); await metaspace.put({ ibGibs: Object.values(graphI), space: toSpace }); await metaspace.registerNewIbGib({ ibGib: latestDomainI, space: toSpace }); // 2. Find and copy delegate(s) const syncDelegateEntry = Object.values(latestDomainI.data?.delegates ?? {}).find( d => d.allowedVerbs?.includes(KEYSTONE_VERB_SYNC) ); if (syncDelegateEntry) { const delegateTjpAddr = syncDelegateEntry.delegateTjpAddr; if (delegateTjpAddr) { const latestDelegateAddr = await metaspace.getLatestAddr({ addr: delegateTjpAddr, space: fromSpace }); if (latestDelegateAddr) { const resDel = await metaspace.get({ addrs: [latestDelegateAddr], space: fromSpace }); const latestDelegate = resDel.ibGibs?.[0] as KeystoneIbGib_V1 | undefined; if (latestDelegate) { const graphDel = await metaspace.getDependencyGraph({ ibGibAddr: latestDelegateAddr, space: fromSpace }); await metaspace.put({ ibGibs: Object.values(graphDel), space: toSpace }); await metaspace.registerNewIbGib({ ibGib: latestDelegate, space: toSpace }); } } } } }