import { readdirSync } from "node:fs"; import path from "node:path"; export interface RouterContext { agentId: string; } export interface RouterModule { resolve(ctx: RouterContext): string | Promise; } export interface LoadedRouter { name: string; filePath: string; module: RouterModule; } const _G = globalThis as Record; const ROUTERS_KEY = "_prismFacetRouters"; const LOAD_COUNTER_KEY = "_prismFacetLoadCounter"; function getRouterMap(): Map { if (!(_G[ROUTERS_KEY] instanceof Map)) { _G[ROUTERS_KEY] = new Map(); } return _G[ROUTERS_KEY] as Map; } function routerNameFromFile(filename: string): string { return filename.replace(/\.(ts|js|mjs)$/, ""); } export async function loadRouters( routersDir: string, log: { info(msg: string): void; warn(msg: string): void } ): Promise { const map = getRouterMap(); map.clear(); if (typeof _G[LOAD_COUNTER_KEY] !== "number") _G[LOAD_COUNTER_KEY] = 0; (_G[LOAD_COUNTER_KEY] as number)++; const counter = _G[LOAD_COUNTER_KEY] as number; let files: string[]; try { files = readdirSync(routersDir).filter( (f) => /\.(ts|js|mjs)$/.test(f) && !f.startsWith(".") ); } catch { log.warn(`[prism-facet] routers directory not found: ${routersDir}`); return; } for (const file of files) { const name = routerNameFromFile(file); const filePath = path.resolve(routersDir, file); try { const mod = (await import(`${filePath}?v=${counter}`)) as RouterModule; if (typeof mod.resolve !== "function") { log.warn(`[prism-facet] router ${name}: no resolve() export, skipping`); continue; } map.set(name, { name, filePath, module: mod }); log.info(`[prism-facet] router loaded: ${name}`); } catch (err) { log.warn(`[prism-facet] router ${name}: failed to load — ${String(err)}`); } } } export function getRouters(): LoadedRouter[] { return Array.from(getRouterMap().values()); } export function getRouterNames(): string[] { return Array.from(getRouterMap().keys()); }