Files
2026-05-27 23:29:53 +01:00

12 KiB
Raw Permalink Blame History

Tasks — complete-react-auth

Change ID: complete-react-auth Package: @suaveplan/react-auth Target path: packages/auth/react-auth/

Pre-flight: @suaveplan/types, @suaveplan/error, @suaveplan/events, @suaveplan/logger, @suaveplan/i18n, @suaveplan/webauthn, @suaveplan/oauth-client, @suaveplan/srp, @suaveplan/otp, @suaveplan/hibp, @suaveplan/password-strength, @suaveplan/password-generator, @suaveplan/react-ui — all ✅ on Verdaccio.


0. Pre-flight (non-negotiable)

  • 0.1 Confirm clean working tree (git status reports nothing) and no in-flight worktrees with uncommitted work (git worktree list then git status in each)
  • 0.2 If any worktrees exist under .claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
  • 0.3 Confirm the package set in MANIFEST.md matches find packages -maxdepth 3 -name package.json count. Drift here means a prior change archived without regenerating the manifest.

1. Scaffold

  • Create directory tree per design.md § File layout.
  • Write package.json at 0.1.0, "sideEffects": false, react ^19.0.0 peer, every internal dep as workspace:^, every external dep via catalog.
  • Write tsconfig.json (extends @suaveplan/typescript-config/browser-react.json), vitest.config.ts (forks pool, fileParallelism false, istanbul 100/100/100/100), playwright.config.ts via @suaveplan/testing-e2e factory.
  • Write README.md at package root — overview, install, quick-start (provider + sign-in form), Modules section linking every co-located .md.

2. Types + schemas + errors

  • src/types/auth-user.ts, auth-state.ts, auth-backend.ts, session.ts, idle-config.ts, permission-resolver.ts — each with sibling .md (≥ 200 words).
  • src/schemas/schemas.ts — Zod schemas for every hook option bag (SignInOptions, SignUpOptions, UsePasskeyAutofillOptions, UseOAuthSignInOptions, …). Sibling .md, schemas.test.ts.
  • src/errors/errors.ts — defineCodes("REACT_AUTH", [...]) for the 29 codes in design.md § Error code namespace. Export ReactAuthError. Sibling .md, errors.test.ts covering: every code reachable from a production path; translation helpers preserve cause.

3. Utilities

  • src/utils/compose-signals.ts (+ .md, .test.ts) — AbortController composition (any abort → composed abort).
  • src/utils/is-ssr.ts (+ .md, .test.ts).
  • src/utils/announce.ts (+ .md, .test.ts) — ARIA live-region helper (creates a single shared aria-live="polite" node on first call).

4. Session — storage, broadcast, idle, refresh, forced-logout

  • src/session/storage/memory/memory.ts (+ .md, .test.ts).
  • src/session/storage/local/local.ts (+ .md, .test.ts).
  • src/session/storage/session/session.ts (+ .md, .test.ts).
  • src/session/broadcast-channel.ts (+ .md, .test.ts) — typed envelope, factory injection, SSR no-op.
  • src/session/auto-refresh.ts (+ .md, .test.ts) — schedule via injected Clock; cancels on every state update.
  • src/session/idle-timer.ts (+ .md, .test.ts) — pointer/key/visibility listeners; debounced; onWarn/onTimeout.
  • src/session/forced-logout.ts (+ .md, .test.ts) — broadcasts + clears storage synchronously.

5. Provider + context

  • src/auth-provider/auth-context.ts (+ .md, .test.ts).
  • src/auth-provider/use-auth-context.ts (+ .md, .test.ts) — throws REACT_AUTH.CONTEXT_MISSING outside provider.
  • src/auth-provider/load-persisted-session.ts (+ .md, .test.ts).
  • src/auth-provider/auth-provider.tsx (+ .md, .test.tsx, .stories.tsx) — wires backend + storage + broadcast + idle + auto-refresh; deterministic SSR render; effect-only DOM access.

6. Lifecycle hooks

  • src/hooks/use-auth/ (+ .md, .test.ts).
  • src/hooks/use-user/ (+ .md, .test.ts).
  • src/hooks/use-is-authenticated/ (+ .md, .test.ts).
  • src/hooks/use-session/ (+ .md, .test.ts).
  • src/hooks/use-sign-in/ (+ .md, .test.ts) — supports password, SRP, passkey result handoff.
  • src/hooks/use-sign-up/ (+ .md, .test.ts).
  • src/hooks/use-sign-out/ (+ .md, .test.ts) — broadcasts signed-out.
  • src/hooks/use-refresh-token/ (+ .md, .test.ts).

