zod-redact
v1.0.5
Published
Data masking plugin for Zod schemas - redact, anonymize, or replace sensitive fields after validation.
Maintainers
Readme
zod-redact
Post-validation data redaction for Zod schemas. Annotate fields with replacement values, then parse-and-redact in one step.
pnpm install zod-redactRequires zod as a peer dependency.
Usage
import * as z from "zod/v4";
import { redact, parseAndRedact } from "zod-redact";
const User = z.object({
id: z.string(),
name: redact(z.string(), "***"),
email: redact(z.string(), ["[email protected]", "[email protected]"]),
ssn: redact(z.string(), (seed) => `XXX-XX-${seed.slice(-4)}`),
age: redact(z.number(), 0),
isAdmin: redact(z.boolean(), false),
});
parseAndRedact(User, rawData);
// { id: "usr_1", name: "***", email: "[email protected]", ssn: "XXX-XX-sr_1", age: 0, isAdmin: false }redact() annotates a schema field — it doesn't change parsing behavior. Regular schema.parse() still returns real data. Redaction only happens when you use the library's parse functions.
API
redact(schema, replacement)
Annotate a field. Returns the schema unchanged (for inline chaining).
| Form | What happens |
|------|-------------|
| redact(z.string(), "***") | Static replacement |
| redact(z.string(), ["A", "B", "C"]) | Deterministic pick via DJB2 hash |
| redact(z.string(), (seed) => ...) | Dynamic — receives a seed string |
Works with z.string(), z.number(), z.boolean(), and anything else.
Parse + redact
| Function | Description |
|----------|-------------|
| parseAndRedact(schema, data, opts?) | Parse, then redact. Throws on invalid input. |
| safeParseAndRedact(schema, data, opts?) | Safe variant — returns { success, data/error }. |
| parseAndRedactAsync(schema, data, opts?) | Async — for schemas with async refinements. |
| safeParseAndRedactAsync(schema, data, opts?) | Async safe variant. |
| applyRedact(schema, data, opts?) | Redact already-parsed data (skips parsing). |
combine(fields, template)
Create a derived redaction function that picks from multiple arrays and combines them. Useful for generating realistic fake data like full names or emails from component arrays.
import { combine, redact } from "zod-redact";
const fullName = combine(
{ firstName: firstNames, lastName: lastNames },
(first, last) => `${first} ${last}`,
);
const email = combine(
{ firstName: firstNames, lastName: lastNames },
(first, last) => `${first.toLowerCase()}.${last.toLowerCase()}@example.com`,
);
const schema = z.object({
name: redact(z.string(), fullName),
email: redact(z.string(), email),
});Options
{
seed?: string; // Base seed for deterministic redaction (default: "")
hash?: (str: string) => number; // Custom hash fn (default: DJB2)
}How seeds work
Array and function replacements need a seed to produce deterministic output. The seed is resolved per object:
- If the object has an
idfield →String(id)is used - Otherwise → redacted string field values are concatenated as a composite seed
- Fallback →
options.seed(or"")
Same id = same redacted output across runs.
Supported types
Objects, arrays, records, tuples, maps, sets, unions, discriminated unions, pipes, optionals, nullables, defaults, readonly, catch, lazy, and nested combinations of all of the above.
License
MIT
