/** * WWW + managed Holesail + swarm chat initd units — registered and started only after identity unlock, * stopped on logout. Guest boot skips this stack entirely. */ import { findBareServiceDefinition, startBareService, stopBareService } from './bare-initd.js' import { maybeRegisterBareHolesailInitd } from './bare-holesail.js' import { maybeRegisterBareOsChatInitd } from './bare-os-chat-initd.js' import { maybeRegisterBareOsWwwInitd } from './bare-os-www-initd.js' import { maybeStartBareOsDiscordAfterIdentity, stopBareOsDiscordInitd } from './bare-os-discord-initd.js' import { bareOpensshGetListenEndpoint } from './bare-openssh.js' import { ensureBareOsSshHolesailTunnel } from './bare-os-ssh-holesail.js' import { bareOsChatMuxEnabled, ensureDiskBareOsChatTransport } from './bare-os-chat-service.js' import { bareOsMeshdropMuxEnabled, ensureDiskBareOsMeshdropTransport } from './bare-os-meshdrop-service.js' /** @param {Record} env */ export function registerBareUserSessionStackUnits(env) { maybeRegisterBareHolesailInitd(env) maybeRegisterBareOsWwwInitd(env) maybeRegisterBareOsChatInitd(env) } /** * Idempotent: registers units once, attaches chat service to `ctx.disk` when mux is enabled, then starts * **bare-os-www** → **bare-holesail** → **bare-os-chat** (initd DAG order). * @param {Record} ctx */ export async function startBareUserSessionStack(ctx) { const env = ctx.env && typeof ctx.env === 'object' ? /** @type {Record} */ (ctx.env) : /** @type {Record} */ ({}) registerBareUserSessionStackUnits(env) const disk = /** @type {{ bareOsChatService?: unknown }} */ (ctx.disk) if (disk && bareOsChatMuxEnabled(globalThis.process?.env)) { ensureDiskBareOsChatTransport( /** @type {import('./swarm-disk.js').SwarmDisk} */ (disk), env ) } if (disk && bareOsMeshdropMuxEnabled(globalThis.process?.env)) { ensureDiskBareOsMeshdropTransport( /** @type {import('./swarm-disk.js').SwarmDisk} */ (disk), env ) } /** Peers may have connected during guest boot; pair chat after this tick (avoid mux re-entrancy). */ if (disk && typeof disk.pairBareOsChatExistingPeers === 'function') { await new Promise((r) => setImmediate(r)) disk.pairBareOsChatExistingPeers() } if (disk && typeof disk.pairBareOsMeshdropExistingPeers === 'function') { await new Promise((r) => setImmediate(r)) disk.pairBareOsMeshdropExistingPeers() } await maybeStartBareOsDiscordAfterIdentity(ctx) const order = ['bare-os-www', 'bare-holesail', 'bare-os-chat'] for (const name of order) { if (!findBareServiceDefinition(name)) continue try { await startBareService(ctx, name) } catch (e) { const msg = (e && /** @type {{ message?: string }} */ (e).message) || String(e) try { ctx.console?.error?.(`[bare-user-stack] start ${name}: ${msg}`) } catch { /* ignore */ } } } /** bare-openssh may already be listening from guest boot — run managed tunnel ensure after holesail is up. */ try { const ep = bareOpensshGetListenEndpoint() if (ep) await ensureBareOsSshHolesailTunnel(ctx, env, ep.port, ep.host) } catch (e) { const msg = (e && /** @type {{ message?: string }} */ (e).message) || String(e) try { ctx.console?.error?.(`[bare-user-stack] ssh holesail ensure: ${msg}`) } catch { /* ignore */ } } } /** * Stops **bare-holesail** (before www so the tunnel drops first), **bare-os-www**, **bare-os-chat**. * Swarm chat **transport** (`disk.bareOsChatService`) stays; `logoutIdentity` refreshes it for guest. * @param {Record} ctx */ export async function stopBareUserSessionStack(ctx) { await stopBareOsDiscordInitd(ctx) const order = ['bare-holesail', 'bare-os-www', 'bare-os-chat'] for (const name of order) { if (!findBareServiceDefinition(name)) continue try { await stopBareService(ctx, name) } catch (e) { const msg = (e && /** @type {{ message?: string }} */ (e).message) || String(e) try { ctx.console?.error?.(`[bare-user-stack] stop ${name}: ${msg}`) } catch { /* ignore */ } } } }