Skip to content

fix(passkey): typed PasskeyError everywhere + shared predicate adoption - #43

Merged
ExorTek merged 3 commits into
masterfrom
refactor/passkey-shared-guards
Aug 6, 2026
Merged

fix(passkey): typed PasskeyError everywhere + shared predicate adoption#43
ExorTek merged 3 commits into
masterfrom
refactor/passkey-shared-guards

Conversation

@ExorTek

@ExorTek ExorTek commented Aug 6, 2026

Copy link
Copy Markdown
Owner

What

Two coupled cleanups bringing @exortek/passkey error handling in line with the rest of the repo.

1. Typed errors from every parser

The binary parsers — cbor/decode, asn1/der, cose/key, x509/chain, and the WebAuthn authData/clientData/extensions/rpIdMatch/originCheck/flags readers — threw ~100 generic Errors. A malformed attestation/assertion therefore left the public API as a bare Error with no code, breaking the package's "branch on err.code" contract.

Every throw now carries a PasskeyError code:

  • new ErrorCode.DECODE_ERROR for low-level CBOR/DER decode failures
  • AUTH_DATA_INVALID, CLIENT_DATA_INVALID, EXTENSION_INVALID
  • PUBLIC_KEY_UNSUPPORTED / UNSUPPORTED_ALGORITHM (COSE)
  • ATTESTATION_INVALID / ATTESTATION_TRUST_ANCHOR_MISSING (X.509)
  • INVALID_ARGUMENT for argument-shape failures

2. Drop the per-code throw-factory bloat

Removed the 24 throwXxx = throwFactory(code) exports (+ the unused non-throwing invalidArgument) — a pattern no other package carries. Every call site now constructs the error directly: throw new PasskeyError(ErrorCode.X, msg), exactly like jwt / apikey / session. errors.js is now just ErrorCode + PasskeyError.

3. Shared predicate adoption

Inline typeof / Array.isArray / Number.isInteger@exortek/shared/predicates (isString, isObject, isArray, …). Behaviour-preserving (audited: object sites expect non-array objects; integer sites are bounded). typeof x === 'number' checks are left inline on purpose — shared isNumber also rejects NaN, which would change behaviour.

Compatibility

  • No public surface removed — index only ever re-exported PasskeyError + ErrorCode.
  • Existing try/catch keeps working (PasskeyError extends Error); err.code is now populated for parser failures too.

Verification

  • yarn verify green — 2671 tests pass, 0 fail (passkey 309; parser tests assert by message, so retyping is transparent).
  • yarn build clean; packages/passkey/dist/index.d.ts carries DECODE_ERROR, no throwXxx, no @exortek/shared leak.

Minor changeset included (new DECODE_ERROR code + typed parser errors).

ExorTek added 3 commits August 7, 2026 02:04
…w factories

Two coupled cleanups to align passkey error handling with the rest of the repo:

1. The binary parsers (asn1/der, cbor/decode, cose/key, x509/chain, webauthn
   authData/clientData/extensions/rpIdMatch/originCheck/flags) threw ~100
   generic `Error`s, so a malformed attestation/assertion left the public API
   as a bare Error with no `code`. Every throw now carries a PasskeyError code:
   DECODE_ERROR (new, for der/cbor), AUTH_DATA_INVALID, CLIENT_DATA_INVALID,
   EXTENSION_INVALID, PUBLIC_KEY_UNSUPPORTED / UNSUPPORTED_ALGORITHM,
   ATTESTATION_INVALID / ATTESTATION_TRUST_ANCHOR_MISSING, INVALID_ARGUMENT.

2. Removed the 24 per-code `throwXxx = throwFactory(code)` exports (plus the
   unused non-throwing `invalidArgument`) — a bloat no other package carries.
   Every call site now constructs the error directly, `throw new
   PasskeyError(ErrorCode.X, msg)`, exactly like jwt / apikey / session.

errors.js is now just ErrorCode + PasskeyError. Messages and control flow are
unchanged; the 309-test suite (asserts parser errors by message) passes.
Replace inline typeof / Array.isArray / Number.isInteger with the shared
predicates (isString, isFunction, isBoolean, isBigInt, isArray, isInteger,
isObject) across the package — the repo convention every other package already
follows. Behaviour-preserving: each object check expects a non-array object so
array-excluding isObject matches (clientData already rejected arrays
explicitly), and every integer site is bounded so isInteger (isSafeInteger) is
equivalent. `typeof x === 'number'` checks are left inline on purpose — shared
isNumber additionally rejects NaN, which would be a behaviour change. 309 tests
green.
Copilot AI lite review requested due to automatic review settings August 6, 2026 23:11

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@ExorTek
ExorTek merged commit ee78259 into master Aug 6, 2026
@ExorTek
ExorTek deleted the refactor/passkey-shared-guards branch August 6, 2026 23:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants