6.5 KiB
6.5 KiB
Tasks — @suaveplan/react-auth usePasskeyAutofill
Every checkbox MUST reflect work actually done in this change. Do not retroactively tick boxes.
0. Blocking prerequisite
- 0.1
@suaveplan/webauthnexportsauthenticate({ mediation: "conditional" })andisConditionalMediationAvailable()— verified atpackages/auth/webauthn/src/authenticate/authenticate.tsandpackages/auth/webauthn/src/index.ts.
1. Spec authoring
- 1.1 Read
openspec/archive/2026-05-11-enterprise-webauthn/proposal.md+tasks.mdto confirm theusePasskeyAutofilldeferral - 1.2 Read
openspec/AGENTS.md§13 and §14 - 1.3 Draft
proposal.mdfromopenspec/templates/proposal.md - 1.4 Draft
design.mdcovering hook signature, lifecycle, SSR safety, error translation - 1.5 Draft
specs/react-auth/spec.mdfromopenspec/templates/spec-delta.md - 1.6 Every requirement in the spec delta carries a
**Verified by:**line naming concreteit(...)titles
2. Package scaffold
- 2.1 Create
packages/auth/react-auth/withpackage.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.jsonextending@suaveplan/typescript-config/browser - 2.3
vitest.config.tsviacreateTestConfigwith jsdom environment and 100/100/100/100 thresholds - 2.4
package.jsonexportsmap 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 NAbortSignals 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— namedUsePasskeyAutofillOptions,UsePasskeyAutofillReturninterfaces - 3.3.2
src/use-passkey-autofill/use-passkey-autofill.schemas.ts—UsePasskeyAutofillOptionsSchemaZod schema; throwsREACT_AUTH.INVALID_OPTIONSon parse failure - 3.3.3
src/use-passkey-autofill/use-passkey-autofill.ts— hook body: SSR no-op, feature-detect, dispatch, AbortController ownership, stableabortcallback, 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— namedPasskeyAutofillFieldProps - 3.4.2
src/passkey-autofill-field/passkey-autofill-field.tsx— wraps hook +<input autocomplete="username webauthn">; forwardsonBlur→abort()
3.5 Barrels
- 3.5.1
src/index.ts— explicit named re-exports (noexport *) - 3.5.2 Per-feature
index.tsfiles — 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 everyWEBAUTHN.*code, Zod rejection at entry - 4.2
src/passkey-autofill-field/passkey-autofill-field.test.tsx— renders input with correct autocomplete, forwardsinputProps, blur callsabortonly when no credential delivered - 4.3
src/errors/errors.test.ts— everyREACT_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
.mdforuse-passkey-autofill.ts,passkey-autofill-field.tsx,errors.ts,compose-signals.ts(≥200 words, basic + advanced examples, full API reference) - 6.2
README.mdat package root with Modules table - 6.3 Add
@suaveplan/react-authrow toCLAUDE.mdunder 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, noerrorfindings - 7.5
bunx turbo build --filter=@suaveplan/react-auth— green
8. Pre-archive 7-row checklist (AGENTS.md §13)
- 8.1 Generics threaded;
expectTypeOfassertions 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.mdintoopenspec/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.mdviabun scripts/folder-reorg/generate-manifest.ts - 10.4 Refresh
MISSING.ymlviabun scripts/generate-missing.ts - 10.5 Update
STATUS.md— add@suaveplan/react-authrow inCompleted - 10.6 Update
SUMMARY.mdwith per-package paragraph - 10.7
bunx markdownlint-cli2 --fixand stage results