7. Password hooks + components

  • src/hooks/use-change-password/ (+ .md, .test.ts).
  • src/hooks/use-password-reset/ (+ .md, .test.ts) — request + confirm.
  • src/components/password-strength-meter/ (+ .md, .test.tsx, .stories.tsx) — wraps password-strength.assessReactive; cancels on unmount.
  • src/components/hibp-pwned-indicator/ (+ .md, .test.tsx, .stories.tsx) — debounced ≥ 500 ms; SSR no-op; injected HibpClient.
  • src/components/password-input/ (+ .md, .test.tsx, .stories.tsx) — show/hide, label association, aria-describedby, optional strength + HIBP slots.
  • src/components/password-generator-button/ (+ .md, .test.tsx, .stories.tsx) — popover via @suaveplan/react-ui <Popover>; passphrase/chars/pin modes.

8. Passkey hooks + components

  • src/hooks/use-register-passkey/ (+ .md, .test.ts).
  • src/hooks/use-authenticate-with-passkey/ (+ .md, .test.ts) — modal mediation.
  • src/hooks/use-passkey-autofill/ (+ .md, .test.tsx) — folded from superseded autofill change; SSR-safe; isConditionalMediationAvailable feature-detect; composed AbortController; stable abort.
  • src/components/passkey-autofill-field/ (+ .md, .test.tsx, .stories.tsx) — <input autocomplete="username webauthn"> wrapper; blur cancels when no credential delivered.
  • src/components/passkey-list/ (+ .md, .test.tsx, .stories.tsx) — lists from backend.listPasskeys; per-row revoke with accessible confirm dialog.

9. OAuth

  • src/oauth/provider-registry.ts (+ .md, .test.ts) — register / get / has / list / unregister; descriptor includes label key + icon slot + scopes.
  • src/oauth/popup.ts (+ .md, .test.ts) — centred-window helper; postMessage origin check; popup-blocked detection.
  • src/oauth/redirect.ts (+ .md, .test.ts) — sessionStorage return-state persist; window.location.assign.
  • src/oauth/handle-callback.ts (+ .md, .test.ts) — parses query, validates state, exchanges code, dispatches result; idempotent on remount.
  • src/hooks/use-oauth-sign-in/ (+ .md, .test.ts) — popup + redirect modes; PKCE via @suaveplan/oauth-client.
  • src/components/oauth-provider-button/ (+ .md, .test.tsx, .stories.tsx).

10. MFA

  • src/hooks/use-enroll-totp/ (+ .md, .test.ts) — begin + finish.
  • src/hooks/use-verify-totp/ (+ .md, .test.ts).
  • src/hooks/use-enroll-webauthn-second-factor/ (+ .md, .test.ts) — wraps register with authenticatorSelection.authenticatorAttachment.
  • src/hooks/use-recovery-codes/ (+ .md, .test.ts) — generate + verify.
  • src/components/totp-enrollment-panel/ (+ .md, .test.tsx, .stories.tsx) — orchestrates secret display → caller-provided QR slot → code entry → recovery-codes reveal.
  • src/components/recovery-codes-panel/ (+ .md, .test.tsx, .stories.tsx) — copy / download / acknowledge before dismiss.

11. Verification flows

  • src/hooks/use-email-verification/ (+ .md, .test.ts).
  • src/hooks/use-phone-verification/ (+ .md, .test.ts).
  • src/components/email-verification-view/ (+ .md, .test.tsx, .stories.tsx) — resend cooldown timer.
  • src/components/phone-verification-view/ (+ .md, .test.tsx, .stories.tsx) — inputMode="numeric", autocomplete="one-time-code".

12. Guards

  • src/hooks/use-permission/ (+ .md, .test.ts).
  • src/hooks/use-auth-guard/ (+ .md, .test.ts).
  • src/components/auth-guard/ (+ .md, .test.tsx, .stories.tsx) — withAuth HOC alongside component.
  • src/components/permission-gate/ (+ .md, .test.tsx, .stories.tsx).

13. Error boundary

  • src/components/auth-error-boundary/ (+ .md, .test.tsx, .stories.tsx) — catches SuaveplanError whose code starts REACT_AUTH.; renders i18n-keyed fallback; re-throws everything else.

