d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 1 | import type { TimelineItem } from './types'; |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 2 | |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 3 | export const FEDERATION_LAG_MS = 60 * 1000; |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 4 | |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 5 | /** |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 6 | * Carries delivery lag forward from the previous list and measures it for events appended |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 7 | * after the last one already known. `since` is when the room last became able to receive |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 8 | * events, so catch-up after being offline or closed doesn't count as federation delay. |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 9 | * Returns null when nothing in `items` was known before, meaning the list was replaced. |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 10 | */ |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 11 | export function observeArrivals(previous: TimelineItem[], items: TimelineItem[], since: number, now: number): TimelineItem[] | null { |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 12 | const lags = new Map<string, number | undefined>(); |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 13 | for (const item of previous) if (item.kind === 'event') lags.set(item.event.item_id, item.event.delivery_lag_ms); |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 14 | let lastKnown = -1; |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 15 | items.forEach((item, index) => { |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 16 | if (item.kind === 'event' && lags.has(item.event.item_id)) lastKnown = index; |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 17 | }); |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 18 | if (lastKnown === -1) return null; |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 19 | return items.map((item, index) => { |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 20 | if (item.kind !== 'event') return item; |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 21 | const event = item.event; |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 22 | if (lags.has(event.item_id)) { |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 23 | const carried = lags.get(event.item_id); |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 24 | return carried === undefined ? item : { ...item, event: { ...event, delivery_lag_ms: carried } }; |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 25 | } |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 26 | if (index < lastKnown || event.own) return item; |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 27 | const lag = now - Math.max(event.timestamp_ms, since); |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 28 | return lag < FEDERATION_LAG_MS ? item : { ...item, event: { ...event, delivery_lag_ms: lag } }; |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 29 | }); |
d2a34d0f4861 | atagen | 2026-10-25 07:29 UTC | 30 | } |