diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index 2a2bb41..adcb861 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -62,11 +62,12 @@ app.route('/api/me', meRouter) app.route('/api/events', eventsRouter) app.route('/api/sse', sseRouter) -// Start the CalDAV broker poller (5-min cron, D-13 ctag change-detection) -// Runs in the background — errors are caught and logged per-credential (T-03-04) -startBrokerPoller() -// Drain the D-05 outbox every 15s: dispatches pending CalDAV writes to Fastmail -startOutboxWorker() +// WR-04: background worker startup (cron schedules) moved into the isMainModule() +// guard below. Calling them at top level registered real node-cron schedules whenever +// ./index.js was imported — the route tests import `app` from here, so the poller/outbox +// drain fired during the test run, touched the mocked DB/CalDAV layers nondeterministically, +// and left open handles that blocked clean process exit. They now start only when the +// module is the process entrypoint. // Serve React PWA static assets from ./public (Vite build output). // MUST serve the whole ./public tree, not just /assets/* — root-level PWA files @@ -97,8 +98,16 @@ function isMainModule(): boolean { } } -// Only start the HTTP server when this module is run directly (not imported in tests) +// Only start the HTTP server AND background workers when this module is run directly +// (not imported in tests). WR-04: gating the cron schedules here keeps them out of the +// test process. if (isMainModule()) { + // Start the CalDAV broker poller (5-min cron, D-13 ctag change-detection). + // Runs in the background — errors are caught and logged per-credential (T-03-04). + startBrokerPoller() + // Drain the D-05 outbox every 15s: dispatches pending CalDAV writes to Fastmail. + startOutboxWorker() + serve({ fetch: app.fetch, port: 3000 }, (info) => { console.log(`FamilySync API running on http://localhost:${info.port}`) })