// Server-side helper for resolving the calling user's IANA timezone. // // After Phase 7.1 Plan 01, `session.user.timezone` is a string populated // either from the stored `"user".timezone` column or from Better Auth's // additionalField `defaultValue` (`process.env.DEFAULT_TIMEZONE || 'UTC'`). // // This helper: // - reads the value off a Better Auth session // - validates it against `Intl.supportedValuesOf('timeZone')` (defence in // depth — Plan 02 already validates writes, but a corrupt row from // before this phase, or a manual SQL edit, must not crash dashboards) // - falls back to `process.env.DEFAULT_TIMEZONE || 'UTC'` if invalid // // Use this in every API route that does day/week/month boundary math. export const DEFAULT_TIMEZONE_FALLBACK = (): string => process.env.DEFAULT_TIMEZONE || 'UTC'; type SessionLike = { user?: { timezone?: unknown } | null; } | null | undefined; function isValidIanaTimezone(tz: unknown): tz is string { if (typeof tz !== 'string' || tz.length === 0 || tz.length > 64) return false; try { return Intl.supportedValuesOf('timeZone').includes(tz); } catch { return false; } } /** * Returns a validated IANA timezone string for the given session. * Never throws; always returns a usable string (worst case: 'UTC'). */ export function getUserTimezone(session: SessionLike): string { const raw = session?.user?.timezone; if (isValidIanaTimezone(raw)) return raw; return DEFAULT_TIMEZONE_FALLBACK(); }