You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
76 lines
2.2 KiB
TypeScript
76 lines
2.2 KiB
TypeScript
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)
|
|
);
|
|
}
|