fix: namespace request-handler cache per handler and stop persist retries in demo mode

The in-memory request handler cache introduced in #6075 keyed entries by
JSON.stringify(input) in a Map shared across all handlers. Any two handlers
querying the same integration with equal options (e.g. {}) collided and read
each other's data — with the mock integration serving every widget kind, all
demo widgets received whichever handler's data was cached first (beszel
getting health-monitoring payloads, etc.). Cache keys are now namespaced per
handler definition.

Also disable the query-cache persister after the first FORBIDDEN response so
demo mode doesn't retry a mutation that is always rejected.
This commit is contained in:
Thomas Camlong committed 2026-07-04 10:41:36 +02:00
1 parent cf075040e8
commit d0709a684c
3 files changed
+86 -42

No files matched your search

@@ -1,22 +1,39 @@
import { createAsyncStoragePersister } from "@tanstack/query-async-storage-persister";
import { TRPCClientError } from "@trpc/client";
import superjson from "superjson";
import { fetchApi } from "@homarr/api/client";
import { getActiveQueryCacheBoardId, queryCacheStoragePrefix } from "@homarr/api/query-cache";
// Set once the server rejects a persist mutation as read-only (demo mode),
// so we stop retrying a mutation that can never succeed.
let persistDisabled = false;
const isReadOnlyError = (error: unknown) => error instanceof TRPCClientError && error.data?.code === "FORBIDDEN";
const queryCacheStorage = {
getItem: (_key: string) => null as string | null,
async setItem(_key: string, value: string) {
if (persistDisabled) return;
const boardId = getActiveQueryCacheBoardId();
if (!boardId) return;
await fetchApi.queryCache.setItem.mutate({ boardId, value }).catch((error) => {
if (isReadOnlyError(error)) {
persistDisabled = true;
return;
}
console.warn("[query-cache] persist failed", error);
});
},
async removeItem(_key: string) {
if (persistDisabled) return;
const boardId = getActiveQueryCacheBoardId();
if (!boardId) return;
await fetchApi.queryCache.removeItem.mutate({ boardId }).catch((error) => {
if (isReadOnlyError(error)) {
persistDisabled = true;
return;
}
console.warn("[query-cache] remove failed", error);
});
},