Compare commits

..
Author SHA1 Message Date
ajnart b650bffaa8 fix(request-handler): restore cacheTtlMs values lost in v1.69.0 refactor
The v1.69.0 caching refactor (f19033e0d) replaced the old Redis-backed
cached request handler with a simpler in-memory handler but dropped
all per-handler cacheDuration values, defaulting everything to 10s.
This caused widgets that previously had short cache durations (e.g.
health-monitoring at 5s, dns-hole at 5s) to refresh much less
frequently since the client polls every 30s.

Restores cacheTtlMs for all affected request handlers to match their
pre-v1.69.0 values. Also adds cacheTtlMs support to
createWidgetRequestHandler which was missing it.

Beszel handlers are intentionally left untouched as they have their
own cache handling.

Fixes #6268
2026-07-15 10:53:36 +02:00
homarr-renovate[bot] a0034b2cfc chore(deps): update dependency @immich/sdk to ^3.0.2 (#6339)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-14 21:01:58 +00:00
homarr-renovate[bot] 4a297180fd chore(deps): update dependency lucide-react to ^1.24.0 (#6334)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-14 19:23:26 +00:00
Thomas 5fa3a3313a Merge pull request #6337 from homarr-labs/fix/ts7-nextjs-build
fix(docker): pin TypeScript to v6 to fix Next.js 16.2.10 build in CI
2026-07-14 18:11:38 +02:00
Thomas Camlong 29ee87c4aa fix(docker): pin typescript to v6 via alias to fix Next.js 16.2.10 build 2026-07-14 18:11:15 +02:00
Thomas 94a247e24a fix(docker): remove --offline flag from pnpm install step (#6335) 2026-07-14 17:19:51 +02:00
homarr-renovate[bot] 6d37710fec chore(deps): update dependency vite@>=5.0.0 <=5.4.18 to >=8.1.4 (#6333)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-14 11:26:55 +00:00
homarr-renovate[bot] c016beb2e5 chore(deps): update dependency vite to ^8.1.4 (#6332)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-14 09:06:17 +00:00
homarr-renovate[bot] f9e1b85c6a chore(deps): update dependency posthog-node to ^5.40.0 (#6314)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-14 06:14:41 +00:00
homarr-renovate[bot] 38ba19e665 chore(deps): update dependency oxlint to ^1.73.0 (#6306)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-14 03:22:16 +00:00
homarr-renovate[bot] f55c99d2d6 chore(deps): update dependency posthog-js to ^1.399.0 (#6331)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-14 00:00:38 +00:00
homarr-renovate[bot] c5e8b83d8a chore(deps): update vitest monorepo to ^4.1.10 (#6286)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-13 23:01:00 +00:00
homarr-renovate[bot] d52d9cfed2 chore(deps): update dependency posthog-js to ^1.398.7 (#6319)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-13 21:58:26 +00:00
Thomas 93325642aa Merge pull request #6324 from homarr-labs/renovate/major-github-artifact-actions 2026-07-13 22:12:32 +02:00
Thomas 165e94abbc Merge pull request #6328 from homarr-labs/fix-pnpm-fetch-build 2026-07-13 22:12:11 +02:00
homarr-renovate[bot] 2e3127e766 chore(deps): update docker/dockerfile docker tag to v1.25 (#6321) 2026-07-13 22:10:35 +02:00
Thomas d37326d905 Merge pull request #6322 from homarr-labs/renovate/actions-cache-6-x 2026-07-13 22:09:57 +02:00
homarr-renovate[bot] e51e39ff38 chore(deps): update dependency typescript to v7 (#6325) 2026-07-13 22:09:30 +02:00
homarr-renovate[bot] 6c075b6d74 chore(deps): update dependency mysql2 to v3.22.6 (#6310)
Co-authored-by: homarr-renovate[bot] <158783068+homarr-renovate[bot]@users.noreply.github.com>
2026-07-13 18:45:08 +00:00
homarr-renovate[bot] 1c0ff8930e chore(deps): update actions/upload-artifact action to v7 2026-07-13 16:39:27 +00:00
homarr-renovate[bot] e2b8355639 chore(deps): update actions/cache action to v6 2026-07-13 16:39:10 +00:00
37 changed files with 626 additions and 659 deletions

No files matched your search

+2 -2
View File
@@ -167,7 +167,7 @@ jobs:
- name: Cache Playwright browsers
if: '!env.ACT'
id: playwright-cache
uses: actions/cache@v4
uses: actions/cache@v6
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
@@ -185,7 +185,7 @@ jobs:
- name: Upload E2E artifacts
if: failure() && !env.ACT
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: playwright-report
path: e2e/test-results/
+2 -3
View File
@@ -1,4 +1,4 @@
# syntax=docker/dockerfile:1.10
# syntax=docker/dockerfile:1.25
FROM node:24.18.0-alpine AS base
@@ -24,10 +24,9 @@ RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store \
COPY . .
# Follow the pnpm fetch pattern from https://pnpm.io/cli/fetch
# --offline enforces no registry access (all packages are in the store from fetch)
# --frozen-lockfile is omitted as recommended by the pnpm fetch docs
RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store \
pnpm install --recursive --offline
pnpm install --recursive
ARG SKIP_ENV_VALIDATION='true'
ARG CI='true'
@@ -12,6 +12,7 @@ export const anchorNotesListRequestHandler = createIntegrationRequestHandler<
const instance = await createIntegrationAsync(integration);
return instance.listNotesAsync(input);
},
cacheTtlMs: 15_000,
});
export const anchorNoteRequestHandler = createIntegrationRequestHandler<AnchorNote, "anchor", { noteId: string }>({
@@ -19,4 +20,5 @@ export const anchorNoteRequestHandler = createIntegrationRequestHandler<AnchorNo
const instance = await createIntegrationAsync(integration);
return instance.getNoteAsync(input.noteId);
},
cacheTtlMs: 15_000,
});
@@ -13,4 +13,5 @@ export const archiveTeamWarriorRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getStatusAsync();
},
cacheTtlMs: 300_000,
});
@@ -12,4 +12,5 @@ export const audiobookshelfRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getDashboardDataAsync();
},
cacheTtlMs: 600_000,
});
+1
View File
@@ -23,4 +23,5 @@ export const calendarMonthRequestHandler = createIntegrationRequestHandler<
input.showUnmonitored,
);
},
cacheTtlMs: 60_000,
});
+1
View File
@@ -12,4 +12,5 @@ export const coolifyRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getInstanceInfoAsync();
},
cacheTtlMs: 30_000,
});
+1
View File
@@ -13,4 +13,5 @@ export const dnsHoleRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getSummaryAsync();
},
cacheTtlMs: 5_000,
});
+1
View File
@@ -177,6 +177,7 @@ export const dockerContainersRequestHandler = createWidgetRequestHandler({
}
return await getContainersWithStatsAsync();
},
cacheTtlMs: 20_000,
});
const extractImage = (container: ContainerInfo) => extractContainerImageName(container.Image);
@@ -13,4 +13,5 @@ export const downloadClientRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getClientJobsAndStatusAsync(input);
},
cacheTtlMs: 5_000,
});
@@ -69,4 +69,5 @@ export const duckDuckGoBangsRequestHandler = createRequestHandler({
return normalized;
},
cacheTtlMs: 86_400_000,
});
+4
View File
@@ -18,6 +18,7 @@ export const firewallCpuRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return integrationInstance.getFirewallCpuAsync();
},
cacheTtlMs: 5_000,
});
export const firewallMemoryRequestHandler = createIntegrationRequestHandler<
@@ -29,6 +30,7 @@ export const firewallMemoryRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getFirewallMemoryAsync();
},
cacheTtlMs: 15_000,
});
export const firewallInterfacesRequestHandler = createIntegrationRequestHandler<
@@ -40,6 +42,7 @@ export const firewallInterfacesRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getFirewallInterfacesAsync();
},
cacheTtlMs: 30_000,
});
export const firewallVersionRequestHandler = createIntegrationRequestHandler<
@@ -51,4 +54,5 @@ export const firewallVersionRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getFirewallVersionAsync();
},
cacheTtlMs: 3_600_000,
});
@@ -13,6 +13,7 @@ export const systemInfoRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getSystemInfoAsync();
},
cacheTtlMs: 5_000,
});
export const clusterInfoRequestHandler = createIntegrationRequestHandler<
@@ -24,4 +25,5 @@ export const clusterInfoRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getClusterInfoAsync();
},
cacheTtlMs: 5_000,
});
+3
View File
@@ -13,6 +13,7 @@ export const immichStatsRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getServerStatsAsync();
},
cacheTtlMs: 900_000,
});
export const immichAlbumsRequestHandler = createIntegrationRequestHandler<
@@ -28,6 +29,7 @@ export const immichAlbumsRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getAlbumsAsync();
},
cacheTtlMs: 900_000,
});
export const immichAlbumRequestHandler = createIntegrationRequestHandler<
@@ -39,4 +41,5 @@ export const immichAlbumRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getAlbumAsync(input.albumId);
},
cacheTtlMs: 900_000,
});
@@ -13,4 +13,5 @@ export const indexerManagerRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getIndexersAsync();
},
cacheTtlMs: 300_000,
});
@@ -2,6 +2,7 @@ import { createRequestHandler } from "./request-handler";
interface Options<TData, TInput extends Record<string, unknown>> {
requestAsync: (input: TInput) => Promise<TData>;
cacheTtlMs?: number;
}
export const createWidgetRequestHandler = <TData, TInput extends Record<string, unknown>>(
@@ -10,5 +11,6 @@ export const createWidgetRequestHandler = <TData, TInput extends Record<string,
handler: (widgetOptions: TInput) =>
createRequestHandler<TData, TInput>({
requestAsync: options.requestAsync,
cacheTtlMs: options.cacheTtlMs,
}).handler(widgetOptions),
});
@@ -13,4 +13,5 @@ export const mediaReleaseRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getMediaReleasesAsync();
},
cacheTtlMs: 300_000,
});
@@ -16,4 +16,5 @@ export const mediaRequestStatsRequestHandler = createIntegrationRequestHandler<
users: await integrationInstance.getUsersAsync(),
};
},
cacheTtlMs: 60_000,
});
@@ -15,4 +15,5 @@ export const mediaServerRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getCurrentSessionsAsync({ showOnlyPlaying: input.showOnlyPlaying });
},
cacheTtlMs: 5_000,
});
@@ -17,6 +17,7 @@ export const mediaTranscodingRequestHandler = createIntegrationRequestHandler<
statistics: await integrationInstance.getStatisticsAsync(),
};
},
cacheTtlMs: 300_000,
});
export interface MediaTranscoding {
@@ -14,6 +14,7 @@ export const minecraftServerStatusRequestHandler = createWidgetRequestHandler({
);
return responseSchema.parse(await response.json());
},
cacheTtlMs: 300_000,
});
const responseSchema = z
@@ -12,4 +12,5 @@ export const navidromeRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getDashboardDataAsync();
},
cacheTtlMs: 600_000,
});
@@ -13,4 +13,5 @@ export const networkControllerRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getNetworkSummaryAsync();
},
cacheTtlMs: 300_000,
});
@@ -13,4 +13,5 @@ export const notificationsRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getNotificationsAsync();
},
cacheTtlMs: 300_000,
});
@@ -12,4 +12,5 @@ export const paperlessNgxStatsRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getStatsAsync();
},
cacheTtlMs: 900_000,
});
@@ -28,6 +28,7 @@ export const rssFeedsRequestHandler = createWidgetRequestHandler({
entries: result.entries?.map((entry) => ({ ...entry, feedUrl: input.url })).slice(0, input.count) ?? [],
};
},
cacheTtlMs: 300_000,
});
const attemptGetImageFromEntry = (feedUrl: string, entry: object) => {
@@ -18,4 +18,5 @@ export const smartHomeEntityStateRequestHandler = createIntegrationRequestHandle
return result.data.state;
},
cacheTtlMs: 60_000,
});
@@ -12,4 +12,5 @@ export const speedtestTrackerRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getDashboardDataAsync();
},
cacheTtlMs: 600_000,
});
@@ -39,6 +39,7 @@ export const fetchStockPriceHandler = createWidgetRequestHandler({
shortName: firstResult.meta.shortName,
};
},
cacheTtlMs: 300_000,
});
const dataSchema = z
+1
View File
@@ -12,4 +12,5 @@ export const tracearrRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getDashboardDataAsync();
},
cacheTtlMs: 5_000,
});
+6
View File
@@ -12,6 +12,7 @@ export const umamiRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getVisitorStatsAsync(input.websiteId, input.timeFrame, input.eventName);
},
cacheTtlMs: 300_000,
});
export const umamiEventNamesRequestHandler = createIntegrationRequestHandler<string[], "umami", { websiteId: string }>({
@@ -19,6 +20,7 @@ export const umamiEventNamesRequestHandler = createIntegrationRequestHandler<str
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getEventNamesAsync(input.websiteId);
},
cacheTtlMs: 300_000,
});
export const umamiTopPagesRequestHandler = createIntegrationRequestHandler<
@@ -30,6 +32,7 @@ export const umamiTopPagesRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getTopPagesAsync(input.websiteId, input.timeFrame, input.limit);
},
cacheTtlMs: 300_000,
});
export const umamiTopReferrersRequestHandler = createIntegrationRequestHandler<
@@ -41,6 +44,7 @@ export const umamiTopReferrersRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getTopReferrersAsync(input.websiteId, input.timeFrame, input.limit);
},
cacheTtlMs: 300_000,
});
export const umamiMultiEventRequestHandler = createIntegrationRequestHandler<
@@ -52,6 +56,7 @@ export const umamiMultiEventRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getMultiEventTimeSeriesAsync(input.websiteId, input.timeFrame, input.eventNames);
},
cacheTtlMs: 300_000,
});
export const umamiActiveVisitorsRequestHandler = createIntegrationRequestHandler<
@@ -63,4 +68,5 @@ export const umamiActiveVisitorsRequestHandler = createIntegrationRequestHandler
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getActiveVisitorsAsync(input.websiteId);
},
cacheTtlMs: 30_000,
});
+1
View File
@@ -13,4 +13,5 @@ export const upsSummariesRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getUpsSummariesAsync();
},
cacheTtlMs: 60_000,
});
@@ -12,4 +12,5 @@ export const uptimeKumaRequestHandler = createIntegrationRequestHandler<
const integrationInstance = await createIntegrationAsync(integration);
return await integrationInstance.getDashboardDataAsync();
},
cacheTtlMs: 60_000,
});
+1
View File
@@ -25,4 +25,5 @@ export const vpnSummaryHandler = createIntegrationRequestHandler<
return null;
}
},
cacheTtlMs: 300_000,
});
+1
View File
@@ -31,6 +31,7 @@ export const weatherRequestHandler = createWidgetRequestHandler({
}),
} satisfies Weather;
},
cacheTtlMs: 60_000,
});
const atLocationOutput = z.object({
+564 -642
View File
File diff suppressed because it is too large. Load diff
+12 -12
View File
@@ -18,7 +18,7 @@ catalog:
"@gitbeaker/rest": ^43.8.0
"@homarr/gridstack": ^1.12.0
"@homarr/node-unifi": ^2.6.0
"@immich/sdk": ^3.0.1
"@immich/sdk": ^3.0.2
"@jellyfin/sdk": ^0.13.0
"@kubernetes/client-node": ^1.4.0
"@modelcontextprotocol/sdk": 1.29.0
@@ -93,11 +93,11 @@ catalog:
"@types/video.js": ^7.3.58
"@types/ws": ^8.18.1
"@types/xml2js": ^0.4.14
posthog-js: ^1.398.2
posthog-node: ^5.39.2
posthog-js: ^1.399.0
posthog-node: ^5.40.0
"@vitejs/plugin-react": ^6.0.3
"@vitest/coverage-v8": ^4.1.9
"@vitest/ui": ^4.1.9
"@vitest/coverage-v8": ^4.1.10
"@vitest/ui": ^4.1.10
"@xterm/addon-canvas": ^0.7.0
"@xterm/addon-fit": 0.11.0
"@xterm/xterm": ^6.0.0
@@ -139,20 +139,20 @@ catalog:
jsonpath-plus: ^10.4.0
ldapts: 8.1.8
lodash.clonedeep: ^4.5.0
lucide-react: ^1.23.0
lucide-react: ^1.24.0
"mantine-contextmenu": ^9.3.1
mantine-datatable: ^9.3.1
mantine-react-table: npm:mantine-react-table-open@9.0.3
mcp-handler: ^1.1.0
maria2: ^0.4.1
mysql2: 3.22.5
mysql2: 3.22.6
next: 16.2.10
next-auth: 5.0.0-beta.31
next-intl: 4.13.1
node-loader: ^2.1.0
octokit: ^5.0.5
oxfmt: ^0.58.0
oxlint: ^1.72.0
oxlint: ^1.73.0
pg: ^8.22.0
postcss-preset-mantine: ^1.18.0
prismjs: ^1.30.0
@@ -177,13 +177,13 @@ catalog:
tsdav: ^2.3.0
tsx: 4.20.4
turbo: ^2.10.4
typescript: ^6.0.3
vite: ^8.1.2
typescript: "npm:@typescript/typescript6@^6.0.2"
vite: ^8.1.4
undici: 7.28.0
use-deep-compare-effect: ^1.8.1
video.js: ^8.23.9
vite-tsconfig-paths: ^6.1.1
vitest: ^4.1.9
vitest: ^4.1.10
winston: 3.19.0
ws: ^8.21.0
xml2js: ^0.6.2
@@ -229,7 +229,7 @@ overrides:
"tar-fs@>=3.0.0 <3.0.9": ">=3.1.3"
"tar-fs@>=2.0.0 <2.1.3": ">=3.1.3"
"tmp@<=0.2.3": ">=0.2.7"
"vite@>=5.0.0 <=5.4.18": ">=8.1.3"
"vite@>=5.0.0 <=5.4.18": ">=8.1.4"
patchedDependencies:
"@types/node-unifi": "patches/@types__node-unifi.patch"
"trpc-to-openapi": "patches/trpc-to-openapi.patch"