# versecafe/exact-mz

[View on GitCafe](https://git.cafe/versecafe/exact-mz)

Repository: [versecafe/exact-mz](https://git.cafe/versecafe/exact-mz)

Visibility: public

Default branch: main

## Resources

- [Source](https://git.cafe/versecafe/exact-mz/tree/refs%2Fheads%2Fmain?format=markdown)

- [Commit history](https://git.cafe/versecafe/exact-mz/commits/refs%2Fheads%2Fmain?format=markdown)

- [Issues](https://git.cafe/versecafe/exact-mz/issues?format=markdown)

- [Pull requests](https://git.cafe/versecafe/exact-mz/pulls?format=markdown)

- [Stacks](https://git.cafe/versecafe/exact-mz/stacks?format=markdown)

- [Branches](https://git.cafe/versecafe/exact-mz/branches?format=markdown)

- [Tags](https://git.cafe/versecafe/exact-mz/tags?format=markdown)

Snapshot commit: b52afe8ae322828296aee30bbf036f578eab4f6f

## README

[README.md](https://git.cafe/versecafe/exact-mz/blob/b52afe8ae322828296aee30bbf036f578eab4f6f/README.md?format=markdown)

---

# exact-mirror-zod

AOT compiler for Zod 4 schemas that generates fast property-stripping functions. Port of [exact-mirror](https://github.com/elysiajs/exact-mirror) from TypeBox to Zod 4.

## Install

```bash
bun add exact-mirror-zod
```

> Requires [Zod 4](https://zod.dev).

## Usage

```typescript
import { z } from "zod";
import { createMirror } from "exact-mirror-zod";

const schema = z.object({ name: z.string(), age: z.number() });
const mirror = createMirror(schema);

mirror({ name: "test", age: 25, password: "leaked" });
// => { name: "test", age: 25 }
```

`createMirror(schema)` compiles a Zod schema into a function that strips unknown properties from objects to match the schema's shape. **It does not validate** -- it assumes input is already valid and just projects known keys.

### Why?

Validate on input (`z.parse()`), strip on output (`createMirror()`). Prevents leaking internal fields from API responses without the overhead of full re-parsing. Typically **5-15x faster** than `z.parse()` for stripping.

## Supported Types

| Type | Behavior |
|------|----------|
| Object | Keeps only declared keys |
| Array | Per-element mirroring (passes through primitive arrays) |
| Tuple | Per-index mirroring |
| Record | `Object.keys` iteration with value mirroring |
| Discriminated Union | `switch` on discriminator key |
| Union | Cheap `typeof` / `Array.isArray` structural checks |
| Intersection | Merges object shapes |
| Recursive (`z.lazy`) | Memoized helpers with cycle detection |
| Wrappers | `optional`, `nullable`, `default`, `readonly`, `branded`, `pipe` -- unwraps and recurses |

## Options

```typescript
createMirror(schema, {
  // Sanitization functions applied to every string value
  sanitize: (v) => v.trim(),

  // Max recursion depth for z.lazy() schemas (default: 8)
  recursionLimit: 8,

  // Remove values that don't match any union variant (default: false)
  removeUnknownUnionType: false,
});
```

### String Sanitization

Pass one or more functions to transform every string value in the output:

```typescript
const mirror = createMirror(schema, {
  sanitize: [(v) => v.trim(), (v) => v.replace(/</g, "&lt;")],
});
```

## Development

```bash
bun test              # run tests
bun run bench         # run benchmarks
bun run bench:small   # benchmark small schemas
bun run bench:compare # compare against z.parse()
bun run typecheck     # type check
bun run fix           # lint + format
```

## License

MIT

