Initial Commit
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
# `errors/error-codes` — `TPM_STRUCT` error registry
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
The `errors` module ships the canonical `defineCodes("TPM_STRUCT", [...])`
|
||||
registry (10 codes) and the `TpmStructError extends SuaveplanError<TpmStructErrorCode>`
|
||||
base class every other module throws from. Stable codes are
|
||||
non-negotiable: consumers (WebAuthn verifiers, attestation gateways,
|
||||
log scrapers) branch on `err.code` to distinguish "buffer was short"
|
||||
from "magic prefix wrong" from "the registered code I care about for
|
||||
my dashboard." A registry with a fixed alphabet is also what makes
|
||||
the `tpm_struct.parse_errors_total{code}` OTel counter bounded.
|
||||
|
||||
## Features
|
||||
|
||||
- Ten registered codes covering every failure class from §8.3 (object
|
||||
attributes), §10.x (attest), §11.x (algorithm and curve), §12.x
|
||||
(public area), and §16 (name).
|
||||
- `TpmStructError` extends `SuaveplanError<TpmStructErrorCode>` so
|
||||
`instanceof` narrows the `.code` union.
|
||||
- `tpmStructError(code, message, detail?)` helper attaches a structured
|
||||
`detail` payload (cursor, requested length, Zod issues) to the cause
|
||||
chain so log adapters can format failures without downcasting.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
TPM_STRUCT_CODES,
|
||||
TpmStructError,
|
||||
tpmStructError,
|
||||
} from "@suaveplan/tpm-struct/errors";
|
||||
|
||||
try {
|
||||
// ... parser code
|
||||
} catch (e) {
|
||||
if (e instanceof TpmStructError) {
|
||||
console.error(`tpm-struct failure: ${e.code}`);
|
||||
if (e.code === TPM_STRUCT_CODES.TRUNCATED) {
|
||||
// recoverable: ask the upstream for a longer buffer
|
||||
}
|
||||
}
|
||||
}
|
||||
void tpmStructError;
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
TPM_STRUCT_CODES,
|
||||
TpmStructError,
|
||||
} from "@suaveplan/tpm-struct/errors";
|
||||
|
||||
type ParseFailureMetric = "magic" | "truncated" | "alg" | "curve" | "other";
|
||||
|
||||
function classify(err: TpmStructError): ParseFailureMetric {
|
||||
switch (err.code) {
|
||||
case TPM_STRUCT_CODES.MAGIC_INVALID:
|
||||
return "magic";
|
||||
case TPM_STRUCT_CODES.TRUNCATED:
|
||||
return "truncated";
|
||||
case TPM_STRUCT_CODES.ALG_UNSUPPORTED:
|
||||
return "alg";
|
||||
case TPM_STRUCT_CODES.CURVE_UNSUPPORTED:
|
||||
return "curve";
|
||||
default:
|
||||
return "other";
|
||||
}
|
||||
}
|
||||
|
||||
// `cause.detail` carries the structured failure context.
|
||||
function reportTruncated(err: TpmStructError) {
|
||||
const detail =
|
||||
((err as unknown as { cause?: { detail?: Record<string, unknown> } })
|
||||
.cause?.detail) ?? {};
|
||||
return { cursor: detail.cursor, requested: detail.requested };
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- **`TPM_STRUCT_CODES`** — frozen registry: `MAGIC_INVALID`, `TRUNCATED`,
|
||||
`ALG_UNSUPPORTED`, `CURVE_UNSUPPORTED`, `TYPE_MISMATCH`, `MALFORMED`,
|
||||
`NAME_ALG_NULL`, `ATTEST_TYPE_UNSUPPORTED`, `PARAMETERS_INVALID`,
|
||||
`OBJECT_ATTRIBUTES_RESERVED_NONZERO`. Each value is the literal
|
||||
`TPM_STRUCT.<NAME>`.
|
||||
- **`TpmStructError`** — base class, message is always prefixed with the
|
||||
code literal.
|
||||
- **`TpmStructErrorCode`** — literal union of the ten code strings.
|
||||
- **`tpmStructError(code, message, detail?)`** — convenience constructor;
|
||||
`detail` (when provided) is wrapped in an Error so it survives through
|
||||
the `cause` chain.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The error message is always prefixed with the code literal so log
|
||||
scrapers find a stable substring without inspecting `.code`. Non-Error
|
||||
detail payloads are wrapped in a synthetic `Error` carrying a `detail`
|
||||
slot — this preserves the standard ECMAScript Error.cause shape while
|
||||
still surfacing structured fields downstream code can read.
|
||||
Reference in New Issue
Block a user