Rip Authelia, fix voice input + Switch UI #822

Merged
reviewer merged 1 commit from feat/authelia-rip-and-voice-fixes into main 2026-05-04 12:01:22 +00:00
Collaborator

Summary

Three intertwined fixes that surfaced from operator-reported avatar breakage on claude.jacquin.app.

Authelia rip (#540 follow-through)

The session gate (F1/F2/F3 OAuth) is now the only auth surface. Caddy no longer fronts claude-hooks with forward_auth (proxmox-iac 68d1404), so the upstream Remote-User header is gone. Removed:

  • auth.ts gutted to 27 LOC (just isLoopback); dropped AuthConfig, extractUser, checkOperatorAuth, ipInCidr, isFromTrustedProxy.
  • main.ts — dropped c.set("user", …) middleware; guardMutating now requires an OAuth session (or loopback); every c.get("user") ?? "operator" is c.get("session")?.account_login.
  • webhook-config.ts — dropped the auth field, parsing block, and session_gate_enabled deprecation log.
  • service-config-schema.ts, service-config-settings.ts, defaults.ts, resolver.ts, presets.ts — dropped the auth field and auth_json SQL.
  • New migration 011-drop-service-config-auth.ts physically drops the service_config.auth_json column.
  • Web: app-shell.tsx, avatar-menu.tsx, useFlowAuth.ts — dropped auth_enabled / authEnabled; logout always rendered.
  • Tests: deleted auth.test.ts; cleaned auth fixtures.

Voice input fixes

  • transcribe-health.ts — speaches/uvicorn rejects HEAD on /v1/models with 405; switch probe to GET. (Without this the pill was stuck on "Unreachable".)
  • transcribe.ts — speaches' OpenAI-compat SSE emits transcript.text.delta (incremental) then transcript.text.done (with empty text). Accumulate deltas, only finalize on done. Skip frames after finalEmitted=true.
  • use-mic-dictation.ts — POST multipart/form-data (not raw blob) so req.formData() parses; SSE reader now pairs event: line with following data: (previous parser looked for a non-existent type field on the JSON body).
  • composer.tsx — mic button shows loading spinner during uploading phase too.

Switch.Thumb position fix

Tailwind v4 + Base UI Switch + Firefox 150: the data-checked: named variant emits a CSS rule, but Firefox doesn't apply translate: var(--tw-translate-x) var(--tw-translate-y) from the indirected variable — data-checked:bg-accent (color) works, data-checked:translate-x-N (position) doesn't. Fix: control thumb's transform via React inline style based on the checked prop. Applied across SwitchRow + voice toggle (settings.index.tsx), dispatch / watch toggles (settings.repos.tsx), and both plugin toggles (plugins-tab.tsx). Also registered data-checked / data-unchecked as @custom-variant in styles/index.css so other call sites (non-Switch.Thumb) keep working.

Test plan

  • just qa — 3169 tests pass
  • Avatar renders on both localhost:4500 and claude.jacquin.app
  • All Switch toggles (caveman mode, design pipeline, voice enable, repos dispatch / watch, plugins) show thumb in correct position when checked
  • Mic input round-trip: record → upload → final transcript inserted at caret
  • Voice input pill flips green ("Live") when speaches reachable
  • service_config.auth_json column physically gone (PRAGMA table_info)
  • Verify mutating routes still 401 cleanly when session cookie missing on staging
  • Verify Forgejo / GitHub / GitLab OAuth flows all still log in cleanly

🤖 Generated with Claude Code

## Summary Three intertwined fixes that surfaced from operator-reported avatar breakage on `claude.jacquin.app`. ### Authelia rip (#540 follow-through) The session gate (F1/F2/F3 OAuth) is now the only auth surface. Caddy no longer fronts claude-hooks with `forward_auth` (proxmox-iac `68d1404`), so the upstream `Remote-User` header is gone. Removed: - `auth.ts` gutted to 27 LOC (just `isLoopback`); dropped `AuthConfig`, `extractUser`, `checkOperatorAuth`, `ipInCidr`, `isFromTrustedProxy`. - `main.ts` — dropped `c.set("user", …)` middleware; `guardMutating` now requires an OAuth session (or loopback); every `c.get("user") ?? "operator"` is `c.get("session")?.account_login`. - `webhook-config.ts` — dropped the `auth` field, parsing block, and `session_gate_enabled` deprecation log. - `service-config-schema.ts`, `service-config-settings.ts`, `defaults.ts`, `resolver.ts`, `presets.ts` — dropped the `auth` field and `auth_json` SQL. - New migration `011-drop-service-config-auth.ts` physically drops the `service_config.auth_json` column. - Web: `app-shell.tsx`, `avatar-menu.tsx`, `useFlowAuth.ts` — dropped `auth_enabled` / `authEnabled`; logout always rendered. - Tests: deleted `auth.test.ts`; cleaned auth fixtures. ### Voice input fixes - `transcribe-health.ts` — speaches/uvicorn rejects HEAD on `/v1/models` with 405; switch probe to GET. (Without this the pill was stuck on "Unreachable".) - `transcribe.ts` — speaches' OpenAI-compat SSE emits `transcript.text.delta` (incremental) then `transcript.text.done` (with empty `text`). Accumulate deltas, only finalize on `done`. Skip frames after `finalEmitted=true`. - `use-mic-dictation.ts` — POST `multipart/form-data` (not raw blob) so `req.formData()` parses; SSE reader now pairs `event:` line with following `data:` (previous parser looked for a non-existent `type` field on the JSON body). - `composer.tsx` — mic button shows loading spinner during `uploading` phase too. ### Switch.Thumb position fix Tailwind v4 + Base UI `Switch` + Firefox 150: the `data-checked:` named variant emits a CSS rule, but Firefox doesn't apply `translate: var(--tw-translate-x) var(--tw-translate-y)` from the indirected variable — `data-checked:bg-accent` (color) works, `data-checked:translate-x-N` (position) doesn't. Fix: control thumb's `transform` via React inline style based on the `checked` prop. Applied across SwitchRow + voice toggle (`settings.index.tsx`), dispatch / watch toggles (`settings.repos.tsx`), and both plugin toggles (`plugins-tab.tsx`). Also registered `data-checked` / `data-unchecked` as `@custom-variant` in `styles/index.css` so other call sites (non-Switch.Thumb) keep working. ## Test plan - [x] `just qa` — 3169 tests pass - [x] Avatar renders on both `localhost:4500` and `claude.jacquin.app` - [x] All Switch toggles (caveman mode, design pipeline, voice enable, repos dispatch / watch, plugins) show thumb in correct position when checked - [x] Mic input round-trip: record → upload → final transcript inserted at caret - [x] Voice input pill flips green ("Live") when speaches reachable - [x] `service_config.auth_json` column physically gone (`PRAGMA table_info`) - [ ] Verify mutating routes still 401 cleanly when session cookie missing on staging - [ ] Verify Forgejo / GitHub / GitLab OAuth flows all still log in cleanly 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat: rip Authelia / Remote-User trust, fix voice + Switch UI
All checks were successful
qa / dockerfile (pull_request) Successful in 16s
qa / qa-1 (pull_request) Successful in 3m3s
qa / qa (pull_request) Successful in 0s
97bb801007
Several intertwined fixes that surfaced from operator-reported avatar
breakage on claude.jacquin.app:

**Authelia rip (#540 follow-through)**

The session gate (F1/F2/F3 OAuth) is the only auth surface now. Caddy
no longer fronts claude-hooks with `forward_auth` (proxmox-iac commit
68d1404), so the upstream `Remote-User` header is gone — and with it
the entire `auth: AuthConfig | null` branch. Gutted:

- `apps/server/src/http/auth.ts` — kept only `isLoopback`; dropped
  `AuthConfig`, `extractUser`, `checkOperatorAuth`, `ipInCidr`,
  `isFromTrustedProxy`, `normaliseIp`. (~150 LOC → 27 LOC.)
- `main.ts` — dropped the `c.set("user", …)` middleware; rewrote
  `guardMutating` to require an OAuth session (or loopback);
  `/whoami` reads identity from the session row only;
  every `c.get("user") ?? "operator"` callsite now reads
  `c.get("session")?.account_login`.
- `webhook-config.ts` — dropped the `auth` field, the parsing block,
  and the `session_gate_enabled` deprecation log.
- `service-config-schema.ts` — dropped `authServiceSchema`.
- `service-config-settings.ts` + `defaults.ts` + `resolver.ts` +
  `presets.ts` — dropped the `auth` field and `auth_json` SQL.
- New migration `011-drop-service-config-auth.ts` physically drops
  the `service_config.auth_json` column (idempotent via
  `PRAGMA table_info`).
- Web: `app-shell.tsx`, `avatar-menu.tsx`, `useFlowAuth.ts` — dropped
  `auth_enabled` / `authEnabled`; logout always rendered.
- Tests: deleted `auth.test.ts`; cleaned the auth fixtures in
  `session-gate.test.ts`, `webhook-config.test.ts`,
  `app-shell.test.tsx`, `avatar-menu.test.tsx`.

**Voice input fixes**

- `transcribe-health.ts` — speaches/uvicorn rejects HEAD on
  `/v1/models` with 405; switch probe to GET. (Without this the
  Settings → Voice input pill was stuck on "Unreachable".)
- `transcribe.ts` — speaches' OpenAI-compat SSE emits
  `transcript.text.delta` (incremental) then
  `transcript.text.done` (with empty `text`); accumulate deltas
  and only finalize on `done`. Skip frames after `finalEmitted=true`
  so the upstream double-fire doesn't propagate.
- `use-mic-dictation.ts` — POST `multipart/form-data` (not raw blob)
  so the server's `req.formData()` parses; SSE reader now tracks
  the `event:` line and pairs it with the next `data:` payload
  (the previous parser looked for a non-existent `type` field on
  the JSON body).
- `composer.tsx` — mic button shows the loading spinner during the
  `uploading` phase too, not just `requesting-permission`.

**Switch.Thumb position fix**

Tailwind v4 + Base UI `Switch` + Firefox 150: the `data-checked:`
named variant emits a CSS rule, but the browser doesn't apply
`translate: var(--tw-translate-x) var(--tw-translate-y)` from the
indirected variable — `data-checked:bg-accent` (color) works,
`data-checked:translate-x-N` (position) doesn't. Fix: control the
thumb's `transform` via React inline style based on the `checked`
prop. Applied across SwitchRow, the voice toggle, the dispatch /
watch toggles in `settings.repos.tsx`, and both plugin toggles in
`plugins-tab.tsx`. Also registered `data-checked` / `data-unchecked`
as `@custom-variant` in `styles/index.css` so other call sites
(non-Switch.Thumb) keep working.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
reviewer approved these changes 2026-05-04 12:01:12 +00:00
reviewer left a comment

CI green (run 3014). Auth removal is consistent end-to-end — auth.ts gutted to isLoopback, guardMutating correctly gates on session-or-loopback, migration 011 is idempotent, SQL column list balanced post-drop. Voice fixes are correct: HEAD→GET probe, FormData upload, SSE event:-aware parser, delta accumulation with OpenAI-compat fallback. Switch.Thumb inline-style workaround is sound for the Firefox 150 / Tailwind v4 issue.

CI green (run 3014). Auth removal is consistent end-to-end — `auth.ts` gutted to `isLoopback`, `guardMutating` correctly gates on session-or-loopback, migration 011 is idempotent, SQL column list balanced post-drop. Voice fixes are correct: HEAD→GET probe, FormData upload, SSE `event:`-aware parser, delta accumulation with OpenAI-compat fallback. Switch.Thumb inline-style workaround is sound for the Firefox 150 / Tailwind v4 issue.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks!822
No description provided.