Files
erika/lib/config/environment.ts
T

53 lines
1.5 KiB
TypeScript

import { z } from "zod";
const nonEmptyString = z.string().trim().min(1);
const urlString = z.url();
export type Environment = Record<string, string | undefined>;
export function requiredEnvironmentValue(
name: string,
environment: Environment = process.env,
) {
const parsed = nonEmptyString.safeParse(environment[name]);
if (!parsed.success) {
throw new Error(`Missing required environment variable: ${name}`);
}
return parsed.data;
}
export function optionalEnvironmentValue(
name: string,
environment: Environment = process.env,
) {
const parsed = nonEmptyString.safeParse(environment[name]);
return parsed.success ? parsed.data : null;
}
export function requiredEnvironmentUrl(
name: string,
environment: Environment = process.env,
) {
const value = requiredEnvironmentValue(name, environment);
const parsed = urlString.safeParse(value);
if (!parsed.success) {
throw new Error(`Environment variable ${name} must be an absolute URL`);
}
return parsed.data.replace(/\/$/, "");
}
export function readFeatureEnvironment<Names extends readonly string[]>(
feature: string,
names: Names,
environment: Environment = process.env,
): { [Name in Names[number]]: string } {
try {
return Object.fromEntries(
names.map((name) => [name, requiredEnvironmentValue(name, environment)]),
) as { [Name in Names[number]]: string };
} catch (error) {
const message = error instanceof Error ? error.message : "Invalid configuration";
throw new Error(`${feature} is not configured: ${message}`, { cause: error });
}
}