import { type SecretReader, type HydrateReport } from './env'; import { type FzConfig } from './config'; /** Tests, and a process that has genuinely rotated its own credential. */ export declare const resetHydration: () => void; export interface SetupOptions { /** Pre-loaded config. Omit to find `.fz/config.json` by walking up. */ config?: FzConfig; vault: SecretReader; cwd?: string; readFile?: (path: string) => string | undefined; env?: Record; /** Defaults to a single line naming counts and variable names, never values. */ log?: (line: string) => void; onReport?: (report: HydrateReport) => void; } /** * Hydrate exactly once per process, whoever asks first. * * The memo is on the PROMISE, not on a completed flag: two requests arriving * during startup would otherwise both see "not done yet" and both fetch. */ export declare function setupEnv(options: SetupOptions): Promise; export interface SvelteKitHandleEvent { event: unknown; resolve: (event: unknown) => unknown; } /** * A SvelteKit `handle` hook. * * // src/hooks.server.ts * import { forgeZeroHandle } from '@forgezero/vault/frameworks'; * import { createVault } from '@forgezero/vault'; * import { readFileSync, existsSync } from 'node:fs'; * * export const handle = forgeZeroHandle({ * vault: createVault(), * readFile: (path) => (existsSync(path) ? readFileSync(path, 'utf8') : undefined) * }); * * Compose it with `sequence()` if you already have hooks — it must come FIRST, * because everything after it expects the environment to be populated. * * Read secrets through `$env/dynamic/private`, never `$env/static/private`. The * static form is substituted at build and the value ends up in a file on disk; * the dynamic form reads `process.env` at request time, which is what this * fills. */ export declare function forgeZeroHandle(options: SetupOptions): ({ event, resolve }: SvelteKitHandleEvent) => Promise; /** * A SvelteKit `init` hook, for versions that have one. * * Better than `handle` where available: it runs before the first request rather * than during it, so a missing secret fails the server at start instead of * turning the first visitor into the person who discovers it. */ export declare function forgeZeroInit(options: SetupOptions): () => Promise; /** * A Next.js instrumentation hook. * * // instrumentation.ts * import { forgeZeroRegister } from '@forgezero/vault/frameworks'; * import { createVault } from '@forgezero/vault'; * import { readFileSync, existsSync } from 'node:fs'; * * export const register = forgeZeroRegister({ * vault: createVault(), * readFile: (path) => (existsSync(path) ? readFileSync(path, 'utf8') : undefined) * }); * * `instrumentation.ts` is the only place Next.js runs code once per server * process before any request. Do NOT use the `env` block in `next.config.js`: * it is substituted at build time and, for anything a client component touches, * substituted into the CLIENT bundle. * * The guard below is why this is not just a re-export of `setupEnv`. Next runs * `register` in the edge runtime too, where there is no filesystem and no vault * socket — hydrating there would fail the whole build with an error pointing at * the wrong thing entirely. */ export declare function forgeZeroRegister(options: SetupOptions): () => Promise; /** * For a plain Bun or Node process, before anything else imports. * * await bootstrapEnv({ vault: createVault(), readFile }); * const { start } = await import('./server'); * * The dynamic import is the point: a top-level `import './server'` is hoisted * above this call, so the server module would read `process.env` before it was * filled. That ordering trap is subtle enough to be worth the example. */ export declare function bootstrapEnv(options: SetupOptions): Promise;