/** * Dependency-integrity gate for infrastructure declaration folders. * * CDK executes the customer's app (npx tsx infrastructure.ts) in the * declaration dir, and Node resolves imports by walking ANCESTOR * directories whenever the local node_modules is missing or incomplete - * silently synthesising against stale or wrong packages. Two real * incidents drive the check: a missing local install resolved a stray * ancestor copy and silently dropped resources from the template (I1), and * a node_modules older than the lockfile pin broke the synth (I2). The * gate therefore verifies that every DECLARED dependency is satisfied * locally before any CDK child is spawned, auto-heals with npm when it is * not, re-verifies, and fails closed when the tree still cannot be * trusted. * * The check is satisfaction-based, not manager-based: a correct tree * passes untouched regardless of which package manager produced it * (existsSync follows symlinks, so pnpm/yarn layouts pass), and a dir an * ancestor manifest DECLARES as a workspace member may satisfy deps from * that workspace root - explicit membership is the hoist contract, not the * stray-ancestor hazard. There is deliberately no opt-out - if the * declared dependencies are unsatisfiable the synth WOULD be wrong, so * there is nothing legitimate to skip. */ import { type ChildEnvPolicy } from "@fjall/util"; import type { Result } from "@fjall/generator"; /** Timeout for the dependency sync (5 minutes). */ export declare const DEPENDENCY_SYNC_TIMEOUT_MS: number; export interface EnsureDependencyIntegrityOptions { /** * How this spawn inherits the caller's environment. REQUIRED — see * `DeployParams.childEnvPolicy`. This spawn executes the customer's `npm` install scripts, so under * `isolate` it must not see the caller's secrets. */ childEnvPolicy: ChildEnvPolicy; onOutput?: (chunk: string) => void; abortSignal?: AbortSignal; } /** * "skipped" is minted only by callers that bypass the gate entirely * (skipProjectCheck-style paths with no declaration folder to verify); * ensureDependencyIntegrity itself never returns it. */ export type DependencyIntegrityStatus = "satisfied" | "installed" | "skipped"; export interface DependencyIntegrityOutcome { status: DependencyIntegrityStatus; /** * Pre-masked notes for pin comparisons the verification SKIPPED (installed * manifest present but unreadable, or carrying no usable version). Carried * in the outcome - not emitted here - so cache-hit re-entries repeat them; * each caller owns the rendering for its own surface. */ warnings: string[]; } export declare function clearDependencyIntegrityCache(): void; /** * Verify (and if needed heal) the declaration folder's dependency tree. * * Fails closed on: missing/unparseable package.json (the documented * ancestor-resolution hole), unparseable package-lock.json, an npm sync * that fails, and a tree still unsatisfied after a successful sync. * Memoised per real path for the life of the process; failures are not * cached. */ export declare function ensureDependencyIntegrity(path: string, options: EnsureDependencyIntegrityOptions): Promise>;