Dropped @ts-nocheck and annotated the fallout (~54 errors, all mechanical:
implicit-any helper/callback params + dynamic response-assembly objects
in status.cts typed `any` per the shared db.d.ts philosophy). No behavior
change — pure annotation. Zero 'possibly undefined' cases in this batch.
@ts-nocheck server count: 29 -> 21.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CODE_STANDARDS 'every multi-statement write runs inside db.transaction()'
hits from the review: snowball plan create (abandon-existing + insert),
webauthn disable (credential delete + flag clear — a failure between them
recreates the stale-flag state), admin password reset (hash update +
session invalidation). Cleanups: dead ApiError import (payments), dead
action: params on the four snowball transition callers, createSession
consolidated into auth.cts's top-level import.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The backend existed since 99abca9 with no way to reach it (QA-B1-01).
Now wired:
- LoginPage: requires_webauthn second step mirrors TOTP — the key prompt
fires automatically after the password; cancel/retry + back-to-sign-in
- ProfilePage: PasskeySection (mirrors TotpSection) — enroll with a name,
list keys, password-gated per-key remove + remove-all
- webauthnService: WEBAUTHN_ORIGIN stays authoritative; otherwise accept
the browser's origin when its hostname equals the RP ID — fixes real
dev/e2e enrollment where the Vite UI port differs from the API port
(the browser already enforces RP ID ⊆ origin, so no widened trust)
- Deploy safety: WEBAUTHN_RP_ID documented in .env.example + a boot-time
prod warning in utils/env.cts (localhost-bound keys silently fail
behind a real domain)
- e2e/webauthn.probe.spec.js: CDP virtual authenticator drives the full
lifecycle (enroll -> key sign-in -> password-gated removal), retiring
Cycle 1's 'needs a human with a key' assumption. Probe suite 18/18.
Server 252/252, client 52/52, typecheck + build clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 'ADMIN ROUTES (MOUNTED AT /api/admin)' section was false — auth.cts is
mounted only at /api/auth, and the client calls the canonical copies in
admin.cts via /api/admin/*. The duplicates were unreachable dead code, and
/api/auth/has-users was additionally exposed without authentication.
Verified: no callers of /api/auth/has-users or /api/auth/users anywhere.
(QA-B17-01)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
authService.login returns a requires_webauthn payload for webauthn-enabled
users, but the login route only handled requires_totp and fell through to
result.user.id (undefined) -> TypeError -> 500 on every attempt. Any user who
enabled WebAuthn via the API (reachable today) was permanently locked out.
- routes/auth.cts: return the two-step requires_webauthn payload (mirrors TOTP)
- services/authService.cts: stale-flag guard — webauthn_enabled with no usable
credentials falls through to password login instead of hard-failing
- tests/authLoginWebauthnRoute.test.js: pins both paths + wrong-password 401
(QA-B1-01, lockout part)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
utils/logger.cts — console-compatible log.{debug,info,warn,error} with:
- level gating (LOG_LEVEL; debug in dev / info in prod), and
- REDACTION of secrets/PII (sensitive keys + bearer/JWT) so tokens,
passwords, and encrypted values never reach the logs (financial app).
Backend is abstracted (console now, swappable to pino later).
Swept all 317 server-runtime console.* across 35 files → log.* + inserted
the import at correct scope. tests/logger.test.js pins the redaction
contract (4 tests). CODE_STANDARDS updated; raw console.* is now banned in
server code.
Verified: check:server + typecheck:server + lint clean; 240/240 server
tests; client 50/50; build; e2e probe 17/17; boot smoke logs flow through
the logger and graceful shutdown intact.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Every routes/*.js → .cts, with handler signatures typed against the shared
http Req/Res/Next types. Routes carry @ts-nocheck for now — they're thin glue
over the (fully typed) services, so full route-level type-checking is deferred;
the handler-param typing is a head-start. server.js + test requires updated to
the explicit .cts paths.
Behavior-preserving. Verified: check:server 0, typecheck:server 0, suite 226/226,
real boot → /api/health + /api/about 200 (all routes mount).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>