fix: harden upgrade publication and refresh
This commit is contained in:
@@ -222,4 +222,39 @@ describe("useBankDashboard", () => {
|
||||
expect(result.current.status === "ready" && result.current.snapshot.blockNumber).toBe(13n);
|
||||
});
|
||||
});
|
||||
|
||||
it("refetches a changed manifest on a watched block and isolates its implementation snapshot without remounting", async () => {
|
||||
const v2ManifestJson = { ...manifestJson, implementation: address("6") };
|
||||
const v2Snapshot = {
|
||||
...snapshot,
|
||||
blockNumber: 13n,
|
||||
version: 2 as const,
|
||||
implementation: address("6"),
|
||||
synchronizedAt: new Date("2026-08-21T10:01:00.000Z"),
|
||||
};
|
||||
const pendingV2Snapshot = deferred<DashboardSnapshot>();
|
||||
const loadManifest = vi.fn()
|
||||
.mockResolvedValueOnce(manifestJson)
|
||||
.mockResolvedValueOnce(v2ManifestJson);
|
||||
const loader = vi.fn((current: DeploymentManifest) => current.implementation === manifest.implementation
|
||||
? Promise.resolve(snapshot)
|
||||
: pendingV2Snapshot.promise);
|
||||
const { result } = renderHook(() => useBankDashboard({ loadManifest, loader }), {
|
||||
wrapper: createWrapper(),
|
||||
});
|
||||
await waitFor(() => expect(result.current.status).toBe("ready"));
|
||||
|
||||
act(() => notifyBlock?.(13n));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(loadManifest).toHaveBeenCalledTimes(2);
|
||||
expect(loader).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
expect(result.current.status).toBe("loading");
|
||||
|
||||
pendingV2Snapshot.resolve(v2Snapshot);
|
||||
await waitFor(() => expect(result.current.status).toBe("ready"));
|
||||
expect(result.current.status === "ready" && result.current.manifest.implementation).toBe(address("6"));
|
||||
expect(result.current.status === "ready" && result.current.snapshot).toBe(v2Snapshot);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -43,6 +43,15 @@ function isChainMismatch(error: unknown): boolean {
|
||||
return /endpoint chain ID \d+ does not match manifest chain ID \d+/i.test(message(error));
|
||||
}
|
||||
|
||||
function manifestIdentity(manifest: DeploymentManifest | undefined): string | undefined {
|
||||
if (!manifest) return undefined;
|
||||
return JSON.stringify({
|
||||
...manifest,
|
||||
deploymentBlock: manifest.deploymentBlock.toString(),
|
||||
actors: manifest.actors.map(({ label, address }) => ({ label, address })),
|
||||
});
|
||||
}
|
||||
|
||||
export function useBankDashboard(options: BankDashboardOptions = {}): DashboardState {
|
||||
const loadManifest = options.loadManifest ?? fetchManifest;
|
||||
const loader = options.loader ?? fetchSnapshot;
|
||||
@@ -70,9 +79,10 @@ export function useBankDashboard(options: BankDashboardOptions = {}): DashboardS
|
||||
}
|
||||
}, [manifestQuery.data]);
|
||||
const manifest = parsedManifest && "manifest" in parsedManifest ? parsedManifest.manifest : undefined;
|
||||
const snapshotIdentity = useMemo(() => manifestIdentity(manifest), [manifest]);
|
||||
const snapshotQueryKey = useMemo(
|
||||
() => ["bank-dashboard", manifest?.chainId, manifest?.proxy] as const,
|
||||
[manifest?.chainId, manifest?.proxy],
|
||||
() => ["bank-dashboard", snapshotIdentity] as const,
|
||||
[snapshotIdentity],
|
||||
);
|
||||
|
||||
const snapshotQuery = useQuery({
|
||||
@@ -97,8 +107,19 @@ export function useBankDashboard(options: BankDashboardOptions = {}): DashboardS
|
||||
const reconcileBlock = useCallback((blockNumber: bigint) => {
|
||||
if (!manifest || mismatch || latestSnapshot.current?.blockNumber === blockNumber || lastWatchedBlock.current === blockNumber) return;
|
||||
lastWatchedBlock.current = blockNumber;
|
||||
void queryClient.invalidateQueries({ queryKey: snapshotQueryKey, exact: true });
|
||||
}, [manifest, mismatch, queryClient, snapshotQueryKey]);
|
||||
void manifestQuery.refetch().then((result) => {
|
||||
if (result.error !== null || result.data === undefined) return;
|
||||
let refreshedManifest: DeploymentManifest;
|
||||
try {
|
||||
refreshedManifest = parseDeploymentManifest(result.data);
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
if (manifestIdentity(refreshedManifest) === snapshotIdentity) {
|
||||
void queryClient.invalidateQueries({ queryKey: snapshotQueryKey, exact: true });
|
||||
}
|
||||
});
|
||||
}, [manifest, manifestQuery, mismatch, queryClient, snapshotIdentity, snapshotQueryKey]);
|
||||
|
||||
useWatchBlockNumber({
|
||||
chainId: manifest?.chainId,
|
||||
|
||||
Reference in New Issue
Block a user