Files
skills/docs/security-stack/crypto/crypto-utils/src/errors/codes/codes.md
2026-05-29 08:20:56 +01:00

4.3 KiB

codes

(no submodules)

Purpose

Defines the stable, namespaced error-code registry for @suaveplan/crypto-utils. Every error thrown by this package carries a code from this registry, which lets callers type-narrow on error.code rather than relying on string matching against message text.

Features

  • Single defineCodes call produces a frozen, read-only map of codes under the CRYPTO.UTILS namespace
  • Codes are plain string literals ("CRYPTO.UTILS.PRIMITIVE_NOT_IMPLEMENTED", etc.) — safe to log, serialize, and compare across process boundaries
  • CryptoUtilsCode union type keeps downstream catch blocks fully typed without any runtime cost
  • Covers the full error surface of the package: encoding validation, byte-length mismatches, integer-range checks, Merkle-tree errors, RNG limits, and the primitive-not-implemented sentinel

Usage: Basic Example

import { CRYPTO_UTILS_CODES, type CryptoUtilsCode } from "@suaveplan/crypto-utils/errors/codes";

function handleError(code: CryptoUtilsCode): string {
  switch (code) {
    case CRYPTO_UTILS_CODES.ENCODING_INVALID_INPUT:
      return "The supplied string is not valid for the chosen encoding.";
    case CRYPTO_UTILS_CODES.PRIMITIVE_NOT_IMPLEMENTED:
      return "This cryptographic primitive has no native implementation yet.";
    default:
      return "Unknown crypto-utils error.";
  }
}

Usage: Advanced Example

Type-narrowing in a catch block using the CryptoUtilsCode union:

import { CRYPTO_UTILS_CODES, type CryptoUtilsCode } from "@suaveplan/crypto-utils/errors/codes";
import { CryptoUtilsError } from "@suaveplan/crypto-utils/errors/crypto-utils-error";

async function safeHex(input: string): Promise<Uint8Array | null> {
  try {
    const { hexToBytes } = await import("@suaveplan/crypto-utils/encoding/hex/hex");
    return hexToBytes(input);
  } catch (err) {
    if (err instanceof CryptoUtilsError) {
      const code: CryptoUtilsCode = err.code;
      if (code === CRYPTO_UTILS_CODES.ENCODING_INVALID_INPUT) {
        console.warn("Bad hex input, returning null:", err.message);
        return null;
      }
    }
    throw err;
  }
}

API Reference

CRYPTO_UTILS_CODES

const CRYPTO_UTILS_CODES: {
  readonly PRIMITIVE_NOT_IMPLEMENTED: "CRYPTO.UTILS.PRIMITIVE_NOT_IMPLEMENTED";
  readonly ENCODING_INVALID_INPUT:   "CRYPTO.UTILS.ENCODING.INVALID_INPUT";
  readonly BYTES_LENGTH_MISMATCH:    "CRYPTO.UTILS.BYTES.LENGTH_MISMATCH";
  readonly BYTES_INVALID_LENGTH:     "CRYPTO.UTILS.BYTES.INVALID_LENGTH";
  readonly INTEGER_OUT_OF_RANGE:     "CRYPTO.UTILS.INTEGER.OUT_OF_RANGE";
  readonly MERKLE_EMPTY_LEAVES:      "CRYPTO.UTILS.MERKLE.EMPTY_LEAVES";
  readonly MERKLE_INVALID_PROOF:     "CRYPTO.UTILS.MERKLE.INVALID_PROOF";
  readonly RNG_INVALID_LENGTH:       "CRYPTO.UTILS.RNG.INVALID_LENGTH";
};

Frozen registry produced by defineCodes("CRYPTO.UTILS", [...]). Dot-separated sub-namespaces (ENCODING.INVALID_INPUT, BYTES.LENGTH_MISMATCH, etc.) become underscore-keyed properties on the returned object.

Returns — A read-only record whose values are opaque string literals suitable for stable logging and wire serialization.


CryptoUtilsCode

type CryptoUtilsCode = (typeof CRYPTO_UTILS_CODES)[keyof typeof CRYPTO_UTILS_CODES];

Union of every string literal in CRYPTO_UTILS_CODES. Use this as the code parameter type in catch blocks or error-handler signatures to stay fully typed without importing the entire error object.

Implementation Notes

defineCodes (from @suaveplan/error) is the single source of truth for code formatting: it prepends the namespace, freezes the resulting object, and guarantees that each value is a unique string. This file owns no logic — it is a pure declaration layer.

The dot-notation in the raw array entries ("ENCODING.INVALID_INPUT") is a human-readable convention for grouping related codes within the namespace; the resulting object key uses the underscore-separated form (ENCODING_INVALID_INPUT). Consumers should always reference CRYPTO_UTILS_CODES.* constants rather than the raw string literals so that renames are caught at compile time.

Adding a new code requires only appending a string to the as const array in this file and optionally adding a new subclass to the errors/ directory. No numeric IDs, no registry migrations.