revert(version): undo version refactor and tests, keep single-file change

Keep the User-Agent change as a single edit to
packages/core/src/infrastructure/http/request.ts. Remove the @homarr/version
package, the consumer migrations, and the unit tests.
This commit is contained in:
ajnart committed 2026-08-16 15:50:35 +02:00
1 parent 44d7426e9f
commit 1b74d73de0
13 files changed
+19 -154

No files matched your search

-1
View File
@@ -26,7 +26,6 @@
"@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: VERSION,
homarrVersion: packageJson.version,
databaseType: isMysql() ? "mysql" : isPostgresql() ? "postgresql" : "sqlite",
dockerEnabled: Boolean(dockerEnv.ENABLE_DOCKER),
kubernetesEnabled: Boolean(dockerEnv.ENABLE_KUBERNETES),
-1
View File
@@ -46,7 +46,6 @@
"@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:",
+2 -3
View File
@@ -1,7 +1,6 @@
import z from "zod/v4";
import { VERSION } from "@homarr/version";
import packageJson from "../../../../package.json";
import { createTRPCRouter, isDemoMode, isDemoReadOnly, publicProcedure, protectedProcedure } from "../trpc";
export const infoRouter = createTRPCRouter({
@@ -17,7 +16,7 @@ export const infoRouter = createTRPCRouter({
})
.query(() => {
return {
version: VERSION,
version: packageJson.version,
};
}),
isDemoMode: publicProcedure.query(() => isDemoMode),
-1
View File
@@ -36,7 +36,6 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@homarr/version": "workspace:^0.1.0",
"@t3-oss/env-nextjs": "catalog:",
"better-sqlite3": "catalog:",
"dns-caching": "catalog:",
@@ -1,77 +0,0 @@
import { describe, expect, it, vi, beforeEach } from "vitest";
const { fetchMock } = vi.hoisted(() => ({ fetchMock: vi.fn() }));
vi.mock("undici", async (importOriginal) => {
const actual = await (importOriginal as () => Promise<Record<string, unknown>>)();
return { ...actual, fetch: fetchMock };
});
import { Headers } from "undici";
import { fetchWithTrustedCertificatesAsync, getDefaultUserAgent } from "./request";
const dummyDispatcher = {} as never;
const lastFetchHeaders = (): Headers => {
const [, init] = fetchMock.mock.calls.at(-1) ?? [];
return init?.headers as unknown as Headers;
};
describe("fetchWithTrustedCertificatesAsync default User-Agent", () => {
beforeEach(() => {
fetchMock.mockReset();
});
const defaultUserAgent = getDefaultUserAgent();
it("sets the default User-Agent when no header is provided", async () => {
await fetchWithTrustedCertificatesAsync("https://example.com", { dispatcher: dummyDispatcher });
expect(lastFetchHeaders().get("User-Agent")).toBe(defaultUserAgent);
});
it("keeps caller-provided record headers", async () => {
await fetchWithTrustedCertificatesAsync("https://example.com", {
dispatcher: dummyDispatcher,
headers: { Authorization: "token" },
});
const headers = lastFetchHeaders();
expect(headers.get("authorization")).toBe("token");
expect(headers.get("User-Agent")).toBe(defaultUserAgent);
});
it("normalizes a Headers instance without losing entries", async () => {
await fetchWithTrustedCertificatesAsync("https://example.com", {
dispatcher: dummyDispatcher,
headers: new Headers({ "x-custom": "present" }),
});
const headers = lastFetchHeaders();
expect(headers.get("x-custom")).toBe("present");
expect(headers.get("User-Agent")).toBe(defaultUserAgent);
});
it("normalizes a tuple-array of headers", async () => {
await fetchWithTrustedCertificatesAsync("https://example.com", {
dispatcher: dummyDispatcher,
headers: [["x-tuple", "value"]],
});
const headers = lastFetchHeaders();
expect(headers.get("x-tuple")).toBe("value");
expect(headers.get("User-Agent")).toBe(defaultUserAgent);
});
it("does not override a caller-provided User-Agent regardless of casing", async () => {
await fetchWithTrustedCertificatesAsync("https://example.com", {
dispatcher: dummyDispatcher,
headers: { "user-agent": "custom-agent" },
});
expect(lastFetchHeaders().get("User-Agent")).toBe("custom-agent");
});
it("sets the default User-Agent on the timeout path too", async () => {
await fetchWithTrustedCertificatesAsync("https://example.com", {
dispatcher: dummyDispatcher,
timeout: 1000,
});
expect(lastFetchHeaders().get("User-Agent")).toBe(defaultUserAgent);
});
});
@@ -3,27 +3,20 @@ import { Agent as HttpsAgent } from "node:https";
import { checkServerIdentity } from "node:tls";
import axios from "axios";
import type { Agent as UndiciAgent, RequestInfo, RequestInit, Response } from "undici";
import { Headers, fetch } from "undici";
import { fetch } from "undici";
import {
getAllTrustedCertificatesAsync,
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";
export const getDefaultUserAgent = () => `Homarr/${VERSION} (+https://homarr.dev)`;
import packageJson from "../../../../../package.json";
const createFetchHeaders = (initial: RequestInit["headers"]): Headers => {
const headers = new Headers(initial);
if (!headers.has("User-Agent")) {
headers.set("User-Agent", getDefaultUserAgent());
}
return headers;
};
export const getDefaultUserAgent = () => `Homarr/${packageJson.version} (+https://homarr.dev)`;
export const createCustomCheckServerIdentity = (
trustedHostnames: TrustedCertificateHostname[],
@@ -90,7 +83,10 @@ export const fetchWithTrustedCertificatesAsync = async (
async (signal) =>
fetch(url, {
...fetchOptions,
headers: createFetchHeaders(fetchOptions.headers),
headers: {
"User-Agent": getDefaultUserAgent(),
...fetchOptions.headers,
},
signal,
dispatcher: agent,
}),
@@ -101,7 +97,10 @@ export const fetchWithTrustedCertificatesAsync = async (
const { bodyTimeout: _bodyTimeout, dispatcher: _dispatcher, ...fetchOptions } = options ?? {};
return fetch(url, {
...fetchOptions,
headers: createFetchHeaders(fetchOptions.headers),
headers: {
"User-Agent": getDefaultUserAgent(),
...fetchOptions.headers,
},
dispatcher: agent,
});
};
-1
View File
@@ -29,7 +29,6 @@
"@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,7 +6,8 @@ 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 { VERSION } from "@homarr/version";
import packageJson from "../../../package.json";
const logger = createLogger({ module: "updateCheckerRequestHandler" });
@@ -21,7 +22,7 @@ type UpdateCheckCacheEntry = {
checkedAt: number | null;
};
const updateCheckCacheVersion = `v2:${VERSION}`;
const updateCheckCacheVersion = `v2:${packageJson.version}`;
const freshUpdateCheckChannel = createGetSetChannel<UpdateCheckCacheEntry>(
`update-checker:fresh:${updateCheckCacheVersion}`,
);
@@ -68,7 +69,7 @@ const getCachedAvailableUpdatesAsync = async (): Promise<UpdateCheckCacheEntry>
try {
const attemptedAt = Date.now();
const availableUpdates = await getAvailableUpdatesAsync(VERSION);
const availableUpdates = await getAvailableUpdatesAsync(packageJson.version);
const result: UpdateCheckCacheEntry = {
availableUpdates,
attemptedAt,
-3
View File
@@ -1,3 +0,0 @@
import packageJson from "../../package.json";
export const VERSION = packageJson.version;
-20
View File
@@ -1,20 +0,0 @@
{
"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
@@ -1,8 +0,0 @@
{
"extends": "@homarr/tsconfig/base.json",
"compilerOptions": {
"tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json"
},
"include": ["*.ts", "src"],
"exclude": ["node_modules"]
}
-22
View File
@@ -1241,9 +1241,6 @@ 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)
@@ -1314,9 +1311,6 @@ 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)
@@ -1526,9 +1520,6 @@ 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)
@@ -2265,9 +2256,6 @@ 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
@@ -2525,15 +2513,6 @@ 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':
@@ -9428,7 +9407,6 @@ 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==}