# largeBlob extension support _(no submodules)_ ## Purpose Implements the W3C WebAuthn L3 §10.1.3 largeBlob extension passthrough plus result parsing. The largeBlob extension lets the authenticator store a small per-credential byte string (typically credentials or session-resumption tokens) inside the authenticator's secure element. Registration asks the authenticator to allocate the slot; subsequent authentications read or write the blob. ## Features - `LargeBlobRegisterInput` (`{ support: "required" | "preferred" }`) and discriminated `LargeBlobAuthenticateInput` (`{ read: true }` xor `{ write: Uint8Array }`) — W3C-mandated mutual exclusion. - `readLargeBlobRegisterResult` extracts `{ supported }` from the registration ceremony's `ClientExtensionResults`. - `readLargeBlobReadResult` extracts `{ blob? }` from the assertion ceremony's results — `blob` is omitted (not zeroed) when the authenticator did not return one. - `readLargeBlobWriteResult` extracts `{ written }` — boolean discriminator between success and silent drop. - `buildLargeBlobRegisterExtension` / `buildLargeBlobAuthenticateExtension` produce the wire-shape passed to `navigator.credentials.{create,get}`. ## Usage: Basic Example ```ts import { buildLargeBlobAuthenticateExtension, readLargeBlobReadResult, } from "@suaveplan/webauthn/extensions/large-blob"; const ext = buildLargeBlobAuthenticateExtension({ read: true }); const cred = await navigator.credentials.get({ publicKey: { challenge, allowCredentials, extensions: ext } }); const result = readLargeBlobReadResult( (cred as PublicKeyCredential).getClientExtensionResults() ); console.log(result?.blob?.byteLength ?? 0); ``` ## Usage: Advanced Example ```ts import { buildLargeBlobAuthenticateExtension, buildLargeBlobRegisterExtension, readLargeBlobRegisterResult, readLargeBlobWriteResult, } from "@suaveplan/webauthn/extensions/large-blob"; const regExt = buildLargeBlobRegisterExtension({ support: "required" }); const reg = await navigator.credentials.create({ publicKey: { ...opts, extensions: regExt } }); const regResult = readLargeBlobRegisterResult( (reg as PublicKeyCredential).getClientExtensionResults() ); if (!regResult?.supported) { throw new Error("authenticator does not support largeBlob"); } const writeExt = buildLargeBlobAuthenticateExtension({ write: payload }); const authResult = await navigator.credentials.get({ publicKey: { ...authOpts, extensions: writeExt } }); const w = readLargeBlobWriteResult( (authResult as PublicKeyCredential).getClientExtensionResults() ); if (!w?.written) { throw new Error("write dropped"); } ``` ## API Reference - `LargeBlobRegisterInput`, `LargeBlobAuthenticateInput` — input shapes. - `LargeBlobRegisterResult`, `LargeBlobReadResult`, `LargeBlobWriteResult` — result shapes. - `readLargeBlobRegisterResult`, `readLargeBlobReadResult`, `readLargeBlobWriteResult` — narrowing readers. - `buildLargeBlobRegisterExtension`, `buildLargeBlobAuthenticateExtension` — wire-shape builders. ## Implementation Notes - The `support: "required"` mode causes the registration to fail (with `NotSupportedError`) when the authenticator cannot allocate a largeBlob slot; `support: "preferred"` allocates if possible and falls back silently otherwise. The result's `supported` flag distinguishes the two outcomes. - Read and write are mutually exclusive per W3C §10.1.3. The discriminated input union enforces this at the type level so callers cannot accidentally pass both. - `readLargeBlobReadResult` returns `{}` (empty object, not `undefined`) when the extension was acknowledged but no `blob` was returned. This lets callers distinguish "authenticator does not implement the extension" (`undefined` return) from "extension implemented, no blob stored" (`{ blob: undefined }`).