feat(07.1-03): add lib/services/user-timezone.ts helper
- getUserTimezone(session) returns validated IANA tz string with safe fallback
- DEFAULT_TIMEZONE_FALLBACK reads process.env.DEFAULT_TIMEZONE || 'UTC'
- Validates against Intl.supportedValuesOf('timeZone'); 64-char length cap
- Pure / synchronous / no DB / no @/lib/auth-utils import (avoids circular)
This commit is contained in:
parent
3f3142bbb7
commit
ea5532c5c3
1 changed files with 40 additions and 0 deletions
40
lib/services/user-timezone.ts
Normal file
40
lib/services/user-timezone.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// 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();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue