Skip to content

Typed client for the remaining modules + raw-fetch gate, frontend splits, UX polish (#504 #522 #575) - #579

Merged
antosubash merged 19 commits into
mainfrom
feat/typed-client-b4b
Oct 22, 2026
Merged

antosubash merged 19 commits into
mainfrom
feat/typed-client-b4b

Conversation

@antosubash

Copy link
Copy Markdown
Owner

This PR finishes the typed API client migration (#504), adds the raw-fetch gate, does #522's frontend file splits and the #575 UX fixes, and fixes two bugs that QA found.

What changes

  • Frontend: shared typed API client generated from the OpenAPI export (replace ~34 hand-rolled fetch calls) #504 completion. Every page and component now calls the API through the typed client: api.* + apiResult, or apiFetch for multipart uploads, non-/api routes and untyped endpoints. That covers users, background_tasks, branding, settings, file_storage and the setup wizard.
    • users: Login keeps its form-encoded request through a typed bodySerializer. Register uses apiFetch, because the generated UserCreate type would make sign-up send privileged fields.
    • Each module gets a committed pages/api.generated.ts.
    • New gate ci-check-no-raw-fetch (runs in make lint and CI): a raw fetch( outside packages/ui/src/lib/api*.ts fails unless the line has a // raw-fetch-ok: <reason> marker. No markers are needed today.
    • Behaviour change: several error toasts now show the server's detail or a translated fallback, instead of English text or "HTTP n".
  • Planned splits for files at the 300-line cap and oversized modules (before the next feature forces them) #522 frontend splits.
  • UX polish: raw setting keys on tenant settings, 404 without layout, silent invalid invite email #575 fixes.
    • Tenant settings show translated labels through a new SettingDefinition.label_key.
    • Signed-in error pages outside /admin keep the app layout.
    • The tenant invite form shows an inline, translated error for an invalid email.
  • Fixes found by QA and review:
    • Self-service password change revoked the changing browser's own /api token (pre-existing on main). The browser now gets a fresh access token through the shared login cookie builder, with the current remember-me window. Every other session and token is still revoked.
    • Admin-copied reset links and bulk-invite fallback links pointed at localhost:8000. They now use users.base_url, then public_base_url, then the request origin. Emailed links are unchanged.
    • A NUL character in a log record dropped the whole retained-log batch on Postgres. NULs are now stripped.
    • The file_storage public routes had duplicate operation ids. They now have distinct ids, with no change to URLs.
    • The in-process outbox sweep test was flaky. It used one SQLite connection for two sessions; it now uses a file DB.
    • Spanish catalogues were missing 2 keys. Doctor now reports 0 warnings.

Verification (after merging main)

  • make lint ✓
  • make test-py: 5605 ✓
  • make test-js: 747 ✓
  • make ci-api-types-fresh ✓
  • make ci-doctor: 0 warnings ✓
  • uv lock --check ✓

/ship

Two rounds.

  • Round 1. Review was clean after 2 passes (Claude + Codex, 7 findings fixed). QA found a P2, the password-change token bug, which was fixed.
  • Round 2. An Opus security review of the token reissue fixed the cookie lifetime and shared the login cookie builder. Codex was clean. QA re-checked with two browsers: clean.
  • Ship report: https://claude.ai/artifact/MKrxZ8N5VXYBF6CZHqdJS4

Closes #504

Closes #522

Closes #575

https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4

…k origin

A self-service password change deleted every UserAccessToken row for the
account, including the one behind the changing browser's sm_auth cookie,
which fastapi_users.current_user reads on /api/users/me*. The Starlette
session was re-stamped, so pages kept rendering while /api answered 401
(pre-existing on main, not a regression of the typed-client migration).
The endpoint now reissues that cookie under the new session_version,
keeping a remembered sign-in's window; other sessions and bearer tokens
are still revoked. Password and sessions cards show failures inline.

Admin-copied links (reset link, bulk-invite fallback) no longer use the
users.base_url dev default: an explicit users.base_url wins, then
HostSettings.public_base_url, then the request origin. Emails unchanged.

Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
…mber window

The password-change reissue duplicated the remembered-login cookie and
strategy construction and minted for the window the session recorded at
sign-in, so an operator who shortened remember_me_max_age_seconds still saw
new credentials minted for the old, longer window. Both paths now go through
users.backend.cookie_login_response, and the reissue mints for the current
setting, as a fresh login would.

Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
🔒 Security Review ✅ Completed 2026-10-22T13:32:10.124743Z 944f9e0 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying simple-module-python with  Cloudflare Pages  Cloudflare Pages

Latest commit: 944f9e0
Status: ✅  Deploy successful!
Preview URL: https://02e47d0e.simple-module-python.pages.dev
Branch Preview URL: https://feat-typed-client-b4b.simple-module-python.pages.dev

View logs

@antosubash
antosubash merged commit 6a22adc into main Oct 22, 2026
17 checks passed
@antosubash
antosubash deleted the feat/typed-client-b4b branch October 22, 2026 14:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant