# Tasks — `@suaveplan/react-auth` `usePasskeyAutofill` > Every checkbox MUST reflect work actually done in this change. Do not retroactively tick boxes. ## 0. Blocking prerequisite - [x] 0.1 `@suaveplan/webauthn` exports `authenticate({ mediation: "conditional" })` and `isConditionalMediationAvailable()` — verified at `packages/auth/webauthn/src/authenticate/authenticate.ts` and `packages/auth/webauthn/src/index.ts`. ## 1. Spec authoring - [x] 1.1 Read `openspec/archive/2026-05-11-enterprise-webauthn/proposal.md` + `tasks.md` to confirm the `usePasskeyAutofill` deferral - [x] 1.2 Read `openspec/AGENTS.md` §13 and §14 - [x] 1.3 Draft `proposal.md` from `openspec/templates/proposal.md` - [x] 1.4 Draft `design.md` covering hook signature, lifecycle, SSR safety, error translation - [x] 1.5 Draft `specs/react-auth/spec.md` from `openspec/templates/spec-delta.md` - [x] 1.6 Every requirement in the spec delta carries a `**Verified by:**` line naming concrete `it(...)` titles ## 2. Package scaffold - [ ] 2.1 Create `packages/auth/react-auth/` with `package.json` (browser tier, React 19 peer, `@suaveplan/webauthn workspace:^`, `@suaveplan/error workspace:^`, `@suaveplan/types workspace:^`, `zod catalog:forms`, `tslib catalog:build`, `@vitest/coverage-istanbul catalog:testing`) - [ ] 2.2 `tsconfig.json` extending `@suaveplan/typescript-config/browser` - [ ] 2.3 `vitest.config.ts` via `createTestConfig` with jsdom environment and 100/100/100/100 thresholds - [ ] 2.4 `package.json` `exports` map covering `.`, `./use-passkey-autofill/use-passkey-autofill`, `./passkey-autofill-field/passkey-autofill-field`, `./errors` - [ ] 2.5 `"sideEffects": false`, `"browser"` field set ## 3. Implementation ### 3.1 Errors - [ ] 3.1.1 `src/errors/errors.ts` — `defineCodes("REACT_AUTH", ["AUTOFILL_UNAVAILABLE", "AUTOFILL_FAILED", "ABORTED", "SSR_NO_OP", "INVALID_OPTIONS"])` ### 3.2 Utilities - [ ] 3.2.1 `src/utils/compose-signals.ts` — composes N `AbortSignal`s into one (any aborts → composed aborts); handles already-aborted signals ### 3.3 Hook - [ ] 3.3.1 `src/use-passkey-autofill/use-passkey-autofill.types.ts` — named `UsePasskeyAutofillOptions`, `UsePasskeyAutofillReturn` interfaces - [ ] 3.3.2 `src/use-passkey-autofill/use-passkey-autofill.schemas.ts` — `UsePasskeyAutofillOptionsSchema` Zod schema; throws `REACT_AUTH.INVALID_OPTIONS` on parse failure - [ ] 3.3.3 `src/use-passkey-autofill/use-passkey-autofill.ts` — hook body: SSR no-op, feature-detect, dispatch, AbortController ownership, stable `abort` callback, error translation - [ ] 3.3.4 Effect re-runs on option-identity change; old controller aborts cleanly ### 3.4 Component wrapper - [ ] 3.4.1 `src/passkey-autofill-field/passkey-autofill-field.types.ts` — named `PasskeyAutofillFieldProps` - [ ] 3.4.2 `src/passkey-autofill-field/passkey-autofill-field.tsx` — wraps hook + ``; forwards `onBlur` → `abort()` ### 3.5 Barrels - [ ] 3.5.1 `src/index.ts` — explicit named re-exports (no `export *`) - [ ] 3.5.2 Per-feature `index.ts` files — explicit named re-exports ## 4. Tests (runner-neutral imports — `@suaveplan/testing/runner`) - [ ] 4.1 `src/use-passkey-autofill/use-passkey-autofill.test.tsx` — happy path, SSR no-op, feature-unavailable, abort on unmount, abort on caller signal, abort via returned callback, option-identity change re-runs, error translation for every `WEBAUTHN.*` code, Zod rejection at entry - [ ] 4.2 `src/passkey-autofill-field/passkey-autofill-field.test.tsx` — renders input with correct autocomplete, forwards `inputProps`, blur calls `abort` only when no credential delivered - [ ] 4.3 `src/errors/errors.test.ts` — every `REACT_AUTH.*` code reachable from a production path - [ ] 4.4 `src/utils/compose-signals.test.ts` — any-aborts semantics, already-aborted inputs, no leaks - [ ] 4.5 Every `it(...)` carries `{ timeout: 5000 }` (or 30000 for async) ## 5. Stories - [ ] 5.1 `src/use-passkey-autofill/use-passkey-autofill.stories.tsx` — default, playground, variants (unavailable, error, abort-on-blur) - [ ] 5.2 `src/passkey-autofill-field/passkey-autofill-field.stories.tsx` — default, playground, variants ## 6. Documentation - [ ] 6.1 Sibling `.md` for `use-passkey-autofill.ts`, `passkey-autofill-field.tsx`, `errors.ts`, `compose-signals.ts` (≥200 words, basic + advanced examples, full API reference) - [ ] 6.2 `README.md` at package root with Modules table - [ ] 6.3 Add `@suaveplan/react-auth` row to `CLAUDE.md` under an Auth/React section ## 7. Pre-archive verification (the 5-gate triple) - [ ] 7.1 `bun run check` — Biome 0 errors / 0 warnings / 0 info - [ ] 7.2 `bunx turbo lint typecheck test --filter=@suaveplan/react-auth` — green - [ ] 7.3 `bunx turbo test:coverage --filter=@suaveplan/react-auth` — 100/100/100/100 - [ ] 7.4 `bun scripts/openspec-conformance.ts @suaveplan/react-auth` — exit 0, no `error` findings - [ ] 7.5 `bunx turbo build --filter=@suaveplan/react-auth` — green ## 8. Pre-archive 7-row checklist (AGENTS.md §13) - [ ] 8.1 Generics threaded; `expectTypeOf` assertions on hook return type - [ ] 8.2 Zod schema wired at hook entry boundary - [ ] 8.3 Every `REACT_AUTH.*` code thrown by ≥1 production path - [ ] 8.4 Strict-mode behaviors tested (feature-available vs unavailable) - [ ] 8.5 Hook lifecycle tested under React 19 strict-mode double-mount - [ ] 8.6 AbortSignal composition tested for all sources (caller signal, returned `abort`, unmount) - [ ] 8.7 No retroactive tick ## 9. Banned-pattern + barrel + runner-import scans - [ ] 9.1 `grep -rn "@deprecated\|TODO\|FIXME\|ts-ignore\|ts-expect-error\|\.skip\|\.only" packages/auth/react-auth/src/ --include="*.ts" --include="*.tsx"` — zero output - [ ] 9.2 `grep -rn "^\s*export\s\+\(type\s\+\)\?\*\s\+from" packages/auth/react-auth/src/ --include="index.ts"` — zero output (feature barrels must use named exports) - [ ] 9.3 `grep -rnE "from ['\"](vitest|bun:test)['\"]" packages/auth/react-auth/src/ --include="*.ts" --include="*.tsx"` — zero output ## 10. Archive - [ ] 10.1 Fold `specs/react-auth/spec.md` into `openspec/specs/react-auth/spec.md` - [ ] 10.2 Move `openspec/changes/add-react-auth-passkey-autofill/` → `openspec/archive/-add-react-auth-passkey-autofill/` - [ ] 10.3 Refresh `MANIFEST.md` via `bun scripts/folder-reorg/generate-manifest.ts` - [ ] 10.4 Refresh `MISSING.yml` via `bun scripts/generate-missing.ts` - [ ] 10.5 Update `STATUS.md` — add `@suaveplan/react-auth` row in `Completed` - [ ] 10.6 Update `SUMMARY.md` with per-package paragraph - [ ] 10.7 `bunx markdownlint-cli2 --fix` and stage results