import { existsSync, readFileSync } from "node:fs"; import { join, resolve } from "node:path"; interface ExplainRoute { kind: "page" | "api" | "realtime"; path: string; source: string; execution: string; canPrerender: boolean; needsClientRuntime: boolean; needsServerRuntime: boolean; hydrationStrategy: string | null; reasons?: string[]; cachePolicy?: Record; requiredPermission?: string | null; } interface ExplainReport { frameworkVersion: string; adapter: string; routes: ExplainRoute[]; assets: Array<{ file: string; bytes: number }>; measurements: Record; budgetViolations: Array<{ metric: string; budget: number; actual: number }>; } export interface Explanation { target: string; subject: string; summary: string; reasons: string[]; evidence: Record; } function loadReport(root: string): ExplainReport { const path = join(resolve(root), "dist", "build-report.json"); if (!existsSync(path)) { throw new Error( "WRN-EXPLAIN-NO-BUILD: run `wrnexus build` before requesting build explanations.", ); } return JSON.parse(readFileSync(path, "utf8")) as ExplainReport; } function routeMatch(routes: ExplainRoute[], subject: string): ExplainRoute | undefined { const normalized = subject.startsWith("/") ? subject : `/${subject}`; return routes.find((route) => route.path === normalized || route.source.includes(subject)); } export function explainBuildDecision(root: string, target: string, subject = ""): Explanation { const report = loadReport(root); if ( target === "route" || target === "hydration" || target === "cache" || target === "permission" ) { const route = target === "permission" ? report.routes.find((item) => item.requiredPermission === subject) : routeMatch(report.routes, subject); if (!route) throw new Error(`WRN-EXPLAIN-NOT-FOUND: no route or source matches '${subject}'.`); if (target === "cache") { const policy = route.cachePolicy ?? {}; const entries = Object.entries(policy); return { target, subject: route.path, summary: entries.length ? `Route cache uses '${policy.strategy ?? "framework-default"}' strategy.` : "Route has no explicit cache policy and uses safe framework defaults.", reasons: entries.length ? entries.map(([name, value]) => `${name} = ${value}`) : ["responses remain private/revalidated unless an explicit safe policy enables reuse"], evidence: { source: route.source, cachePolicy: policy, execution: route.execution }, }; } if (target === "permission") { const requested = subject.startsWith("/") ? undefined : subject; const matches = report.routes.filter((item) => requested ? item.requiredPermission === requested : item.path === route.path, ); return { target, subject: requested ?? route.path, summary: matches.length ? `${matches.length} route(s) require this permission.` : "No built route declares this permission.", reasons: matches.length ? matches.map((item) => `${item.path} declares security.permission in ${item.source}`) : ["authorization may still be enforced programmatically; inspect authz policies"], evidence: { routes: matches }, }; } const reasons = route.reasons?.length ? route.reasons : ["no dynamic requirement was detected"]; return { target, subject: route.path, summary: target === "hydration" ? route.needsClientRuntime ? `Hydration uses '${route.hydrationStrategy ?? "load"}' because client runtime is required.` : "Hydration is omitted because no client runtime is required." : `Route execution is '${route.execution}'${route.canPrerender ? " and can prerender" : " and cannot prerender"}.`, reasons, evidence: { ...route }, }; } if (target === "bundle") { const assets = [...report.assets].sort((a, b) => b.bytes - a.bytes); return { target, subject: subject || "production bundle", summary: `${assets.length} emitted assets; largest is ${assets[0]?.file ?? "none"}.`, reasons: assets.slice(0, 10).map((asset) => `${asset.file}: ${asset.bytes} bytes`), evidence: { measurements: report.measurements, largestAssets: assets.slice(0, 10) }, }; } if (target === "build") { return { target, subject: "production build", summary: `${report.routes.length} routes target the ${report.adapter} adapter.`, reasons: report.budgetViolations.length ? report.budgetViolations.map( (item) => `${item.metric} exceeds ${item.budget} with ${item.actual}`, ) : ["all configured performance budgets pass"], evidence: { frameworkVersion: report.frameworkVersion, adapter: report.adapter, measurements: report.measurements, }, }; } throw new Error(`WRN-EXPLAIN-TARGET: unsupported target '${target}'.`); } export function runExplain(root: string, target: string, subject: string, args: string[]): void { const explanation = explainBuildDecision(root, target, subject); if (args.includes("--json")) { console.log(JSON.stringify(explanation, null, 2)); return; } console.log(explanation.summary); explanation.reasons.forEach((reason, index) => console.log(` ${index + 1}. ${reason}`)); }