import { runTransactionalLifecycleHooks } from './bare-os-lifecycle-manager.js' /** * Host lifecycle: when Corestore / Hyperswarm expose `suspend`/`resume`, wire them into * `ctx.bareOsInvokeSuspendHooks` / `ctx.bareOsInvokeResumeHooks` (mobile sleep, etc.). */ /** @type {{ store: unknown, swarm: unknown } | null} */ let pendingPair = null /** * Called once from main() with live instances; hooks install on first guest ctx. * @param {unknown} store * @param {unknown} swarm */ export function bareOsRegisterCorestoreSuspendResumeHooks(store, swarm) { pendingPair = { store, swarm } } /** * Corestore 7.12+ no longer flushes on `suspend()`. Flush open sessions first * so in-memory tree/blocks hit storage before the RocksDB handle sleeps. * @param {unknown} store */ async function flushCorestoreSessions(store) { if (!store || typeof store !== 'object') return const sessions = /** @type {{ sessions?: Iterable }} */ (store) .sessions if (!sessions || typeof sessions[Symbol.iterator] !== 'function') return /** @type {Promise[]} */ const pending = [] for (const sess of sessions) { if (!sess || typeof sess !== 'object') continue const flush = /** @type {{ flush?: () => unknown }} */ (sess).flush if (typeof flush === 'function') pending.push(Promise.resolve(flush.call(sess))) } if (pending.length) await Promise.all(pending) } /** * @param {unknown} target * @param {string} label */ async function callSuspendResume(target, label) { if (!target || typeof target !== 'object') return if (label === 'suspend') await flushCorestoreSessions(target) const o = /** @type {{ suspend?: () => unknown, resume?: () => unknown }} */ ( target ) const fn = label === 'suspend' ? o.suspend : o.resume if (typeof fn !== 'function') return await Promise.resolve(fn.call(target)) } /** * @param {{ bareOsRegisterSuspendHook: (fn: () => void | Promise) => unknown, bareOsRegisterResumeHook: (fn: () => void | Promise) => unknown }} ctx */ export function bareOsInstallCorestoreSuspendResumeHooks(ctx) { if (!pendingPair) return const { store, swarm } = pendingPair ctx.bareOsRegisterSuspendHook(async () => { const rep = await runTransactionalLifecycleHooks([ { name: 'corestore.suspend', run: () => callSuspendResume(store, 'suspend') }, { name: 'swarm.suspend', run: () => callSuspendResume(swarm, 'suspend') } ]) if (!rep.ok) throw new Error('bare-os suspend hook transaction failed') }) ctx.bareOsRegisterResumeHook(async () => { const rep = await runTransactionalLifecycleHooks([ { name: 'swarm.resume', run: () => callSuspendResume(swarm, 'resume') }, { name: 'corestore.resume', run: () => callSuspendResume(store, 'resume') } ]) if (!rep.ok) throw new Error('bare-os resume hook transaction failed') }) } /** * Non-secret operator hint for integrating **`corestore-snapshot`** on the host. * @param {unknown} store */ export function bareOsCorestoreSnapshotOperatorHint(store) { const env = globalThis.process?.env const snapRaw = String(env?.BARE_OS_CORESTORE_SNAPSHOT_JSON || '').trim() const statsRaw = String(env?.BARE_OS_CORESTORE_STATS_JSON || '').trim() let snapshotKeyCount = null let statsNamespaceCount = null if (snapRaw) { try { const s = JSON.parse(snapRaw) if (s && typeof s === 'object') { if (Array.isArray(s.handles)) snapshotKeyCount = s.handles.length else if (Array.isArray(s.keys)) snapshotKeyCount = s.keys.length } } catch { snapshotKeyCount = -1 } } if (statsRaw) { try { const st = JSON.parse(statsRaw) if (st && typeof st === 'object' && Array.isArray(st.namespaces)) statsNamespaceCount = st.namespaces.length } catch { statsNamespaceCount = -1 } } return { schema: 4, note: 'Wire the holepunch corestore-snapshot package on the host; guests receive this descriptor only. Schema 4 adds recommendedWorkflow; schema 3 adds merge hints when BARE_OS_CORESTORE_SNAPSHOT_JSON and BARE_OS_CORESTORE_STATS_JSON parse.', corestoreSnapshotPackage: 'corestore-snapshot', recommendedWorkflow: [ 'Run corestore-snapshot (holepunchto/corestore-snapshot) on the host store.', 'Export JSON into BARE_OS_CORESTORE_SNAPSHOT_JSON and pair BARE_OS_CORESTORE_STATS_JSON for operator diff UX.', 'Use replication_operator_sketch.corestoreSnapshotUxHint counts in /proc and disk.os RPC.' ], hasLiveStore: !!(store && typeof store === 'object'), guestSuspendResume: 'ENOTSUP', guestSuspendResumeNote: 'Kernel guests do not call store.suspend() directly; booter wires hooks when the runtime exposes suspend/resume.', corestoreSnapshotEnvPresent: !!snapRaw, corestoreStatsEnvPresent: !!statsRaw, snapshotManifestKeyCount: snapshotKeyCount, statsNamespacesCount: statsNamespaceCount, atMs: Date.now() } }