Fix app stream/timeline ordering desync and init lifecycle race (#73)

* fix(app): enforce canonical stream sequencing and init resolution

* refactor: extract timeline and stream reducers to pure functions
This commit is contained in:
Mohamed Boudra
2026-02-23 19:30:48 +07:00
committed by GitHub
parent 9b6f5e028c
commit a134132418
12 changed files with 1732 additions and 109 deletions
@@ -0,0 +1,62 @@
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;
}