Dedup checkout status refetch and in-flight requests

This commit is contained in:
Mohamed Boudra
2026-01-23 15:46:44 +07:00
parent eab8713c24
commit 907b9f9fbd
5 changed files with 285 additions and 19 deletions
@@ -0,0 +1,23 @@
export type CheckoutStatusRevalidationParams = {
serverId: string;
agentId: string;
isOpen: boolean;
explorerTab: string;
};
export function checkoutStatusRevalidationKey(params: CheckoutStatusRevalidationParams): string | null {
if (!params.agentId) return null;
if (!params.isOpen) return null;
if (params.explorerTab !== "changes") return null;
return `${params.serverId}:${params.agentId}`;
}
export function nextCheckoutStatusRefetchDecision(
prevKey: string | null,
nextKey: string | null
): { nextSeenKey: string | null; shouldRefetch: boolean } {
if (!nextKey) return { nextSeenKey: null, shouldRefetch: false };
if (prevKey === nextKey) return { nextSeenKey: prevKey, shouldRefetch: false };
return { nextSeenKey: nextKey, shouldRefetch: true };
}
@@ -0,0 +1,74 @@
import { describe, expect, it } from "vitest";
import { checkoutStatusRevalidationKey, nextCheckoutStatusRefetchDecision } from "./checkout-status-revalidation";
describe("useCheckoutStatusQuery", () => {
describe("checkoutStatusRevalidationKey", () => {
it("returns null when sidebar is closed", () => {
expect(
checkoutStatusRevalidationKey({
serverId: "daemon-1",
agentId: "agent-1",
isOpen: false,
explorerTab: "changes",
})
).toBeNull();
});
it("returns null when tab is not changes", () => {
expect(
checkoutStatusRevalidationKey({
serverId: "daemon-1",
agentId: "agent-1",
isOpen: true,
explorerTab: "files",
})
).toBeNull();
});
it("returns a stable key when open and on changes tab", () => {
expect(
checkoutStatusRevalidationKey({
serverId: "daemon-1",
agentId: "agent-1",
isOpen: true,
explorerTab: "changes",
})
).toBe("daemon-1:agent-1");
});
});
describe("nextCheckoutStatusRefetchDecision", () => {
it("refetches only once per key until reset", () => {
const key = "daemon-1:agent-1";
expect(nextCheckoutStatusRefetchDecision(null, key)).toEqual({
nextSeenKey: key,
shouldRefetch: true,
});
expect(nextCheckoutStatusRefetchDecision(key, key)).toEqual({
nextSeenKey: key,
shouldRefetch: false,
});
expect(nextCheckoutStatusRefetchDecision(key, null)).toEqual({
nextSeenKey: null,
shouldRefetch: false,
});
expect(nextCheckoutStatusRefetchDecision(null, key)).toEqual({
nextSeenKey: key,
shouldRefetch: true,
});
});
it("refetches again when agent changes while active", () => {
expect(
nextCheckoutStatusRefetchDecision("daemon-1:agent-1", "daemon-1:agent-2")
).toEqual({
nextSeenKey: "daemon-1:agent-2",
shouldRefetch: true,
});
});
});
});
@@ -1,9 +1,13 @@
import { useQuery } from "@tanstack/react-query";
import { useEffect } from "react";
import { useEffect, useMemo, useRef } from "react";
import { UnistylesRuntime } from "react-native-unistyles";
import { useSessionStore } from "@/stores/session-store";
import { usePanelStore } from "@/stores/panel-store";
import type { CheckoutStatusResponse } from "@server/shared/messages";
import {
checkoutStatusRevalidationKey,
nextCheckoutStatusRefetchDecision,
} from "./checkout-status-revalidation";
const CHECKOUT_STATUS_STALE_TIME = 15_000;
@@ -48,12 +52,17 @@ export function useCheckoutStatusQuery({ serverId, agentId }: UseCheckoutStatusQ
});
// Revalidate when sidebar is open with "changes" tab active.
const revalidationKey = useMemo(
() => checkoutStatusRevalidationKey({ serverId, agentId, isOpen, explorerTab }),
[serverId, agentId, isOpen, explorerTab]
);
const lastRevalidationKey = useRef<string | null>(null);
useEffect(() => {
if (!isOpen || explorerTab !== "changes" || !agentId) {
return;
}
const decision = nextCheckoutStatusRefetchDecision(lastRevalidationKey.current, revalidationKey);
lastRevalidationKey.current = decision.nextSeenKey;
if (!decision.shouldRefetch) return;
void query.refetch();
}, [isOpen, explorerTab, agentId, query]);
}, [revalidationKey, query.refetch]);
return {
status: query.data ?? null,