feat(web+appview): theme resolution and server-side token injection (ATB-53) (#91)
* docs: add design doc for ATB-59 admin theme token editor
Covers file structure (extract to admin-themes.tsx), editor page layout,
HTMX preview endpoint, save/reset flows, error handling, and test plan.
* docs: add implementation plan for ATB-59 theme token editor
Covers extract-to-admin-themes.tsx, TDD for GET /admin/themes/:rkey,
preview endpoint, save, and reset-to-preset handlers.
* docs: add design doc for ATB-53 theme resolution and server-side token injection
* docs: add implementation plan for ATB-53 theme resolution and server-side token injection
* feat(appview): include cid in GET /api/themes/:rkey response (ATB-53)
* feat(web): add ResolvedTheme types, FALLBACK_THEME, and color scheme helpers (ATB-53)
* feat(web): implement resolveTheme waterfall with CID integrity check (ATB-53)
* test(web): add missing resolveTheme branch test for malformed theme URI (ATB-53)
* fix(web): re-throw programming errors in resolveTheme catch block (ATB-53)
* feat(web): add createThemeMiddleware Hono middleware (ATB-53)
* feat(web): register createThemeMiddleware on webRoutes (ATB-53)
* feat(web): BaseLayout accepts resolvedTheme prop, adds Accept-CH meta (ATB-53)
Update BaseLayout to take a required resolvedTheme prop that drives dynamic :root CSS token injection, font URL rendering, and optional cssOverrides. Remove hardcoded neobrutal-light preset import and static ROOT_CSS constant. Add Accept-CH meta tag for color scheme client hint. Update all route factories to read theme from context (falling back to FALLBACK_THEME when middleware is absent, e.g. in tests).
* fix(web): sanitize cssOverrides before injection, add null branch tests (ATB-53)
* feat(web): type auth and mod route factories with WebAppEnv (ATB-53)
* docs: move ATB-53 plan docs to complete/
* docs(bruno): update GET /api/themes/:rkey to document cid field (ATB-53)
* feat(web): thread resolvedTheme through admin-themes route factory (ATB-53)
* fix(web): address PR review — sanitize tokens, split try blocks, add logs, rkey validation (ATB-53)
- Change `import { WebAppEnv }` to `import type` in routes/index.ts (type-only import)
- Freeze FALLBACK_THEME and its fontUrls array to prevent mutation across callers
- Split single giant try block in resolveTheme into 6 focused blocks (policy fetch, policy parse, URI/rkey extraction, theme fetch, theme parse, CID check) with per-operation error messages
- Add rkey validation against /^[a-z0-9]+$/i before using in fetch URL (path traversal prevention)
- Log warning when theme URI is absent from availableThemes (CID check bypassed)
- Log warn with status+url on non-ok policy/theme responses instead of silent fallback
- SyntaxError from Response.json() is now caught as a data error and not re-thrown
- Fix detectColorScheme cookie regex to use (?:^|;\s*) prefix anchor (prevents x-atbb-color-scheme=dark from matching)
- Wrap :root token block in sanitizeCss() in base.tsx
- Filter fontUrls to https:// only before rendering link tags in base.tsx
- Add try-catch error boundary in createThemeMiddleware so unexpected throws use FALLBACK_THEME
- Add tests: invalid JSON in policy/theme responses, CID bypass warning, invalid rkey, cookie regex prefix fix, middleware error boundary, non-https font URL filtering