105 lines
6.5 KiB
Markdown
105 lines
6.5 KiB
Markdown
# 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 + `<input autocomplete="username webauthn">`; 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/<yyyy-mm-dd>-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
|