@@ -16,26 +16,23 @@ Performed on the `feat/path-only-app-hrefs` branch of `hatlabs/homarr` (cut from
1616 raw path; bookmarks widget gets explicit fallback for ` new URL(...).hostname `
1717 parsing failure (R3).
1818
19- | # | Path | Description | Class |
20- | ---| ------| -------------| -------|
21- | 1 | ` packages/validation/src/app.ts:3-10 ` | ` appHrefSchema ` definition | ** R1 target** — relaxed to accept path-only |
22- | 2 | ` packages/api/src/router/widgets/app.ts:32 ` | Ping query: ` pingUrl ?? href ` | ** Server-internal** — route through ` resolveServerUrl ` |
23- | 3 | ` packages/api/src/router/widgets/app.ts:73 ` | Ping subscription: ` pingUrl ?? href ` | ** Server-internal** — route through ` resolveServerUrl ` |
24- | 4 | ` packages/api/src/router/widgets/app.ts:73,82,88,94 ` | Subscription channel key (was URL-based) | ** Architectural** — switch to ` app.id ` (F3 mitigation) |
25- | 5 | ` packages/cron-jobs/src/jobs/ping.ts:28-46 ` | Cron-job dedup + publish | ** Architectural** — adapt to new ` {id,url} ` channel shape |
26- | 6 | ` packages/redis/src/index.ts:21-24 ` | ` pingChannel ` / ` pingUrlChannel ` types | ** Architectural** — message gains ` id ` , list carries ` {id,url} ` |
27- | 7 | ` packages/request-handler/src/lib/cached-request-integration-job-handler.ts:97 ` | ` externalUrl: integration.app?.href ?? null ` | ** Server-internal** — background job, no headers; resolves to ` null ` for path-only |
28- | 8 | ` packages/api/src/middlewares/integration.ts:69 ` | ` externalUrl: rest.app?.href ?? null ` (one) | ** Server-internal** — route via ` resolveServerUrl(app, ctx.headers) ` |
29- | 9 | ` packages/api/src/middlewares/integration.ts:131 ` | ` externalUrl: rest.app?.href ?? null ` (many) | ** Server-internal** — route via ` resolveServerUrl(app, ctx.headers) ` |
30- | 10 | ` packages/api/src/router/app.ts:122,141,168 ` | App CRUD persistence | ** Storage** — pass through; relaxation propagates via schema |
31- | 11 | ` packages/api/src/router/integration/integration-router.ts:686-701 ` | App creation during integration setup | ** Storage** — pass through |
32- | 12 | ` packages/old-import/src/mappers/map-app.ts:26 ` | Old-Marr import mapper | ** Storage** — pass through; uses ` appCreateManySchema ` downstream |
33- | 13 | ` packages/old-import/src/import/import-single-oldmarr.ts:20 ` | Old-Marr import filter (` href !== null ` ) | ** Storage** — null-tolerant; no change |
34- | 14 | ` packages/widgets/src/app/component.tsx:38,49,64,82,132 ` | App widget ` <a href={app.href}> ` and conditional rendering | ** Navigation-only** — no change (R4 verified — ` UnstyledButton component="a" ` , no ` next/link ` ) |
35- | 15 | ` packages/widgets/src/bookmarks/component.tsx:36,103,161 ` | Bookmarks widget ` <a href={app.href}> ` | ** Navigation-only** — no change |
36- | 16 | ` packages/widgets/src/bookmarks/component.tsx:235,282 ` | Bookmarks widget sub-label ` new URL(app.href).hostname ` | ** Display (R3)** — try/catch fallback to trailing-slash-trimmed path |
37- | 17 | ` apps/nextjs/src/app/[locale]/manage/apps/page.tsx:109-111 ` | Admin apps list — Anchor display + navigation | ** Navigation-only / Display** — works with path-only (anchor resolves; text shows path) |
38- | 18 | ` apps/nextjs/src/components/board/sections/category/category-menu-actions.tsx:119,122 ` | "Open all" — ` window.open(app.href) ` | ** Navigation-only** — ` window.open ` accepts relative URLs (resolved against current document) |
19+ | # | Path | Description | Class |
20+ | --- | -------------------------------------------------------------------------------------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
21+ | 1 | ` packages/validation/src/app.ts:3-10 ` | ` appHrefSchema ` definition | ** R1 target** — relaxed to accept path-only |
22+ | 2 | ` packages/api/src/router/widgets/app.ts:32 ` | Ping query: ` pingUrl ?? href ` | ** Server-internal** — route through ` resolveServerUrl ` |
23+ | 3 | ` packages/api/src/router/widgets/app.ts:73 ` | Ping subscription: ` pingUrl ?? href ` | ** Server-internal** — route through ` resolveServerUrl ` . Subscription stays URL-keyed; under path-only hrefs two clients on different hostnames produce two pings per cycle, each matched by its own client's URL filter. Minor traffic overhead, no correctness issue (commented in source). |
24+ | 4 | ` packages/request-handler/src/lib/cached-request-integration-job-handler.ts:97 ` | ` externalUrl: integration.app?.href ?? null ` | ** Server-internal** — background job, no headers; resolves to ` null ` for path-only |
25+ | 5 | ` packages/api/src/middlewares/integration.ts:69 ` | ` externalUrl: rest.app?.href ?? null ` (one) | ** Server-internal** — route via ` resolveServerUrl(app, ctx.headers) ` |
26+ | 6 | ` packages/api/src/middlewares/integration.ts:131 ` | ` externalUrl: rest.app?.href ?? null ` (many) | ** Server-internal** — route via ` resolveServerUrl(app, ctx.headers) ` |
27+ | 7 | ` packages/api/src/router/app.ts:122,141,168 ` | App CRUD persistence | ** Storage** — pass through; relaxation propagates via schema |
28+ | 8 | ` packages/api/src/router/integration/integration-router.ts:686-701 ` | App creation during integration setup | ** Storage** — pass through |
29+ | 9 | ` packages/old-import/src/mappers/map-app.ts:26 ` | Old-Marr import mapper | ** Storage** — pass through; uses ` appCreateManySchema ` downstream |
30+ | 10 | ` packages/old-import/src/import/import-single-oldmarr.ts:20 ` | Old-Marr import filter (` href !== null ` ) | ** Storage** — null-tolerant; no change |
31+ | 11 | ` packages/widgets/src/app/component.tsx:38,49,64,82,132 ` | App widget ` <a href={app.href}> ` and conditional rendering | ** Navigation-only** — no change (R4 verified — ` UnstyledButton component="a" ` , no ` next/link ` ) |
32+ | 12 | ` packages/widgets/src/bookmarks/component.tsx:36,103,161 ` | Bookmarks widget ` <a href={app.href}> ` | ** Navigation-only** — no change |
33+ | 13 | ` packages/widgets/src/bookmarks/component.tsx:235,282 ` | Bookmarks widget sub-label ` new URL(app.href).hostname ` | ** Display (R3)** — try/catch fallback to trailing-slash-trimmed path |
34+ | 14 | ` apps/nextjs/src/app/[locale]/manage/apps/page.tsx:109-111 ` | Admin apps list — Anchor display + navigation | ** Navigation-only / Display** — works with path-only (anchor resolves; text shows path) |
35+ | 15 | ` apps/nextjs/src/components/board/sections/category/category-menu-actions.tsx:119,122 ` | "Open all" — ` window.open(app.href) ` | ** Navigation-only** — ` window.open ` accepts relative URLs (resolved against current document) |
3936
4037Coverage of the audit scope mandated by the plan:
4138
@@ -49,7 +46,9 @@ Coverage of the audit scope mandated by the plan:
4946- Import/export flows — ✅ (` packages/old-import/ ` )
5047- ` apps/nextjs/** ` — ✅
5148
52- No deeply-coupled consumer was discovered that resists path-only migration. The
53- architectural change in items 4–6 (subscription channel keying) is the only
54- non-trivial behavioral change; it is a small correctness improvement
55- independent of HaLOS use cases.
49+ No deeply-coupled consumer was discovered that resists path-only migration.
50+ All findings are either navigation-only (no change), routed through
51+ ` resolveServerUrl ` (small additive change), or storage paths that pass through
52+ once the schema accepts the new shape. Ping pub/sub keeps its existing
53+ URL-keyed shape; the path-only case produces a small per-extra-hostname
54+ duplication of ping traffic with no correctness consequence.
0 commit comments