* fix(app): enforce canonical stream sequencing and init resolution * refactor: extract timeline and stream reducers to pure functions
63 lines
1.4 KiB
TypeScript
63 lines
1.4 KiB
TypeScript
type TimelineDirection = "tail" | "before" | "after";
|
|
type InitRequestDirection = "tail" | "after";
|
|
|
|
type TimelineCursor = {
|
|
seq: number;
|
|
} | null;
|
|
|
|
export function deriveBootstrapTailTimelinePolicy({
|
|
direction,
|
|
reset,
|
|
epoch,
|
|
endCursor,
|
|
isInitializing,
|
|
hasActiveInitDeferred,
|
|
}: {
|
|
direction: TimelineDirection;
|
|
reset: boolean;
|
|
epoch: string;
|
|
endCursor: TimelineCursor;
|
|
isInitializing: boolean;
|
|
hasActiveInitDeferred: boolean;
|
|
}): {
|
|
replace: boolean;
|
|
catchUpCursor: { epoch: string; endSeq: number } | null;
|
|
} {
|
|
if (reset) {
|
|
return { replace: true, catchUpCursor: null };
|
|
}
|
|
|
|
const isBootstrapTailInit =
|
|
direction === "tail" && isInitializing && hasActiveInitDeferred;
|
|
if (!isBootstrapTailInit) {
|
|
return { replace: false, catchUpCursor: null };
|
|
}
|
|
|
|
return {
|
|
replace: true,
|
|
catchUpCursor: endCursor ? { epoch, endSeq: endCursor.seq } : null,
|
|
};
|
|
}
|
|
|
|
export function shouldResolveTimelineInit({
|
|
hasActiveInitDeferred,
|
|
isInitializing,
|
|
initRequestDirection,
|
|
responseDirection,
|
|
reset,
|
|
}: {
|
|
hasActiveInitDeferred: boolean;
|
|
isInitializing: boolean;
|
|
initRequestDirection: InitRequestDirection;
|
|
responseDirection: TimelineDirection;
|
|
reset: boolean;
|
|
}): boolean {
|
|
if (!hasActiveInitDeferred || !isInitializing) {
|
|
return false;
|
|
}
|
|
if (reset) {
|
|
return true;
|
|
}
|
|
return responseDirection === initRequestDirection;
|
|
}
|