/** * The absolute bounds an investigation link carries. * * Every link out of a query detail is time-scoped on purpose: a relative window * would answer a different question tomorrow than it does today, and the whole * point of linking to an episode is that the link keeps showing that episode. */ import type { ActivitySearch } from "./search"; /** The five-minute window the redesign puts around one query. */ export const RELATED_WINDOW_SECONDS = 300; export interface Bounds { since: number; until: number; } /** * The bounds for "all activity for this domain/client", decided per bound. * * When the reader arrived from a bounded investigation, that bound is the one * they are working in and it carries over. A bound they never set falls back to * the five-minute window around this query — never to no bound at all, which * would answer with the whole retained history and lose the episode in it. The * two bounds are decided separately, so a half-bounded origin keeps its half. */ export function relatedBounds(ts: number, origin: Pick): Bounds { return { since: origin.since ?? ts - RELATED_WINDOW_SECONDS, until: origin.until ?? ts + RELATED_WINDOW_SECONDS, }; } /** * The Diagnostics window around one query. Fixed at five minutes either side of * the query, not inherited: the reader is asking what else was failing while * this query was answered, which is a question about the query's own moment. */ export function diagnosticsBounds(ts: number): Bounds { return { since: ts - RELATED_WINDOW_SECONDS, until: ts + RELATED_WINDOW_SECONDS }; }