wulf-pulse/lib/services/user-timezone.ts

41 lines
1.5 KiB
TypeScript
Raw Normal View History

// 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();
}