# DTP_CODES + DriveTemplateError ## Purpose Frozen registry of error codes plus the error class for the `@suaveplan/drive-template` package. Eleven codes cover the complete failure surface: the eight-step validation pipeline that `Drive.hydrateFrom(template)` runs (version check, expiry, freshness, replay, issuer trust, signature, recursion depth, file consistency) plus three operational codes for CDN signature failure, inline-file signature failure, and key-grant rejection. Consumers branch on `code` programmatically; messages are for humans only. ## Features - Eleven codes mapping one-to-one to the eight-step pipeline plus three operational paths. - `DTP_CODES` is frozen via `defineCodes` from `@suaveplan/error` — adding a code requires a code change and a spec update. - `DriveTemplateError extends SuaveplanError` — inherits cause-chain traversal, redaction, and JSON wire format. - Type-level exhaustiveness on switch statements via the literal-string `DtpErrorCode` union. ## Usage: Basic Example ```ts import { DriveTemplateError, DTP_CODES } from "@suaveplan/drive-template/errors"; throw new DriveTemplateError( DTP_CODES.TEMPLATE_EXPIRED, "template expired at 2026-01-01T00:00:00Z", ); ``` ## Usage: Advanced Example ```ts import { DriveTemplateError, DTP_CODES, type DtpErrorCode, } from "@suaveplan/drive-template/errors"; const remediation: Record = { "DTP.TEMPLATE_VERSION_UNSUPPORTED": "Update the client; this template uses a newer schema.", "DTP.TEMPLATE_EXPIRED": "Request a fresh template from the issuer.", "DTP.TEMPLATE_STALE": "Request a fresh template; this one is more than 24h old.", "DTP.TEMPLATE_REPLAY": "Template nonce already seen; the issuer must mint a new one.", "DTP.TEMPLATE_UNTRUSTED_ISSUER": "Add the issuer to globalPolicy.trustedKeyAuthorities.", "DTP.TEMPLATE_SIG_INVALID": "Template signature does not match the canonical bytes; possible tampering.", "DTP.TEMPLATE_TOO_DEEP": "Folder recursion exceeds the 32-level cap.", "DTP.TEMPLATE_MALFORMED": "Per-file consistency violated; check chunkSize, totalChunks, and manifest fields.", "DTP.CDN_BAD_SIGNATURE": "CDN response failed Ed25519 verification; falling back to mesh.", "DTP.INLINE_SIG_INVALID": "Inline file's stored signature does not match the bytes.", "DTP.KEY_GRANT_REJECTED": "Key grant signature, recipient, or issuer did not match the template.", }; try { // hydrate code... } catch (err) { if (err instanceof DriveTemplateError) { console.error(`[${err.code}] ${err.message}`); console.error("Remediation:", remediation[err.code]); } } ``` ## API Reference ### `const DTP_CODES` Frozen object mapping uppercase code names to wire-format strings. Eleven entries: **Eight-step validation pipeline** (matches `DTP-05` ordering): - `TEMPLATE_VERSION_UNSUPPORTED` — `template.schemaVersion !== 1`. Future schema versions ship as new packages. - `TEMPLATE_EXPIRED` — `Date.now() >= template.expiresAt`. - `TEMPLATE_STALE` — `Date.now() - template.issuedAt > 24h`. Templates issued more than 24h ago are rejected even if not yet expired. - `TEMPLATE_REPLAY` — `(driveId, nonce)` already seen in the local LRU cache (last 1024 entries). - `TEMPLATE_UNTRUSTED_ISSUER` — `template.issuer` is not in `globalPolicy.trustedKeyAuthorities`. - `TEMPLATE_SIG_INVALID` — Ed25519 verification of `serverSignature` over `canonicalSerialize(template - sig)` failed. - `TEMPLATE_TOO_DEEP` — folder recursion exceeds 32 levels. - `TEMPLATE_MALFORMED` — per-file consistency violated: `chunkSize <= 164`, `totalChunks * chunkSize < size`, `manifestKey` empty, etc. **Operational**: - `CDN_BAD_SIGNATURE` — chunk fetched from CDN failed Ed25519 sig verification. Drive falls back to mesh. - `INLINE_SIG_INVALID` — inline file's stored Ed25519 signature does not match `Ed25519-sign(driveSecretKey, fileId ‖ bytes)`. - `KEY_GRANT_REJECTED` — incoming `KeyGrantEnvelope` failed validation: issuer mismatch, recipient mismatch, sig invalid, or expired. ### `type DtpErrorCode` Union: `(typeof DTP_CODES)[keyof typeof DTP_CODES]`. ### `class DriveTemplateError extends SuaveplanError` Constructor: `new DriveTemplateError(code, message, options?)`. Inherits all `SuaveplanError` features. ## Implementation Notes The eight pipeline codes are ordered by check sequence in `DTP-05`. Implementations MUST throw the first applicable code — they are mutually exclusive in a single hydrate call. The three operational codes are independent: a single drive may emit multiple `CDN_BAD_SIGNATURE` and `INLINE_SIG_INVALID` errors during normal operation; both are observable signals, not blockers. `KEY_GRANT_REJECTED` is the only error code whose `context` field carries structured detail by convention. Implementations should populate `context` with `{ reason: 'untrusted-issuer' | 'wrong-recipient' | 'bad-signature' | 'expired' }` so callers can branch on the specific failure. The `error-codes.spec-conformance.test.ts` enforces (1) the registry is frozen, (2) every code value starts with `DTP.`, (3) the eleven names match what the spec requires.