/** * Duration string parsing for stream-basin retention / delete-on-empty * configuration. Used by `streamBasinProvisioner` (to convert to S2's * integer-seconds wire format) and by `env.server.ts` (to validate * duration-shaped env vars at boot rather than at first use). * * Accepts the short forms (`7d`, `30d`, `365d`, `1h`, `90m`, `45s`, * `2w`, `1y`) and the human forms (`7days`, `1week`, `1year`). */ const PATTERN = /^(\d+)\s*(s|sec|secs|seconds?|m|min|mins|minutes?|h|hour|hours?|d|day|days?|w|week|weeks?|y|year|years?)$/; export function isValidDuration(input: string): boolean { return PATTERN.test(input.trim().toLowerCase()); } /** * Parse a duration string into seconds. Throws on garbage so a * misconfigured env var fails loudly. Use {@link isValidDuration} * for non-throwing validation (e.g. inside a Zod `.refine()`). */ export function parseDuration(input: string): number { const trimmed = input.trim().toLowerCase(); const match = trimmed.match(PATTERN); if (!match) { throw new Error(`Invalid duration string: ${input}`); } const value = parseInt(match[1]!, 10); const unit = match[2]!; const multiplier = /^s/.test(unit) ? 1 : /^m(?:in|ins|inute|inutes)?$/.test(unit) ? 60 : /^h/.test(unit) ? 3600 : /^d/.test(unit) ? 86400 : /^w/.test(unit) ? 604800 : /^y/.test(unit) ? 31_536_000 : NaN; if (!Number.isFinite(multiplier)) { throw new Error(`Invalid duration unit: ${unit}`); } return value * multiplier; }