Files
suaveplan/packages/foundation/bitpacker/bitpacker-validation/src/safety/safety-checks.schema.md
2026-05-27 23:47:53 +01:00

4.7 KiB

Safety Checks Schemas

Purpose

Zod schemas for the configuration types of @suaveplan/bitpacker-validation's safety subsystem: SafetyLimits (the absolute caps applied by every SafetyChecker), SafetyPerformanceOptions (selective skip flags for hot-path code), and SchemaSafetyLimits (per-schema embedded _safety overrides). Each schema is used at the SafetyChecker constructor boundary so a misconfigured limits bundle is rejected at the call site rather than producing surprising allow/deny behaviour deep in a pack/unpack chain.

The schemas are deliberately strict — .strict() rejects unknown keys, and numeric fields are bounded to non-negative integers because every limit is either a count (maxRecursionDepth, maxArrayLength, maxObjectKeys) or a byte count (maxBufferSize). A negative limit would be either a developer mistake or an attempt to bypass safety; either way, refusing it at parse time prevents the SafetyChecker from entering an undefined state.

Features

  • safetyLimitsSchema — strict, all fields required, numerics non-negative integers
  • safetyPerformanceOptionsSchema — strict, all skip* flags optional booleans
  • schemaSafetyLimitsSchema — strict, every override optional, customValidators is string[]
  • as unknown as z.ZodType<T> casts where Zod's T | undefined collides with exactOptionalPropertyTypes
  • .strict() on every schema — unknown keys throw

Usage: Basic Example

import { SafetyChecker } from "@suaveplan/bitpacker-validation";
import { safetyLimitsSchema } from "@suaveplan/bitpacker-validation";

const limits = safetyLimitsSchema.parse({
    maxBufferSize: 1024 * 1024,
    maxRecursionDepth: 32,
    maxArrayLength: 5000,
    maxObjectKeys: 200,
    allowInfiniteFloats: false,
    allowNaNFloats: false,
});
const checker = new SafetyChecker(limits);

Usage: Advanced Example

import {
    SafetyChecker,
    SafetyError,
    safetyLimitsSchema,
    safetyPerformanceOptionsSchema,
    schemaSafetyLimitsSchema,
} from "@suaveplan/bitpacker-validation";

function makeSafeChecker(rawLimits: unknown, rawPerf: unknown): SafetyChecker {
    const limitsResult = safetyLimitsSchema.safeParse(rawLimits);
    if (!limitsResult.success) {
        throw new SafetyError(
            `Invalid safety limits: ${limitsResult.error.message}`,
            "INVALID_LIMITS"
        );
    }
    const perfResult = safetyPerformanceOptionsSchema.safeParse(rawPerf);
    if (!perfResult.success) {
        throw new SafetyError(
            `Invalid performance options: ${perfResult.error.message}`,
            "INVALID_PERF"
        );
    }
    return new SafetyChecker(limitsResult.data, perfResult.data);
}

// Embedded per-schema override:
const blob = schemaSafetyLimitsSchema.parse({
    maxBufferSize: 64 * 1024,
    customValidators: ["png-magic-bytes"],
});

API Reference

safetyLimitsSchema: z.ZodType<SafetyLimits>

Validates a fully-populated SafetyLimits bundle. Every numeric field is required and must be a non-negative integer; both boolean flags are required. Throws ZodError on missing fields, negative values, or unknown keys.

safetyPerformanceOptionsSchema: z.ZodType<SafetyPerformanceOptions>

Validates a SafetyPerformanceOptions bundle of optional skip* boolean flags. An empty bundle is valid. Throws ZodError on unknown keys or non-boolean values.

schemaSafetyLimitsSchema: z.ZodType<SchemaSafetyLimits>

Validates an embedded _safety block. Every field is optional. customValidators must be a string[] (the names of validators registered out-of-band). Throws ZodError on unknown keys, negative numerics, or non-string validator names.

Implementation Notes

  • Non-negative integer bounds. Every numeric field is bounded by .int().nonnegative(). A floating-point limit would be ambiguous (round half-up? half-down?) and a negative limit is meaningless. Refusing both at parse time keeps the SafetyChecker contract simple.
  • as unknown as z.ZodType<T> cast. Optional boolean fields under exactOptionalPropertyTypes: true produce T | undefined from Zod's .optional(), which doesn't match the target's ?: declaration. The cast is purely a TypeScript shim — runtime semantics are identical.
  • .strict() everywhere. SafetyChecker reads only the documented fields. A typo'd key would otherwise be silently dropped, leaving the caller convinced they had configured a limit they hadn't. Strict-mode is the only safe default for safety configuration.
  • No cross-field validation. The schema does not enforce e.g. maxBufferSize ≥ maxArrayLength * minElementSize — that's a SafetyChecker invariant, not a config invariant. The schemas validate shape; the checker validates semantics.