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 integerssafetyPerformanceOptionsSchema— strict, allskip*flags optional booleansschemaSafetyLimitsSchema— strict, every override optional,customValidatorsisstring[]as unknown as z.ZodType<T>casts where Zod'sT | undefinedcollides withexactOptionalPropertyTypes.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 underexactOptionalPropertyTypes: trueproduceT | undefinedfrom Zod's.optional(), which doesn't match the target's?:declaration. The cast is purely a TypeScript shim — runtime semantics are identical..strict()everywhere.SafetyCheckerreads 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.