final touches for beta skymoney (at least i think)

This commit is contained in:
2026-01-18 00:00:44 -06:00
parent 4eae966f96
commit f4f0ae5df2
161 changed files with 26016 additions and 1966 deletions

View File

@@ -1,26 +1,62 @@
// api/src/env.ts
import { z } from "zod";
const BoolFromEnv = z
.union([z.boolean(), z.string()])
.transform((val) => {
if (typeof val === "boolean") return val;
const normalized = val.trim().toLowerCase();
return normalized === "true" || normalized === "1";
});
const Env = z.object({
NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
PORT: z.coerce.number().int().positive().default(8080),
HOST: z.string().default("0.0.0.0"),
DATABASE_URL: z.string().min(1),
// Comma-separated list of allowed origins; empty => allow all (dev)
CORS_ORIGIN: z.string().optional(),
// 🔹 New: rate-limit knobs (have defaults so typing is happy)
RATE_LIMIT_MAX: z.coerce.number().int().positive().default(200),
RATE_LIMIT_WINDOW_MS: z.coerce.number().int().positive().default(60_000),
JWT_SECRET: z.string().min(32),
COOKIE_SECRET: z.string().min(32),
COOKIE_DOMAIN: z.string().optional(),
AUTH_DISABLED: BoolFromEnv.optional().default(false),
SEED_DEFAULT_BUDGET: BoolFromEnv.default(true),
SESSION_TIMEOUT_MINUTES: z.coerce.number().int().positive().default(30),
});
export const env = Env.parse({
const rawEnv = {
NODE_ENV: process.env.NODE_ENV,
PORT: process.env.PORT,
HOST: process.env.HOST,
DATABASE_URL: process.env.DATABASE_URL,
CORS_ORIGIN: "http://localhost:5173,http://127.0.0.1:5173",
CORS_ORIGIN: process.env.CORS_ORIGIN,
RATE_LIMIT_MAX: process.env.RATE_LIMIT_MAX,
RATE_LIMIT_WINDOW_MS: process.env.RATE_LIMIT_WINDOW_MS,
});
JWT_SECRET: process.env.JWT_SECRET ?? "dev-jwt-secret-change-me",
COOKIE_SECRET: process.env.COOKIE_SECRET ?? "dev-cookie-secret-change-me",
COOKIE_DOMAIN: process.env.COOKIE_DOMAIN,
AUTH_DISABLED: process.env.AUTH_DISABLED,
SEED_DEFAULT_BUDGET: process.env.SEED_DEFAULT_BUDGET,
};
const parsed = Env.parse(rawEnv);
if (parsed.NODE_ENV === "production") {
if (!parsed.CORS_ORIGIN) {
throw new Error("CORS_ORIGIN must be set in production.");
}
if (rawEnv.AUTH_DISABLED && parsed.AUTH_DISABLED) {
throw new Error("AUTH_DISABLED cannot be enabled in production.");
}
if (parsed.SEED_DEFAULT_BUDGET) {
throw new Error("SEED_DEFAULT_BUDGET must be disabled in production.");
}
if (parsed.JWT_SECRET.includes("dev-jwt-secret-change-me")) {
throw new Error("JWT_SECRET must be set to a strong value in production.");
}
if (parsed.COOKIE_SECRET.includes("dev-cookie-secret-change-me")) {
throw new Error("COOKIE_SECRET must be set to a strong value in production.");
}
}
export const env = parsed;