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>
Plan en 9 tâches avec cycle TDD par étape, du vocabulaire dans
@homarr/definitions jusqu'au déploiement sur le LXC.
Corrige aussi la spec sur deux points relevés en écrivant le plan :
- catalog.ts (widgetCatalogIcons) est un cinquième point d'enregistrement,
vérifié par manifest.spec.ts et absent du §5.2
- le §9 décrivait un test d'agrégation multi-site devenu sans objet depuis
la décision de ne pas agréger
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Conception validée pour une intégration UniFi OS en complément de
unifiController, basée sur l'API d'intégration officielle (clé X-API-KEY)
plutôt que sur l'ancienne API du Network Controller.
Toutes les capacités et limites de l'API ont été mesurées sur une console
réelle en 10.6.102, pas déduites de la documentation publiée (qui s'arrête
à 10.4.57 et est déjà en retard sur les consoles).
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.