The widget stub (packages/widgets/src/unifi-os/) was incorrectly added in
Task 6 and belongs to Task 7. Its removal confirms the type system does not
require it, and prevents inconsistencies: the stub declares IconWifi while
Task 7 specifies IconRouter, and it is not registered in manifest.ts,
catalog.ts or refetch-intervals.ts.
- Delete packages/widgets/src/unifi-os/ directory entirely
- Revert packages/widgets/src/index.tsx to commit 57286d83d
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Create unifiOs request handler with 60s cache and stale-on-error fallback, and tRPC router exposing clientApi.widget.unifiOs.summary query. Include minimal widget stub for type system.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Introduces UnifiOsIntegration, orchestrating UnifiOsApi (local) and
UnifiSmApi (optional cloud) to build the UnifiOsSummary. Local endpoint
calls degrade independently via Promise.allSettled; the cloud client is
never instantiated without a configured siteManagerApiKey secret.
Registers the unifiOs kind in the integration creator, index, and types
barrels, resolving the previously-failing typecheck.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Task 4 of the UniFi OS integration: an optional cloud client for
Ubiquiti's Site Manager API that enriches the local console with ISP
latency data. Instantiated only when a cloud API key is configured
(Task 5). Every failure path (bad key, non-ok status, parse error,
unmatched gateway MAC) returns null rather than throwing, since the
cloud is a pure enrichment. Metrics are cached 5 minutes, keyed by
gateway MAC, to respect the ~27 min publication lag and avoid rate
limiting; the query window is 3 hours because a 15-minute window
returns an empty array on the real API.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Implements HTTP client for UniFi OS console integration API with support for
fetching site information, client counts, device statistics, and VPN server
configs. Includes pagination handling with filter-based fallback when client
count exceeds API limit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Guarded environment validation with SKIP_ENV_VALIDATION and SECRET_ENCRYPTION_KEY
set in vi.hoisted() so that tests pass both with 'pnpm test' (NODE_ENV=development)
and bare 'pnpm vitest run' (no env override).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add two regression tests that fail on v1.76.0 and pass with the fix:
- wire-level test: a Headers instance (the shape @immich/sdk hands over)
must reach the remote server with all headers intact
- real-SDK e2e: getServerStatistics through fetchWithTrustedCertificatesAsync
against a live local server must deliver x-api-key
The v1.76.0 User-Agent injection object-spread `fetchOptions.headers`, which
silently drops all headers when the value is a Headers instance. The Immich
SDK passes a Headers object with the merged x-api-key header, so requests
lost their API key and returned 401 (issue #6672). Build a real Headers
instance instead, keeping case-insensitive user-agent handling.
Fix Unraid logical CPU averaging, preserve native context menus for app and bookmark widgets in view mode, and prevent scrollbar-width GridStack resize oscillation.
OMV reports filesystem devices (sda1) without the /dev/ prefix, so the
partition-suffix normalization never applied and filesystem-to-SMART
matching returned no temperature. Strip partition suffixes from
unprefixed sd/vd, nvme and mmcblk names, and use the shared normalized
matcher in both the health monitoring and system disks widgets.
* feat(http): set custom User-Agent on outbound integration requests
Set a default 'User-Agent: Homarr/<version> (+https://homarr.dev)' header
on all outbound HTTP requests made via fetchWithTrustedCertificatesAsync,
so Homarr's integration traffic is distinguishable in reverse-proxy,
WAF, and security-monitoring logs instead of appearing as generic undici.
Closes#6604
* 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.
* fix(http): normalize User-Agent injection with Headers
Object-spreading fetchOptions.headers breaks when callers pass a Headers
instance (spread yields no entries) or a tuple array (numeric keys), and is
case-sensitive. Build a Headers instance and set the default User-Agent only
when no case-insensitive User-Agent entry exists, via a shared helper in both
fetch paths.
Adds unit tests covering record, Headers, tuple-array, and casing variants.
* 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.