# `ocra/ocra.schema` ## Purpose Zod boundary schema for `OcraParams` — the runtime parameter bag passed alongside a suite string and a key. Optional fields (`counter`, `passwordHash`, `sessionInfo`, `timestampMs`) are validated when present so callers cannot silently pass through malformed values; the actual presence/absence rule is enforced by `buildOcraMessage` against the parsed suite directives. ## Features - Strict-mode object — unknown keys rejected. - `counter` typed as `bigint` non-negative. - `passwordHash` and `sessionInfo` typed as `Uint8Array`. - `timestampMs` typed as non-negative integer. ## Usage: Basic Example ```ts import { OcraParamsSchema } from "@suaveplan/otp/ocra"; OcraParamsSchema.parse({ challenge: "12345678", counter: 1n }); ``` ## Usage: Advanced Example ```ts import { OcraParamsSchema } from "@suaveplan/otp/ocra"; // Validate before passing through to ocra() — useful at API boundaries. const safe = OcraParamsSchema.safeParse(req.body); if (!safe.success) return res.status(400).json(safe.error); ``` ## API Reference - `OcraParamsSchema` — strict Zod object covering all five `OcraParams` fields. ## Implementation Notes The schema is intentionally permissive about WHICH optional fields are present — that's the suite parser's responsibility. Validating the shape of values that ARE present catches cases like `counter: -1n` or `timestampMs: -5` that would otherwise produce nonsensical OCRA outputs without raising. The schema lives in its own module so consumers that only need validation (e.g. an API gateway that records OCRA-bound transactions) can import it without pulling in the OCRA codec. The `Uint8Array` instance check uses Zod's `z.instanceof` so tagged byte arrays round-trip cleanly. Callers passing `ArrayBuffer` instead must convert at the boundary; the schema deliberately does not accept arbitrary buffer shapes to avoid silent slice / endianness surprises. The `counter` and `timestampMs` lower-bounds are non-negative because OCRA inherits the unsigned counter rules from RFC 4226 §5.1.