Files
CollabTable/CollabTableServer/src/notifications.ts
T

54 lines
1.6 KiB
TypeScript

import { dbAdapter, DBAdapter } from './db';
import crypto from 'crypto';
export type NotificationEvent = {
id: string;
deviceIdOrigin?: string;
eventType: string; // created | updated | deleted | listContentUpdated | listEdited ...
entityType: string; // list | field | item | value
entityId?: string;
listId?: string;
createdAt: number; // ms epoch
};
function genId() {
try {
return crypto.randomUUID();
} catch {
return `${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
}
}
export async function enqueueNotification(
adapter: DBAdapter,
deviceIdOrigin: string | undefined,
eventType: string,
entityType: string,
entityId?: string,
listId?: string,
createdAt?: number
) {
const id = genId();
const ts = createdAt ?? Date.now();
await adapter.execute(
'INSERT INTO notifications (id, deviceIdOrigin, eventType, entityType, entityId, listId, createdAt) VALUES (?, ?, ?, ?, ?, ?, ?)',
[id, deviceIdOrigin ?? null, eventType, entityType, entityId ?? null, listId ?? null, ts]
);
}
// Retention policy
const DEFAULT_RETENTION_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
const CLEAN_INTERVAL_MS = 60 * 60 * 1000; // hourly
export function startNotificationCleanup() {
const retentionMs = Number(process.env.NOTIF_RETENTION_MS || DEFAULT_RETENTION_MS);
setInterval(async () => {
try {
const cutoff = Date.now() - retentionMs;
await dbAdapter.execute('DELETE FROM notifications WHERE createdAt < ?', [cutoff]);
} catch (e) {
console.warn('[NOTIF] Retention cleanup failed:', e);
}
}, CLEAN_INTERVAL_MS).unref?.();
}