fix: concurrent cache miss, SVG output, narrowed error handling, format

- Fix integration data cache: check pending promise before TTL to
  prevent returning undefined on concurrent cold-cache access
- Add concurrent-miss test (two parallel callers, one fetch)
- SVG sanitizer: extract <svg> from DOMPurify output to strip
  residual HTML wrapper
- Narrow safeRevalidateTag catch: log unexpected errors, silence only
  known "outside request scope" messages
- Run oxfmt across all packages (206 files formatted)
This commit is contained in:
Thomas Camlong committed 2026-08-07 20:48:17 +02:00
1 parent b81b90875f
commit 38ac8f3075
206 files changed
+7952 -6722

No files matched your search

+6 -4
View File
@@ -12,15 +12,17 @@ import { cacheTags } from "./cache-tags";
import { invalidateIntegrationDataCache } from "./integration-data-cache";
// ponytail: revalidateTag throws outside Next.js request context (tests, tasks, websocket).
// Ceiling: if Next.js context detection changes, update the try-catch.
// Ceiling: if Next.js context detection changes, update the require/catch.
const safeRevalidateTag = (tag: string) => {
try {
// Dynamic import avoidance — revalidateTag is only available within Next.js runtime.
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { revalidateTag } = require("next/cache") as typeof import("next/cache");
revalidateTag(tag, "max");
} catch {
// Not in a Next.js request context — no-op
} catch (error) {
const msg = error instanceof Error ? error.message : "";
if (!msg.includes("static generation") && !msg.includes("was called outside a request scope")) {
console.warn(`[cache-invalidation] revalidateTag("${tag}") failed:`, msg);
}
}
};
@@ -63,6 +63,26 @@ describe("getCachedIntegrationData", () => {
vi.useRealTimers();
});
test("concurrent cold-cache calls coalesce into one fetch, never return undefined", async () => {
let resolveOuter!: (v: { value: number }) => void;
const fetcher = vi.fn(
() =>
new Promise<{ value: number }>((resolve) => {
resolveOuter = resolve;
}),
);
const p1 = getCachedIntegrationData("integration-a", "widget:concurrent", fetcher);
const p2 = getCachedIntegrationData("integration-a", "widget:concurrent", fetcher);
resolveOuter({ value: 42 });
const [r1, r2] = await Promise.all([p1, p2]);
expect(r1).toEqual({ value: 42 });
expect(r2).toEqual({ value: 42 });
expect(fetcher).toHaveBeenCalledTimes(1);
});
test("invalidates all cache entries for an integration", async () => {
const fetcherOne = vi.fn(async () => ({ value: "one" }));
const fetcherTwo = vi.fn(async () => ({ value: "two" }));
+3 -3
View File
@@ -31,12 +31,12 @@ export const getCachedIntegrationData = async <T>(
const now = Date.now();
if (existing) {
if (now - existing.timestamp < ttlMs) {
return existing.data;
}
if (existing.pending) {
return existing.pending;
}
if (existing.timestamp > 0 && now - existing.timestamp < ttlMs) {
return existing.data;
}
}
const pending = fetcher()
@@ -101,9 +101,7 @@ describe("patchmonRouter.getStats access control", () => {
});
const caller = createCaller(db, null);
await expect(caller.getStats({ integrationId })).rejects.toThrow(
new TRPCError({ code: "UNAUTHORIZED" }),
);
await expect(caller.getStats({ integrationId })).rejects.toThrow(new TRPCError({ code: "UNAUTHORIZED" }));
});
test("should throw FORBIDDEN for authenticated users without board or integration access", async () => {
+10 -10
View File
@@ -11,17 +11,17 @@ export const coolifyRouter = createTRPCRouter({
return await settleIntegrationQueries(
ctx.integrations,
async (integration) => {
const innerHandler = coolifyRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
const innerHandler = coolifyRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
return {
integrationId: integration.id,
integrationName: integration.name,
integrationUrl: integration.url,
instanceInfo: data,
updatedAt: timestamp,
};
},
return {
integrationId: integration.id,
integrationName: integration.name,
integrationUrl: integration.url,
instanceInfo: data,
updatedAt: timestamp,
};
},
{ queryKey: integrationQueryKey("coolify", "getInstancesInfo") },
);
}),
+6 -6
View File
@@ -23,12 +23,12 @@ export const dnsHoleRouter = createTRPCRouter({
return await settleIntegrationQueries(
ctx.integrations,
async (integration) => {
const { data, timestamp } = await dnsHoleRequestHandler.handler(integration, {}).getDataAsync();
return {
integration: { id: integration.id, name: integration.name, kind: integration.kind, updatedAt: timestamp },
summary: data,
};
},
const { data, timestamp } = await dnsHoleRequestHandler.handler(integration, {}).getDataAsync();
return {
integration: { id: integration.id, name: integration.name, kind: integration.kind, updatedAt: timestamp },
summary: data,
};
},
{ queryKey: integrationQueryKey("dns-hole", "summary") },
);
}),
+12 -8
View File
@@ -28,14 +28,18 @@ export const downloadsRouter = createTRPCRouter({
return await settleIntegrationQueries(
ctx.integrations,
async (integration) => {
const innerHandler = downloadClientRequestHandler.handler(integration, { limit: input.limitPerIntegration });
const { data, timestamp } = await innerHandler.getDataAsync();
return {
integration: { id: integration.id, name: integration.name, kind: integration.kind, updatedAt: timestamp },
data,
};
},
{ queryKey: integrationQueryKey("downloads", "getJobsAndStatuses", { limitPerIntegration: input.limitPerIntegration }) },
const innerHandler = downloadClientRequestHandler.handler(integration, { limit: input.limitPerIntegration });
const { data, timestamp } = await innerHandler.getDataAsync();
return {
integration: { id: integration.id, name: integration.name, kind: integration.kind, updatedAt: timestamp },
data,
};
},
{
queryKey: integrationQueryKey("downloads", "getJobsAndStatuses", {
limitPerIntegration: input.limitPerIntegration,
}),
},
);
}),
pause: protectedProcedure
+10 -7
View File
@@ -24,18 +24,21 @@ const queryFirewall = <
settleIntegrationQueries(
ctx.integrations,
async (integration) => {
const { data, timestamp } = await handler.handler(integration, {}).getDataAsync();
return {
integration: { id: integration.id, name: integration.name, kind: integration.kind, updatedAt: timestamp },
summary: data as Awaited<ReturnType<ReturnType<THandler["handler"]>["getDataAsync"]>>["data"],
};
},
const { data, timestamp } = await handler.handler(integration, {}).getDataAsync();
return {
integration: { id: integration.id, name: integration.name, kind: integration.kind, updatedAt: timestamp },
summary: data as Awaited<ReturnType<ReturnType<THandler["handler"]>["getDataAsync"]>>["data"],
};
},
{ queryKey },
),
);
export const firewallRouter = createTRPCRouter({
getFirewallCpuStatus: queryFirewall(firewallCpuRequestHandler, integrationQueryKey("firewall", "getFirewallCpuStatus")),
getFirewallCpuStatus: queryFirewall(
firewallCpuRequestHandler,
integrationQueryKey("firewall", "getFirewallCpuStatus"),
),
getFirewallInterfacesStatus: queryFirewall(
firewallInterfacesRequestHandler,
integrationQueryKey("firewall", "getFirewallInterfacesStatus"),
@@ -29,14 +29,14 @@ export const healthMonitoringRouter = createTRPCRouter({
return await settleIntegrationQueries(
ctx.integrations,
async (integration) => {
const { data, timestamp } = await systemInfoRequestHandler.handler(integration, {}).getDataAsync();
return {
integrationId: integration.id,
integrationName: integration.name,
healthInfo: data,
updatedAt: timestamp,
};
},
const { data, timestamp } = await systemInfoRequestHandler.handler(integration, {}).getDataAsync();
return {
integrationId: integration.id,
integrationName: integration.name,
healthInfo: data,
updatedAt: timestamp,
};
},
{ queryKey: integrationQueryKey("health-monitoring", "getSystemHealthStatus") },
);
}),
@@ -20,14 +20,14 @@ export const indexerManagerRouter = createTRPCRouter({
return await settleIntegrationQueries(
ctx.integrations,
async (integration) => {
const innerHandler = indexerManagerRequestHandler.handler(integration, {});
const { data: indexers } = await innerHandler.getDataAsync();
const innerHandler = indexerManagerRequestHandler.handler(integration, {});
const { data: indexers } = await innerHandler.getDataAsync();
return {
integrationId: integration.id,
indexers,
};
},
return {
integrationId: integration.id,
indexers,
};
},
{ queryKey: integrationQueryKey("indexer-manager", "getIndexersStatus") },
);
}),
@@ -12,19 +12,19 @@ export const mediaReleaseRouter = createTRPCRouter({
const results = await settleIntegrationQueries(
ctx.integrations,
async (integration) => {
const innerHandler = mediaReleaseRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
const innerHandler = mediaReleaseRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
return {
integration: {
id: integration.id,
name: integration.name,
kind: integration.kind,
updatedAt: timestamp,
},
releases: data,
};
},
return {
integration: {
id: integration.id,
name: integration.name,
kind: integration.kind,
updatedAt: timestamp,
},
releases: data,
};
},
{ queryKey: integrationQueryKey("media-release", "getMediaReleases") },
);
return results.flatMap((result) =>
@@ -29,9 +29,9 @@ export const mediaRequestsRouter = createTRPCRouter({
const results = await settleIntegrationQueries(
ctx.integrations,
async (integration) => {
const { data } = await mediaRequestListRequestHandler.handler(integration, input).getDataAsync();
return { integration: { id: integration.id, name: integration.name, kind: integration.kind }, data };
},
const { data } = await mediaRequestListRequestHandler.handler(integration, input).getDataAsync();
return { integration: { id: integration.id, name: integration.name, kind: integration.kind }, data };
},
{ queryKey: integrationQueryKey("media-requests", "getLatestRequests", input) },
);
return results
@@ -65,9 +65,9 @@ export const mediaRequestsRouter = createTRPCRouter({
const results = await settleIntegrationQueries(
ctx.integrations,
async (integration) => {
const { data } = await mediaRequestStatsRequestHandler.handler(integration, {}).getDataAsync();
return { integration: { id: integration.id, name: integration.name, kind: integration.kind }, data };
},
const { data } = await mediaRequestStatsRequestHandler.handler(integration, {}).getDataAsync();
return { integration: { id: integration.id, name: integration.name, kind: integration.kind }, data };
},
{ queryKey: integrationQueryKey("media-requests", "getStats") },
);
return {
@@ -26,12 +26,16 @@ export const mediaServerRouter = createTRPCRouter({
return await settleIntegrationQueries(
ctx.integrations,
async (integration) => {
const { data } = await mediaServerRequestHandler
.handler(integration, { showOnlyPlaying: input.showOnlyPlaying })
.getDataAsync();
return { integrationId: integration.id, integrationKind: integration.kind, sessions: data };
},
{ queryKey: integrationQueryKey("media-server", "getCurrentStreams", { showOnlyPlaying: input.showOnlyPlaying }) },
const { data } = await mediaServerRequestHandler
.handler(integration, { showOnlyPlaying: input.showOnlyPlaying })
.getDataAsync();
return { integrationId: integration.id, integrationKind: integration.kind, sessions: data };
},
{
queryKey: integrationQueryKey("media-server", "getCurrentStreams", {
showOnlyPlaying: input.showOnlyPlaying,
}),
},
);
}),
});
@@ -12,19 +12,19 @@ export const networkControllerRouter = createTRPCRouter({
return await settleIntegrationQueries(
ctx.integrations,
async (integration) => {
const innerHandler = networkControllerRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
const innerHandler = networkControllerRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
return {
integration: {
id: integration.id,
name: integration.name,
kind: integration.kind,
},
summary: data,
updatedAt: timestamp,
};
},
return {
integration: {
id: integration.id,
name: integration.name,
kind: integration.kind,
},
summary: data,
updatedAt: timestamp,
};
},
{ queryKey: integrationQueryKey("network-controller", "summary") },
);
}),
@@ -16,19 +16,19 @@ export const notificationsRouter = createTRPCRouter({
return await settleIntegrationQueries(
ctx.integrations,
async (integration) => {
const innerHandler = notificationsRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
const innerHandler = notificationsRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
return {
integration: {
id: integration.id,
name: integration.name,
kind: integration.kind,
updatedAt: timestamp,
},
data,
};
},
return {
integration: {
id: integration.id,
name: integration.name,
kind: integration.kind,
updatedAt: timestamp,
},
data,
};
},
{ queryKey: integrationQueryKey("notifications", "getNotifications") },
);
}),
@@ -11,17 +11,17 @@ export const speedtestTrackerRouter = createTRPCRouter({
return await settleIntegrationQueries(
ctx.integrations,
async (integration) => {
const innerHandler = speedtestTrackerRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
const innerHandler = speedtestTrackerRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
return {
integrationId: integration.id,
integrationName: integration.name,
integrationUrl: integration.url,
dashboard: data,
updatedAt: timestamp,
};
},
return {
integrationId: integration.id,
integrationName: integration.name,
integrationUrl: integration.url,
dashboard: data,
updatedAt: timestamp,
};
},
{ queryKey: integrationQueryKey("speedtest-tracker", "getDashboard") },
);
}),
+10 -10
View File
@@ -9,17 +9,17 @@ export const tracearrRouter = createTRPCRouter({
return await settleIntegrationQueries(
ctx.integrations,
async (integration) => {
const innerHandler = tracearrRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
const innerHandler = tracearrRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
return {
integrationId: integration.id,
integrationName: integration.name,
integrationUrl: integration.url,
dashboard: data,
updatedAt: timestamp,
};
},
return {
integrationId: integration.id,
integrationName: integration.name,
integrationUrl: integration.url,
dashboard: data,
updatedAt: timestamp,
};
},
{ queryKey: integrationQueryKey("tracearr", "getDashboard") },
);
}),
+10 -10
View File
@@ -18,17 +18,17 @@ export const traefikRouter = createTRPCRouter({
return await settleIntegrationQueries(
ctx.integrations,
async (integration) => {
const innerHandler = traefikRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
const innerHandler = traefikRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
return {
integrationId: integration.id,
integrationName: integration.name,
integrationUrl: integration.url,
dashboard: data,
updatedAt: timestamp,
};
},
return {
integrationId: integration.id,
integrationName: integration.name,
integrationUrl: integration.url,
dashboard: data,
updatedAt: timestamp,
};
},
{ queryKey: integrationQueryKey("traefik", "getDashboard") },
);
}),
+14 -14
View File
@@ -42,21 +42,21 @@ export const umamiRouter = createTRPCRouter({
return await settleIntegrationQueries(
ctx.integrations,
async (integration) => {
const innerHandler = umamiRequestHandler.handler(integration, {
websiteId: input.websiteId,
timeFrame: input.timeFrame,
eventName: input.eventName,
});
const { data, timestamp } = await innerHandler.getDataAsync();
const innerHandler = umamiRequestHandler.handler(integration, {
websiteId: input.websiteId,
timeFrame: input.timeFrame,
eventName: input.eventName,
});
const { data, timestamp } = await innerHandler.getDataAsync();
return {
integrationId: integration.id,
integrationName: integration.name,
integrationUrl: integration.url,
visitorStats: data,
updatedAt: timestamp,
};
},
return {
integrationId: integration.id,
integrationName: integration.name,
integrationUrl: integration.url,
visitorStats: data,
updatedAt: timestamp,
};
},
{
queryKey: integrationQueryKey("umami", "getVisitorStats", {
websiteId: input.websiteId,
+10 -10
View File
@@ -12,17 +12,17 @@ export const upsRouter = createTRPCRouter({
return await settleIntegrationQueries(
ctx.integrations,
async (integration) => {
const innerHandler = upsSummariesRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
const innerHandler = upsSummariesRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
return {
integrationId: integration.id,
integrationName: integration.name,
integrationUrl: integration.url,
summaries: data,
updatedAt: timestamp,
};
},
return {
integrationId: integration.id,
integrationName: integration.name,
integrationUrl: integration.url,
summaries: data,
updatedAt: timestamp,
};
},
{ queryKey: integrationQueryKey("ups", "getSummaries") },
);
}),
+10 -10
View File
@@ -11,17 +11,17 @@ export const uptimeKumaRouter = createTRPCRouter({
return await settleIntegrationQueries(
ctx.integrations,
async (integration) => {
const innerHandler = uptimeKumaRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
const innerHandler = uptimeKumaRequestHandler.handler(integration, {});
const { data, timestamp } = await innerHandler.getDataAsync();
return {
integrationId: integration.id,
integrationName: integration.name,
integrationUrl: integration.url,
dashboard: data,
updatedAt: timestamp,
};
},
return {
integrationId: integration.id,
integrationName: integration.name,
integrationUrl: integration.url,
dashboard: data,
updatedAt: timestamp,
};
},
{ queryKey: integrationQueryKey("uptime-kuma", "getDashboard") },
);
}),
+11 -11
View File
@@ -12,17 +12,17 @@ export const vpnRouter = createTRPCRouter({
return await settleIntegrationQueries(
ctx.integrations,
async (integration) => {
const { data, timestamp } = await vpnSummaryHandler.handler(integration, {}).getDataAsync();
return {
integration: {
id: integration.id,
name: integration.name,
kind: integration.kind,
updatedAt: timestamp,
},
summary: data,
};
},
const { data, timestamp } = await vpnSummaryHandler.handler(integration, {}).getDataAsync();
return {
integration: {
id: integration.id,
name: integration.name,
kind: integration.kind,
updatedAt: timestamp,
},
summary: data,
};
},
{ queryKey: integrationQueryKey("vpn", "getSummaries") },
);
}),