scripts/lib/built-config.ts
Rama main · réplica de lectura del repositorio original.
/**
* The IO half of `deploy-config.ts`: read the tracked config, the generated
* overlay (if any) and the built `dist/server/wrangler.json`, apply the overlay,
* write it back, and re-read it to prove the file wrangler will deploy carries
* every generated-owned value.
*
* Shared by `pnpm run deploy[:dev]` (scripts/deploy.ts), `setup:domain` and
* `setup:cloud`, so there is exactly one way a generated file reaches a deploy.
*/
import { existsSync, readFileSync, writeFileSync } from "node:fs";
import {
applyGeneratedOverlay,
effectiveBlock,
findOverlayMismatches,
GENERATED_OWNED_FIELDS,
type OverlayResult,
stripJsonc,
type WranglerBlock,
type WranglerConfig,
} from "./deploy-config";
export const BUILT_CONFIG_PATH = "dist/server/wrangler.json";
export const TRACKED_CONFIG_PATH = "wrangler.jsonc";
export function generatedConfigPathFor(env: string | undefined): string {
return `wrangler.generated.${env ?? "production"}.json`;
}
export function readTrackedConfig(): WranglerConfig {
return JSON.parse(stripJsonc(readFileSync(TRACKED_CONFIG_PATH, "utf8"))) as WranglerConfig;
}
export function readGeneratedConfig(env: string | undefined): WranglerConfig | undefined {
const path = generatedConfigPathFor(env);
if (!existsSync(path)) return undefined;
return JSON.parse(stripJsonc(readFileSync(path, "utf8"))) as WranglerConfig;
}
function show(value: unknown): string {
return value === undefined ? "(unset)" : JSON.stringify(value);
}
/** Prints what the overlay did, in the same shape for every caller. */
export function printOverlayReport(result: OverlayResult, generatedPath: string): void {
if (result.applied.length === 0) {
console.log(` ${generatedPath} adds nothing the tracked config does not already ship.`);
} else {
console.log(` From ${generatedPath} (generated wins for the fields it owns):`);
for (const change of result.applied) {
console.log(` ${change.field}: ${show(change.from)} -> ${show(change.to)}`);
}
}
if (result.ignored.length > 0) {
console.log(
` Ignored in ${generatedPath} (wrangler.jsonc owns these, so its value deploys):\n` +
result.ignored.map((field) => ` ${field}`).join("\n"),
);
}
}
/**
* Patches the built Worker config in place. Throws — never warns — when the
* re-read file does not carry the generated values, or when the build targets a
* different Worker than the tracked config names: a deploy that ships something
* other than what it just printed is the exact silent drift this replaces.
*/
export function patchBuiltConfig(env: string | undefined): OverlayResult | null {
const generatedPath = generatedConfigPathFor(env);
const tracked = effectiveBlock(readTrackedConfig(), env);
const built = JSON.parse(readFileSync(BUILT_CONFIG_PATH, "utf8")) as WranglerBlock;
if (tracked.name && built.name !== tracked.name) {
throw new Error(
`${BUILT_CONFIG_PATH} targets Worker "${built.name}", but ${TRACKED_CONFIG_PATH} names "${tracked.name}" for ${env ? `env "${env}"` : "the top level"}. ` +
`Rebuild with ${env ? `CLOUDFLARE_ENV=${env} ` : ""}pnpm run build.`,
);
}
const generatedConfig = readGeneratedConfig(env);
console.log(`\n▸ Overlay generated config onto the build\n target: ${BUILT_CONFIG_PATH}`);
if (!generatedConfig) {
console.log(` ${generatedPath} not found — deploying the tracked config exactly as built.`);
return null;
}
const generated = effectiveBlock(generatedConfig, env);
const result = applyGeneratedOverlay({ base: built, generated, tracked });
printOverlayReport(result, generatedPath);
writeFileSync(BUILT_CONFIG_PATH, `${JSON.stringify(result.config, null, 2)}\n`);
const reread = JSON.parse(readFileSync(BUILT_CONFIG_PATH, "utf8")) as WranglerBlock;
const mismatches = findOverlayMismatches(reread, generated);
if (mismatches.length > 0) {
throw new Error(
`${BUILT_CONFIG_PATH} does not carry what ${generatedPath} declares:\n ${mismatches.join("\n ")}\n` +
`Owned fields: ${GENERATED_OWNED_FIELDS.join("; ")}.`,
);
}
console.log(` Verified: ${BUILT_CONFIG_PATH} carries every value ${generatedPath} owns.`);
return result;
}