yiekheng 6893ca6ba9 fix(web): lazy-parse env so docker build doesn't crash on missing DATABASE_URL
`scripts/publish.sh` failed during the web image build at
"Collecting page data" with:
  ZodError: DATABASE_URL: Required

next build walks every route module including api/events/route.ts,
which imports env from @/env. The previous shape ran
envSchema.parse(process.env) at module top level, so the parse fired
inside the build container where DATABASE_URL deliberately isn't set.

Wrap the parse in a Proxy that resolves on first property access.
The build's page-data pass doesn't read any env property, so the
parse never runs at build time. Runtime callers (db.ts, media.ts,
api/events/route.ts) hit the proxy on first use and get the same
strict Zod validation as before.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 22:13:30 +08:00

33 lines
1.2 KiB
TypeScript

import { z } from "zod";
const envSchema = z.object({
DATABASE_URL: z.string().url(),
DATA_DIR: z.string().min(1).default("/data"),
MEDIA_DIR: z.string().min(1).default("/data/media"),
WEB_PORT: z.string().regex(/^\d+$/).transform((s) => Number(s)).default("3000"),
});
export type Env = z.infer<typeof envSchema>;
// Lazy parse via Proxy. Next.js's `next build` does a
// "Collecting page data" pass that imports every route module —
// including api/events/route.ts which depends on this env. With a
// top-level `envSchema.parse(process.env)` the parse ran during
// the build container, where DATABASE_URL isn't (and shouldn't be)
// set, and Zod aborted the build with:
// ZodError: DATABASE_URL: Required
// Deferring the parse until first property access lets the build
// finish (no consumer accesses env during page-data collection)
// while still failing loudly at runtime if the var is missing.
let cached: Env | null = null;
function read(): Env {
if (cached) return cached;
cached = envSchema.parse(process.env);
return cached;
}
export const env: Env = new Proxy({} as Env, {
get(_t, prop) {
return read()[prop as keyof Env];
},
}) as Env;