import type { Database } from 'bun:sqlite'; // --------------------------------------------------------------------------- // Snapshot freshness // --------------------------------------------------------------------------- function maxSnapshotAgeMs(): number { const raw = Number(process.env.MAX_MEMBERS_SNAPSHOT_AGE_MS); return Number.isFinite(raw) && raw > 0 ? raw : 24 * 60 * 60 * 1000; // 24h default } export function isSnapshotFresh( db: Database, groupId: string, nowMs: number = Date.now() ): boolean { try { const row = db .prepare(`SELECT last_verified FROM groups WHERE id = ?`) .get(groupId) as { last_verified?: string | null } | undefined; const lv = row?.last_verified ? String(row.last_verified) : null; if (!lv) return false; const iso = lv.includes('T') ? lv : lv.replace(' ', 'T') + 'Z'; const ms = Date.parse(iso); if (!Number.isFinite(ms)) return false; return nowMs - ms <= maxSnapshotAgeMs(); } catch { return false; } } // --------------------------------------------------------------------------- // Membership queries // --------------------------------------------------------------------------- export function isUserActiveInGroup( db: Database, userId: string, groupId: string ): boolean { if (!userId || !groupId) return false; const row = db .prepare( `SELECT 1 FROM group_members WHERE group_id = ? AND user_id = ? AND is_active = 1 LIMIT 1` ) .get(groupId, userId); return !!row; } export function getActiveGroupIdsForUser( db: Database, userId: string ): string[] { if (!userId) return []; const rows = db .prepare( `SELECT gm.group_id AS id FROM group_members gm JOIN groups g ON g.id = gm.group_id WHERE gm.user_id = ? AND gm.is_active = 1 AND g.active = 1 AND COALESCE(g.is_community,0) = 0 AND COALESCE(g.archived,0) = 0` ) .all(userId) as Array<{ id: string }>; return [...new Set(rows.map(r => String(r.id)))]; } export function getFreshMemberGroupsForUser( db: Database, userId: string ): string[] { return getActiveGroupIdsForUser(db, userId).filter(gid => isSnapshotFresh(db, gid) ); }