* Fix projected timeline paging * Avoid full timeline fetches for plain pages
114 lines
2.8 KiB
TypeScript
114 lines
2.8 KiB
TypeScript
import { TIMELINE_FETCH_PAGE_SIZE } from "@/timeline/timeline-fetch-policy";
|
|
|
|
export interface TimelineSyncCursor {
|
|
epoch: string;
|
|
seq: number;
|
|
}
|
|
|
|
export interface AgentTimelineCursorRange {
|
|
epoch: string;
|
|
startSeq: number;
|
|
endSeq: number;
|
|
}
|
|
|
|
export interface ProjectedTimelineTailFetchPlan {
|
|
direction: "tail";
|
|
limit: number;
|
|
projection: "projected";
|
|
}
|
|
|
|
export interface ProjectedTimelineAfterFetchPlan {
|
|
direction: "after";
|
|
cursor: TimelineSyncCursor;
|
|
limit: number;
|
|
projection: "projected";
|
|
}
|
|
|
|
export interface ProjectedTimelineBeforeFetchPlan {
|
|
direction: "before";
|
|
cursor: TimelineSyncCursor;
|
|
limit: number;
|
|
projection: "projected";
|
|
}
|
|
|
|
export type ProjectedTimelineFetchPlan =
|
|
| ProjectedTimelineTailFetchPlan
|
|
| ProjectedTimelineAfterFetchPlan
|
|
| ProjectedTimelineBeforeFetchPlan;
|
|
|
|
export type ProjectedTimelineForwardFetchPlan =
|
|
| ProjectedTimelineTailFetchPlan
|
|
| ProjectedTimelineAfterFetchPlan;
|
|
|
|
export function planInitialAgentTimelineSync(input: {
|
|
cursor: AgentTimelineCursorRange | undefined;
|
|
hasAuthoritativeHistory: boolean;
|
|
}): ProjectedTimelineForwardFetchPlan {
|
|
if (input.hasAuthoritativeHistory && input.cursor) {
|
|
return planTimelineCatchUpAfter({ epoch: input.cursor.epoch, seq: input.cursor.endSeq });
|
|
}
|
|
|
|
return planTimelineTailFetch();
|
|
}
|
|
|
|
export function planResumeTimelineSync(input: {
|
|
cursor: AgentTimelineCursorRange | undefined;
|
|
}): ProjectedTimelineForwardFetchPlan {
|
|
if (input.cursor) {
|
|
return planTimelineCatchUpAfter({ epoch: input.cursor.epoch, seq: input.cursor.endSeq });
|
|
}
|
|
|
|
return planTimelineTailFetch();
|
|
}
|
|
|
|
export function planTimelineCatchUpAfter(cursor: TimelineSyncCursor) {
|
|
return {
|
|
direction: "after",
|
|
cursor,
|
|
limit: TIMELINE_FETCH_PAGE_SIZE,
|
|
projection: "projected",
|
|
} as const;
|
|
}
|
|
|
|
export function planTimelineTailFetch() {
|
|
return {
|
|
direction: "tail",
|
|
limit: TIMELINE_FETCH_PAGE_SIZE,
|
|
projection: "projected",
|
|
} as const;
|
|
}
|
|
|
|
export function planTimelineOlderFetch(cursor: TimelineSyncCursor) {
|
|
return {
|
|
direction: "before",
|
|
cursor,
|
|
limit: TIMELINE_FETCH_PAGE_SIZE,
|
|
projection: "projected",
|
|
} as const;
|
|
}
|
|
|
|
export function planTimelineCatchUpFollowUp(input: {
|
|
direction: "tail" | "before" | "after";
|
|
hasNewer: boolean;
|
|
endCursor: TimelineSyncCursor | null;
|
|
error: string | null;
|
|
}): ProjectedTimelineAfterFetchPlan | null {
|
|
if (input.error || input.direction !== "after" || !input.hasNewer || !input.endCursor) {
|
|
return null;
|
|
}
|
|
|
|
return planTimelineCatchUpAfter(input.endCursor);
|
|
}
|
|
|
|
export function isTimelineCatchUpComplete(input: {
|
|
direction: "tail" | "before" | "after";
|
|
hasNewer: boolean;
|
|
error: string | null;
|
|
}): boolean {
|
|
if (input.error) {
|
|
return false;
|
|
}
|
|
|
|
return input.direction !== "after" || !input.hasNewer;
|
|
}
|