84 lines
2.5 KiB
TypeScript
84 lines
2.5 KiB
TypeScript
import { resolve } from "node:path";
|
|
|
|
export interface Config {
|
|
host: string;
|
|
port: number;
|
|
storageDir: string;
|
|
maxFileSize: number;
|
|
fileTtlMs: number;
|
|
rateLimitEnabled: boolean;
|
|
rateLimitMax: number;
|
|
rateLimitWindowMs: number;
|
|
trustProxy: boolean;
|
|
}
|
|
|
|
const DEFAULT_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 1 week
|
|
|
|
const SIZE_UNITS: Record<string, number> = {
|
|
B: 1,
|
|
K: 1 << 10,
|
|
KB: 1 << 10,
|
|
KIB: 1 << 10,
|
|
M: 1 << 20,
|
|
MB: 1 << 20,
|
|
MIB: 1 << 20,
|
|
G: 1 << 30,
|
|
GB: 1 << 30,
|
|
GIB: 1 << 30,
|
|
T: 1 << 40,
|
|
TB: 1 << 40,
|
|
TIB: 1 << 40,
|
|
};
|
|
|
|
export function parseSize(value: string): number {
|
|
const match = /^\s*(\d+(?:\.\d+)?)\s*([A-Za-z]*)\s*$/.exec(value);
|
|
if (!match) throw new Error(`Invalid size value: "${value}"`);
|
|
const num = parseFloat(match[1]!);
|
|
const unit = (match[2] || "B").toUpperCase();
|
|
const factor = SIZE_UNITS[unit];
|
|
if (factor === undefined) throw new Error(`Invalid size unit in: "${value}"`);
|
|
return Math.floor(num * factor);
|
|
}
|
|
|
|
function boolFromEnv(value: string | undefined, fallback: boolean): boolean {
|
|
if (value === undefined) return fallback;
|
|
return !["0", "false", "no", "off"].includes(value.trim().toLowerCase());
|
|
}
|
|
|
|
export function loadConfig(env: Record<string, string | undefined> = process.env): Config {
|
|
const port = Number(env.PORT ?? "3000");
|
|
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
throw new Error(`Invalid PORT: ${env.PORT}`);
|
|
}
|
|
const host = env.HOST ?? "0.0.0.0";
|
|
const storageDir = resolve(env.STORAGE_DIR ?? "./storage");
|
|
const maxFileSize = parseSize(env.MAX_FILE_SIZE ?? "10GB");
|
|
if (maxFileSize < 1024) throw new Error("MAX_FILE_SIZE must be at least 1KB");
|
|
|
|
const fileTtlMs = Number(env.FILE_TTL_MS ?? String(DEFAULT_TTL_MS));
|
|
if (!Number.isInteger(fileTtlMs) || fileTtlMs < 1) {
|
|
throw new Error(`Invalid FILE_TTL_MS: ${env.FILE_TTL_MS}`);
|
|
}
|
|
|
|
const rateLimitMax = Number(env.RATE_LIMIT_MAX ?? "300");
|
|
if (!Number.isInteger(rateLimitMax) || rateLimitMax < 1) {
|
|
throw new Error(`Invalid RATE_LIMIT_MAX: ${env.RATE_LIMIT_MAX}`);
|
|
}
|
|
const rateLimitWindowMs = Number(env.RATE_LIMIT_WINDOW_MS ?? "60000");
|
|
if (!Number.isInteger(rateLimitWindowMs) || rateLimitWindowMs < 1000) {
|
|
throw new Error(`Invalid RATE_LIMIT_WINDOW_MS: ${env.RATE_LIMIT_WINDOW_MS}`);
|
|
}
|
|
|
|
return {
|
|
host,
|
|
port,
|
|
storageDir,
|
|
maxFileSize,
|
|
fileTtlMs,
|
|
rateLimitEnabled: boolFromEnv(env.RATE_LIMIT_ENABLED, true),
|
|
rateLimitMax,
|
|
rateLimitWindowMs,
|
|
trustProxy: boolFromEnv(env.TRUST_PROXY, false),
|
|
};
|
|
}
|