/** * desktop/src/notifications.ts — B2: batch notification diff across sessions. * * Given the previous per-session snapshots and the latest poll, compute which * sessions warrant a native notification (delegating each decision to * notify-policy's shouldNotify) and the NEW snapshot map to carry forward. * * Pure: never mutates `prev`. The returned `next` map is rebuilt only from the * current snapshots, so sessions that ended (absent this round) naturally drop * out and won't re-fire on their next appearance. */ import { shouldNotify, type NotifyOptions } from './notify-policy.js' import type { NotifyDecision, SessionStatusSnapshot } from './types.js' /** Result of diffing a poll: what to fire now + the state to remember. */ export interface NotificationsResult { readonly decisions: readonly NotifyDecision[] /** Fresh snapshot map (sessionId → snapshot) for the next round. Handed off as * ReadonlyMap so callers can't mutate the carried-forward state (immutability * is a CRITICAL project rule); the concrete Map is still assignable. */ readonly next: ReadonlyMap } /** * Diff the latest snapshots against the previous round. Collect only the * notifying decisions, and build a new snapshot map keyed by sessionId. The * input `prev` map is treated as read-only and left untouched. */ export function computeNotifications( prev: ReadonlyMap, snapshots: readonly SessionStatusSnapshot[], opts: NotifyOptions, ): NotificationsResult { const decisions: NotifyDecision[] = [] const next = new Map() for (const snapshot of snapshots) { const decision = shouldNotify(prev.get(snapshot.sessionId), snapshot, opts) if (decision.notify) decisions.push(decision) next.set(snapshot.sessionId, snapshot) } return { decisions, next } }