krona-staff/src/config.ts

36 lines
1.5 KiB
TypeScript

import { z } from 'zod';
const configSchema = z.object({
NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),
PORT: z.coerce.number().int().min(1).max(65535).default(8080),
LOG_LEVEL: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace', 'silent']).default('info'),
STAFF_RUNTIME_MODE: z.enum(['standalone', 'platform']).default('standalone'),
DATABASE_URL: z.string().url(),
REDIS_URL: z.string().url().optional(),
PLATFORM_GATEWAY_URL: z.string().url().optional(),
PLATFORM_JWT_ISSUER: z.string().url().optional(),
PLATFORM_JWT_AUDIENCE: z.string().optional(),
PLATFORM_JWKS_URL: z.string().url().optional(),
STANDALONE_TENANT_ID: z.string().regex(/^[0-9A-HJKMNP-TV-Z]{26}$/),
STANDALONE_ACTOR_ID: z.string().regex(/^[0-9A-HJKMNP-TV-Z]{26}$/),
});
export type AppConfig = z.infer<typeof configSchema>;
export function loadConfig(env: NodeJS.ProcessEnv = process.env): AppConfig {
const config = configSchema.parse(env);
if (config.NODE_ENV === 'production' && config.STAFF_RUNTIME_MODE === 'standalone') {
throw new Error('STAFF_RUNTIME_MODE=standalone is not allowed in production');
}
if (config.STAFF_RUNTIME_MODE === 'platform') {
const required = [
'PLATFORM_GATEWAY_URL',
'PLATFORM_JWT_ISSUER',
'PLATFORM_JWT_AUDIENCE',
'PLATFORM_JWKS_URL',
] as const;
for (const key of required)
if (!config[key]) throw new Error(`${key} is required in platform mode`);
}
return config;
}