14. i18n

  • src/i18n/en-gb/index.ts (+ .md) — canonical catalogue with every react-auth.* key used in the package.
  • src/i18n/cy-gb/index.ts (+ .md) — full Welsh translation.
  • src/i18n/zh-cn/index.ts (+ .md) — full Simplified Chinese translation.
  • src/i18n/parity.test.ts — asserts every locale has the same key set as en-GB; fails CI on drift.
  • src/i18n/no-hardcoded-strings.test.ts — scans components/**/*.tsx for hardcoded user-visible strings; allowlist limited to test fixtures.

15. Index + subpath exports

  • src/index.ts — explicit named re-exports (rule 6a); namespace re-exports for errors and schemas.
  • package.json exports map — one entry per subpath per proposal.md.
  • Type-only re-exports separated via export { type X }.

16. Playwright E2E

  • e2e/fixtures/app.tsx — minimal test app wiring an in-memory AuthBackend.
  • e2e/password-sign-in.spec.ts, sign-up.spec.ts, password-reset.spec.ts, change-password.spec.ts.
  • e2e/passkey-register.spec.ts, passkey-autofill.spec.ts, passkey-modal-authenticate.spec.ts (virtual-authenticator via Playwright CDP).
  • e2e/oauth-popup.spec.ts, oauth-redirect.spec.ts — stubbed authorization endpoint.
  • e2e/totp-enroll-verify.spec.ts, recovery-codes.spec.ts.
  • e2e/email-verification.spec.ts, phone-verification.spec.ts.
  • e2e/multi-tab-sync.spec.ts — two browser contexts share the same backend; sign-out in tab A propagates to tab B.
  • e2e/idle-timeout.spec.ts — idle config fires onTimeout after configured ms; user is forced out.
  • e2e/error-boundary.spec.ts — triggers a BACKEND_ERROR; verifies the boundary fallback renders.
  • e2e/rtl-locale.spec.ts — renders with an RTL locale (e.g. ar) via the parent app; verifies dir="rtl" propagates.
  • e2e/accessibility.spec.ts — @axe-core/playwright sweep across every canonical page; zero serious / critical violations.

17. Spec reconciliation (CLAUDE.md §13 step 0)

  • Open specs/react-auth/spec.md. Walk every ### Requirement and #### Scenario. For each **Verified by:** path, confirm the test file exists and the test name matches verbatim.
  • Confirm every error code in defineCodes("REACT_AUTH", …) is reached from a real production path (not just a registry entry).

18. Pre-publish gates

  • bunx turbo lint typecheck test --filter=@suaveplan/react-auth — green.
  • bunx turbo test:coverage --filter=@suaveplan/react-auth — 100/100/100/100.
  • bunx turbo build --filter=@suaveplan/react-auth — green.
  • Banned-pattern scan zero (@deprecated|TODO|FIXME|ts-ignore|ts-expect-error|\.skip|\.only|console\.log).
  • Barrel-shape scan zero (export * only in src/index.ts namespace forms).
  • Test-runner import scan zero (from "vitest" / from "bun:test" outside the exempt allowlist).
  • Missing-.md scan zero.
  • Bare-version scan zero.
  • Subpath export count matches feature-module count.
  • React version check: find . -path "*/node_modules/react/package.json" returns a single version.

19. Root-doc refresh

  • bun scripts/folder-reorg/generate-manifest.ts (refresh MANIFEST.md).
  • bun scripts/generate-missing.ts (refresh MISSING.yml).
  • Edit STATUS.md — move @suaveplan/react-auth from – to ✅; add summary paragraph.
  • Edit SUMMARY.md — add per-package paragraph (features, deps, decisions).
  • bunx markdownlint-cli2 --fix — touched files.

20. Supersede existing change folders

  • mv openspec/changes/enterprise-react-auth openspec/changes/_superseded-narrow-deferrals-2026-05-17/enterprise-react-auth — fold under the existing supersede bucket.

21. Fold spec delta + archive

  • Fold specs/react-auth/spec.md into openspec/specs/react-auth/spec.md (canonical home).
  • mv openspec/changes/complete-react-auth openspec/archive/<yyyy-mm-dd>-complete-react-auth/.
  • bun scripts/publish.ts --package @suaveplan/react-auth.