3250530596
The full sync→async conversion is complete and green on the SQLite backend. Every DB call across the app now awaits the async adapter, so the identical code runs on Postgres at cutover. Converted (this commit finishes Phase 3): - session.js: currentUser/apiKeyFromReq async → 63 route awaits + WS + static. - routes.js: all ~250 R.* awaited; DTO helpers (namesFor, avatarsFor, buildMsgDTO, buildPollDTO, reactionsForMessage, postSystemMessage, pushGroupUpdate, issueRefreshToken, provisionFromBizgaze) made async; every `.map(x=>buildDTO(x))` restructured to `await Promise.all(...map(async...))` preserving order; `.filter` predicates that hit the DB moved to an `asyncFilter` helper; chained `R.x.y(...).length/.map/.filter` wrapped as `(await R.x.y(...)).method`; stream upload handlers (recording/transcript/attachment) made async. - calls.js / signaling.js: all call/meeting fns async; leaveMeeting AWAITS persistCallHistory + finalizeTranscript BEFORE endCallByRoom (ordering matters — fire-and-forget would race the map teardown); WS handle()/cleanup() async with .catch guards. - static.js: authAttachment(Raw) async (the .some carrier check became a loop), handleGet async; server.js dispatch catches handler rejections → 500 not a hang. - media.js backfill, push.js, reminders.js, webhooks.js await their repo calls. Validation on DB_BACKEND=sqlite: db-smoke 22/22; legacy e2e 80 checks pass with zero FAILs (throws only at a PRE-EXISTING WS lobby-drift assertion, unrelated). Every server file `node --check` clean. Still on the branch — master untouched. Next: Phase 5 (pg backend + ~7 dialect queries + data migration + Docker Postgres + cutover), then merge. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
26 lines
1.2 KiB
JavaScript
26 lines
1.2 KiB
JavaScript
// Fires a one-shot "starts in ~10 minutes" reminder to a scheduled meeting's host,
|
|
// group members, and invited participants. Runs on a 60s tick; marks each meeting reminded.
|
|
const R = require('./repos');
|
|
const CHAT = require('./chat');
|
|
|
|
async function tick() {
|
|
try {
|
|
const now = Date.now();
|
|
const due = await R.scheduledMeetings.dueForReminder(now, now + 10 * 60 * 1000); // starting within 10 min
|
|
for (const s of due) {
|
|
const recipients = new Set([s.created_by]);
|
|
let invited = []; try { invited = JSON.parse(s.participants || '[]'); } catch (_) {}
|
|
invited.forEach((id) => recipients.add(id));
|
|
if (s.group_id) { try { (await R.conversations.members(s.group_id)).forEach((m) => recipients.add(m)); } catch (_) {} }
|
|
const evt = { type: 'meeting-reminder', meeting: { id: s.id, title: s.title, scheduledAt: s.scheduled_at, room: s.room_code } };
|
|
recipients.forEach((uid) => { try { CHAT.pushToUser(uid, evt); } catch (_) {} });
|
|
await R.scheduledMeetings.markReminded(s.id);
|
|
}
|
|
} catch (_) { /* never let the timer die */ }
|
|
}
|
|
|
|
let timer = null;
|
|
function start() { if (!timer) timer = setInterval(tick, 60 * 1000); }
|
|
start();
|
|
module.exports = { start, tick };
|