feat(18-03): route all-day reminder TZ through stored household_timezone
- reminderScheduler.ts: add import { getHouseholdTimezone } from '../lib/householdTimezone.js'
and replace bare process.env.TZ ?? Intl... at line 247 with await getHouseholdTimezone(db)
- outboxWorker.ts: add same import and replace BOTH bare tz lookups at the update-branch
(~line 501) and create-branch (~line 607) with await getHouseholdTimezone(db)
- D-05 satisfied: all three all-day sites now read from the single stored accessor
- D-06 satisfied: getHouseholdTimezone falls back to process.env.TZ → Intl when unset;
existing process.env.TZ-pinned tests pass unchanged
- D-07 satisfied: eventDateTime.ts and hydrateEvents.ts are not modified
- outboxWorker.test.ts: update wireMockChain() to handle app_config table with where().limit()
chain returning empty rows (D-06 fallback), so existing CAL-13 all-day test stays green
- reminderScheduler.test.ts: update mockTwoQueries to mock the new third db.select() call
(getHouseholdTimezone) returning no row (D-06 fallback), keeping all 37 existing tests green
- All 76 broker tests pass; tsc --noEmit clean
This commit is contained in:
@@ -43,6 +43,7 @@ import {
|
||||
} from './vevent.js';
|
||||
import type { FastmailClient } from './client.js';
|
||||
import { dispatchEventChange } from '../lib/eventChangeDispatcher.js';
|
||||
import { getHouseholdTimezone } from '../lib/householdTimezone.js';
|
||||
import { onOutboxDrain } from '../lib/outboxTrigger.js';
|
||||
|
||||
// ── Constants (D-07) ────────────────────────────────────────────────────────
|
||||
@@ -498,7 +499,9 @@ async function dispatchRow(row: OutboxRow): Promise<DispatchResult> {
|
||||
fields.allDay &&
|
||||
fields.start
|
||||
) {
|
||||
const tz = process.env.TZ ?? Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
// D-05: route through the single stored-TZ accessor (no inline fallback duplicated here).
|
||||
// D-06: getHouseholdTimezone falls back to process.env.TZ → Intl when no row is stored.
|
||||
const tz = await getHouseholdTimezone(db);
|
||||
const leadDays = fields.reminderLeadMinutes / 1440;
|
||||
allDayAlertInstantUtcUpdate = computeAlertInstantUtc(fields.start, leadDays, tz);
|
||||
}
|
||||
@@ -604,7 +607,9 @@ async function dispatchRow(row: OutboxRow): Promise<DispatchResult> {
|
||||
// carries an explicit picker value or no reminder at all; no preserve path needed).
|
||||
let allDayAlertInstantUtcCreate: Date | undefined;
|
||||
if (fields.reminderLeadMinutes != null && fields.allDay && fields.start) {
|
||||
const tz = process.env.TZ ?? Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
// D-05: route through the single stored-TZ accessor (no inline fallback duplicated here).
|
||||
// D-06: getHouseholdTimezone falls back to process.env.TZ → Intl when no row is stored.
|
||||
const tz = await getHouseholdTimezone(db);
|
||||
const leadDays = fields.reminderLeadMinutes / 1440;
|
||||
allDayAlertInstantUtcCreate = computeAlertInstantUtc(fields.start, leadDays, tz);
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ import { calendarEvents, pushSubscriptions } from '../db/schema.js';
|
||||
import { dispatchPush } from '../lib/pushDispatcher.js';
|
||||
import { computeAlertInstantUtc } from './vevent.js';
|
||||
import type { NotificationPayload } from '../lib/pushDispatcher.js';
|
||||
import { getHouseholdTimezone } from '../lib/householdTimezone.js';
|
||||
|
||||
// Maximum lead time preset (2880 min = 2 days for timed; 7 days for all-day is handled separately)
|
||||
// Pre-filter window upper bound for timed events: fetch events starting up to MAX_LEAD_MINUTES out.
|
||||
@@ -244,7 +245,9 @@ export async function runReminderCheck(now = new Date()): Promise<void> {
|
||||
}
|
||||
|
||||
// Process ALL-DAY events
|
||||
const serverTz = process.env.TZ ?? Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
// D-05: read the stored household timezone through the single accessor (no inline fallback).
|
||||
// D-06: getHouseholdTimezone falls back to process.env.TZ → Intl when no row is stored.
|
||||
const serverTz = await getHouseholdTimezone(db);
|
||||
for (const row of allDayRows) {
|
||||
// Drizzle's date() column type is Date|null in TS but mysql2 returns ISO string at runtime
|
||||
const dtstartDate = row.dtstartDate as unknown as string; // 'YYYY-MM-DD'
|
||||
|
||||
Reference in New Issue
Block a user