Andrey Epifancev 0cd683d5df feat(core): due, stale-sent and claimable selection
Refs #1

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 16:29:28 +04:00

39 lines
1.4 KiB
TypeScript

import { SENT_STALE_MS, type VoiceRecord } from './record';
export interface Located {
path: string;
record: VoiceRecord;
}
const time = (iso?: string) => (iso ? Date.parse(iso) : NaN);
// Отсутствующее или испорченное время — не повод зависнуть навсегда.
export function isStaleSent(r: VoiceRecord, now: Date): boolean {
if (r.status !== 'sent') return false;
const t = time(r.sentAt);
return Number.isNaN(t) || now.getTime() - t > SENT_STALE_MS;
}
export function due(items: readonly Located[], now: Date, deviceId: string): Located[] {
return items
.filter(({ record: r }) => {
if (r.device !== deviceId) return false;
if (r.status === 'saved') return true;
if (r.status !== 'retry') return false;
const t = time(r.nextAttempt);
return Number.isNaN(t) || t <= now.getTime();
})
.sort((a, b) => (a.record.id < b.record.id ? -1 : a.record.id > b.record.id ? 1 : 0));
}
export function staleOwn(items: readonly Located[], now: Date, deviceId: string): Located[] {
return items.filter(({ record: r }) => r.device === deviceId && isStaleSent(r, now));
}
export function claimable(items: readonly Located[], now: Date, deviceId: string): Located[] {
return items.filter(
({ record: r }) =>
r.device !== deviceId && (r.status === 'saved' || r.status === 'retry' || isStaleSent(r, now)),
);
}