refactor(version): centralize Homarr version in @homarr/version package

Replace fragile deep-relative 'package.json' imports across the monorepo
with a single source of truth: the new @homarr/version leaf package reads
the version once from the root package.json and exports it as VERSION.

Consumers now import by package name incl. the new User-Agent header in
fetchWithTrustedCertificatesAsync (packages/core):
  - core, api (info router), analytics, request-handler (update checker)
This also removes all manually-maintained relative version imports.
This commit is contained in:
ajnart committed 2026-08-16 15:24:07 +02:00
1 parent 25b7657a79
commit c08ad3a69a
12 files changed
+67 -11

No files matched your search

+1
View File
@@ -26,6 +26,7 @@
"@homarr/core": "workspace:^0.1.0",
"@homarr/db": "workspace:^0.1.0",
"@homarr/docker": "workspace:^0.1.0",
"@homarr/version": "workspace:^0.1.0",
"posthog-node": "catalog:"
},
"devDependencies": {
@@ -28,8 +28,8 @@ import {
users,
} from "@homarr/db/schema";
import { env as dockerEnv } from "@homarr/docker/env";
import { VERSION } from "@homarr/version";
import packageJson from "../../../package.json";
import { getPostHogClient } from "./client";
const logger = createLogger({ module: "analytics" });
@@ -121,7 +121,7 @@ export const sendServerAnalyticsAsync = async (): Promise<AnalyticsResult> => {
const enabledAuthProviders = (["credentials", "oidc", "ldap"] as const).filter(isProviderEnabled);
const properties: Record<string, unknown> = {
homarrVersion: packageJson.version,
homarrVersion: VERSION,
databaseType: isMysql() ? "mysql" : isPostgresql() ? "postgresql" : "sqlite",
dockerEnabled: Boolean(dockerEnv.ENABLE_DOCKER),
kubernetesEnabled: Boolean(dockerEnv.ENABLE_KUBERNETES),
+1
View File
@@ -46,6 +46,7 @@
"@homarr/server-settings": "workspace:^0.1.0",
"@homarr/translation": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0",
"@homarr/version": "workspace:^0.1.0",
"@kubernetes/client-node": "catalog:",
"@tanstack/react-query": "catalog:",
"@trpc/client": "catalog:",
+3 -2
View File
@@ -1,6 +1,7 @@
import z from "zod/v4";
import packageJson from "../../../../package.json";
import { VERSION } from "@homarr/version";
import { createTRPCRouter, isDemoMode, isDemoReadOnly, publicProcedure, protectedProcedure } from "../trpc";
export const infoRouter = createTRPCRouter({
@@ -16,7 +17,7 @@ export const infoRouter = createTRPCRouter({
})
.query(() => {
return {
version: packageJson.version,
version: VERSION,
};
}),
isDemoMode: publicProcedure.query(() => isDemoMode),
+1
View File
@@ -36,6 +36,7 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@homarr/version": "workspace:^0.1.0",
"@t3-oss/env-nextjs": "catalog:",
"better-sqlite3": "catalog:",
"dns-caching": "catalog:",
@@ -10,13 +10,12 @@ import {
getTrustedCertificateHostnamesAsync,
} from "@homarr/core/infrastructure/certificates";
import { UndiciHttpAgent } from "@homarr/core/infrastructure/http";
import { VERSION } from "@homarr/version";
import type { TrustedCertificateHostname } from "../certificates/hostnames";
import { withTimeoutAsync } from "./timeout";
import packageJson from "../../../../../package.json";
export const getDefaultUserAgent = () => `Homarr/${packageJson.version} (+https://homarr.dev)`;
export const getDefaultUserAgent = () => `Homarr/${VERSION} (+https://homarr.dev)`;
export const createCustomCheckServerIdentity = (
trustedHostnames: TrustedCertificateHostname[],
+1
View File
@@ -29,6 +29,7 @@
"@homarr/docker": "workspace:^0.1.0",
"@homarr/integrations": "workspace:^0.1.0",
"@homarr/redis": "workspace:^0.1.0",
"@homarr/version": "workspace:^0.1.0",
"dayjs": "catalog:",
"octokit": "catalog:",
"superjson": "catalog:",
@@ -6,8 +6,7 @@ import { fetchWithTrustedCertificatesAsync } from "@homarr/core/infrastructure/h
import { createLogger } from "@homarr/core/infrastructure/logs";
import { ErrorWithMetadata } from "@homarr/core/infrastructure/logs/error";
import { createGetSetChannel, createLockChannel } from "@homarr/redis";
import packageJson from "../../../package.json";
import { VERSION } from "@homarr/version";
const logger = createLogger({ module: "updateCheckerRequestHandler" });
@@ -22,7 +21,7 @@ type UpdateCheckCacheEntry = {
checkedAt: number | null;
};
const updateCheckCacheVersion = `v2:${packageJson.version}`;
const updateCheckCacheVersion = `v2:${VERSION}`;
const freshUpdateCheckChannel = createGetSetChannel<UpdateCheckCacheEntry>(
`update-checker:fresh:${updateCheckCacheVersion}`,
);
@@ -69,7 +68,7 @@ const getCachedAvailableUpdatesAsync = async (): Promise<UpdateCheckCacheEntry>
try {
const attemptedAt = Date.now();
const availableUpdates = await getAvailableUpdatesAsync(packageJson.version);
const availableUpdates = await getAvailableUpdatesAsync(VERSION);
const result: UpdateCheckCacheEntry = {
availableUpdates,
attemptedAt,
+3
View File
@@ -0,0 +1,3 @@
import packageJson from "../../package.json";
export const VERSION = packageJson.version;
+20
View File
@@ -0,0 +1,20 @@
{
"name": "@homarr/version",
"version": "0.1.0",
"private": true,
"license": "Apache-2.0",
"type": "module",
"exports": {
".": "./index.ts"
},
"scripts": {
"clean": "rm -rf .turbo node_modules",
"format": "oxfmt .",
"lint": "oxlint",
"typecheck": "tsc --noEmit"
},
"devDependencies": {
"@homarr/tsconfig": "workspace:^0.1.0",
"typescript": "catalog:"
}
}
+8
View File
@@ -0,0 +1,8 @@
{
"extends": "@homarr/tsconfig/base.json",
"compilerOptions": {
"tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json"
},
"include": ["*.ts", "src"],
"exclude": ["node_modules"]
}
+22
View File
@@ -1241,6 +1241,9 @@ importers:
'@homarr/docker':
specifier: workspace:^0.1.0
version: link:../docker
'@homarr/version':
specifier: workspace:^0.1.0
version: link:../version
posthog-node:
specifier: 'catalog:'
version: 5.41.0(rxjs@7.8.2)
@@ -1311,6 +1314,9 @@ importers:
'@homarr/validation':
specifier: workspace:^0.1.0
version: link:../validation
'@homarr/version':
specifier: workspace:^0.1.0
version: link:../version
'@kubernetes/client-node':
specifier: 'catalog:'
version: 1.4.0(supports-color@10.2.2)
@@ -1520,6 +1526,9 @@ importers:
packages/core:
dependencies:
'@homarr/version':
specifier: workspace:^0.1.0
version: link:../version
'@t3-oss/env-nextjs':
specifier: 'catalog:'
version: 0.13.11(arktype@2.1.20)(typescript@7.0.2)(zod@4.4.3)
@@ -2256,6 +2265,9 @@ importers:
'@homarr/redis':
specifier: workspace:^0.1.0
version: link:../redis
'@homarr/version':
specifier: workspace:^0.1.0
version: link:../version
dayjs:
specifier: 'catalog:'
version: 1.11.21
@@ -2513,6 +2525,15 @@ importers:
specifier: 'catalog:'
version: 7.0.2
packages/version:
devDependencies:
'@homarr/tsconfig':
specifier: workspace:^0.1.0
version: link:../../tooling/typescript
typescript:
specifier: 'catalog:'
version: 7.0.2
packages/widgets:
dependencies:
'@dnd-kit/core':
@@ -9407,6 +9428,7 @@ packages:
crypto-js@4.2.0:
resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
deprecated: Active development of CryptoJS has been discontinued. This library is no longer maintained.
crypto-random-string@4.0.0:
resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==}