@frontmcp/lazy-zod 1.9.6 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,83 +1,82 @@
1
1
  # @frontmcp/lazy-zod
2
2
 
3
- Drop-in Zod replacement that lazily constructs compound schemas. On bundled
4
- CLI binaries and edge workers, this cuts module-init cold-start by ~50× on
5
- schema-heavy entries with effectively zero steady-state parse overhead.
3
+ Zod 4's `z`, with compound schemas like `z.object()` built the first time they're used instead of when the module loads. A process that defines many schemas but uses few of them per run, like a CLI, a serverless function or an edge worker, starts faster. This is an internal package: `@frontmcp/sdk` re-exports all of it, so in a FrontMCP server import `z`, `eagerZ` and `lazyZ` from `@frontmcp/sdk`. It doesn't depend on the rest of FrontMCP, so you can also use it on its own.
6
4
 
7
- ## Why
8
-
9
- In a benchmark of 1,515 realistic schemas (see `apps/poc-lazy-zod/`):
10
-
11
- | Metric | Eager zod | Lazy zod | Delta |
12
- | ------------------- | --------- | -------- | -------- |
13
- | Cold-start (median) | 387 ms | 7.1 ms | **−98%** |
14
- | First-parse | 0.45 ms | 1.47 ms | +1 ms |
15
- | Parse-all (steady) | 31 ms | 31 ms | +0.2% |
16
- | Bundle size | 1.69 MB | 1.70 MB | +0.64% |
17
-
18
- The win comes from deferring `z.object({…})` / `z.union([…])` construction
19
- until the first `.parse()` call — and self-patching the schema instance on
20
- that first call so all subsequent parses bypass the wrapper entirely.
5
+ [![npm](https://img.shields.io/npm/v/@frontmcp/lazy-zod.svg)](https://www.npmjs.com/package/@frontmcp/lazy-zod) [![License](https://img.shields.io/npm/l/@frontmcp/lazy-zod.svg)](https://github.com/agentfront/frontmcp/blob/main/LICENSE)
21
6
 
22
7
  ## Install
23
8
 
24
- ```sh
9
+ ```bash
25
10
  npm install @frontmcp/lazy-zod zod
26
11
  ```
27
12
 
28
- `zod` is a peer dependency (v4).
13
+ `zod` `^4.0.0` is a peer dependency: the package wraps the Zod you install. Zod 3 isn't supported. It needs Node.js 24 or later.
29
14
 
30
15
  ## Usage
31
16
 
17
+ Import `z` from here instead of from `zod`:
18
+
32
19
  ```ts
33
- // Preferred — lazy by default, full drop-in for zod's `z`.
34
- import { z } from '@frontmcp/lazy-zod';
20
+ import { eagerZ, lazyZ, toJSONSchema, z } from '@frontmcp/lazy-zod';
35
21
 
36
- const schema = z.object({
37
- name: z.string(),
38
- age: z.number().optional(),
22
+ const Ticket = z.object({
23
+ title: z.string().min(5),
24
+ customer: z.object({ email: z.string().email() }).optional(),
39
25
  });
40
26
 
41
- type User = z.infer<typeof schema>; // { name: string; age?: number }
42
- schema.parse({ name: 'Ada', age: 36 });
43
- ```
27
+ type Ticket = z.infer<typeof Ticket>;
44
28
 
45
- ```ts
46
- // Escape hatch — real zod, zero proxy overhead.
47
- // Use when you need a schema to be fully-constructed at module load
48
- // (e.g. a library will immediately introspect it via toJSONSchema).
49
- import { eagerZ } from '@frontmcp/lazy-zod';
29
+ const ticket: Ticket = Ticket.parse({ title: 'Cannot log in' });
50
30
 
51
- const eager = eagerZ.object({ foo: eagerZ.string() });
52
- ```
31
+ const jsonSchema = toJSONSchema(Ticket);
53
32
 
54
- ```ts
55
- // Explicit factory-style wrapper — when you already have a real zod schema
56
- // and want to defer it.
57
- import { eagerZ, lazyZ } from '@frontmcp/lazy-zod';
33
+ const Built = eagerZ.object({ id: eagerZ.string() });
58
34
 
59
- const deferred = lazyZ(() => eagerZ.object({ foo: eagerZ.string() }));
60
- deferred.parse({ foo: 'bar' }); // materializes on first call
35
+ const Deferred = lazyZ(() => eagerZ.object({ id: eagerZ.string() }));
61
36
  ```
62
37
 
63
- When used inside FrontMCP, you don't need to depend on this package
64
- directly — it's re-exported as `z` from `@frontmcp/sdk`.
38
+ `z.object()`, `z.strictObject()`, `z.looseObject()`, `z.union()`, `z.discriminatedUnion()`, `z.intersection()`, `z.record()` and `z.tuple()` return a stand-in. The real Zod schema is built the first time the stand-in is used, by a parse or by reading a property like `.shape`, and methods you chain on it, like `.optional()`, return stand-ins too. After the first parse, `parse`, `safeParse`, `parseAsync` and `safeParseAsync` call Zod directly. The other factories, like `z.string()` and `z.enum()`, are Zod's own.
39
+
40
+ A stand-in behaves like the schema it stands for: it parses the same, `instanceof ZodObject` is `true`, and `z.infer` gives the same type.
41
+
42
+ | Export | What it is |
43
+ | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
44
+ | `z` (also the default export) | Zod 4's `z`, with the factories above deferred. |
45
+ | `eagerZ` | Zod's own `z`. Use it for a schema that something reads as soon as it's defined. |
46
+ | `lazyZ(build)` | A schema that calls `build()` the first time it's used, and only then. |
47
+ | `isLazy(schema)` | `true` for a stand-in, from `z` or from `lazyZ()`. |
48
+ | `forceMaterialize(schema)` | The real Zod schema, with every stand-in inside it built. |
49
+ | `toJSONSchema(schema)` | Zod's JSON Schema converter, run on `forceMaterialize(schema)`. Use it instead of Zod's own `z.toJSONSchema()`, which throws `TypeError: Cannot set properties of undefined (setting 'ref')` when an object or union in the schema is `.optional()` or has a `.default()`. |
50
+ | `ZodObject`, `ZodError`, … | Zod's classes and types (`ZodTypeAny`, `infer`, `input`, `output`), so your code needs no import from `zod`. |
51
+
52
+ ## Performance
53
+
54
+ The prototype this package grew from was measured on 1,515 generated schemas, bundled into one file, on Node.js 24 (medians of 30 runs):
55
+
56
+ | Metric | Zod's `z` | Lazy `z` |
57
+ | ---------------------------- | --------- | -------- |
58
+ | Start-up | 387 ms | 7.1 ms |
59
+ | First parse of one schema | 0.45 ms | 1.47 ms |
60
+ | First parse of every schema | 235 ms | 616 ms |
61
+ | Second parse of every schema | 31.0 ms | 31.0 ms |
62
+ | Bundle size | 1.69 MB | 1.70 MB |
63
+
64
+ The work isn't removed, it's moved: each schema costs more the first time it's parsed. Lazy schemas pay off when a process starts often and uses only some of its schemas. The benchmark, with its method and full results, is in [`apps/poc-lazy-zod`](https://github.com/agentfront/frontmcp/blob/main/apps/poc-lazy-zod/results/README.md).
65
+
66
+ ## Docs
67
+
68
+ - [`z`, `eagerZ` and `lazyZ`](https://frontmcp.dev/reference/sdk#z-eagerz-and-lazyz): how FrontMCP uses this package
69
+ - [Schemas are contracts](https://frontmcp.dev/learn/schemas-are-contracts): writing input schemas for tools
70
+
71
+ ## Related packages
72
+
73
+ - [`@frontmcp/sdk`](https://www.npmjs.com/package/@frontmcp/sdk): re-exports this package. Use it in a FrontMCP server.
74
+ - [`zod`](https://www.npmjs.com/package/zod): the schema library this package wraps.
65
75
 
66
- ## Status
76
+ ## Contributing
67
77
 
68
- Implemented. `z` is lazy by default — heavy compound factories (`z.object`,
69
- `z.union`, `z.discriminatedUnion`, `z.intersection`, `z.record`, `z.tuple`,
70
- plus `z.strictObject` / `z.looseObject`) return a `Proxy` over a
71
- `LazyZodSchema` that materializes the real zod schema on first
72
- `.parse()` / `.safeParse()` / `.parseAsync()` / `.safeParseAsync()` call
73
- and self-patches the hot-path methods onto the instance so subsequent
74
- parses run at native zod speed (measured at +0.2% steady-state overhead
75
- in the POC). Light factories (`z.string`, `z.number`, `z.enum`,
76
- `z.literal`, `z.lazy`, etc.) pass straight through to real zod. See
77
- `src/lazy-z.ts` for the Proxy and `src/lazy-schema.ts` for the wrapper.
78
- Use `eagerZ` when a consumer needs a fully-constructed schema at
79
- import time (e.g. immediate introspection).
78
+ Source: [`libs/lazy-zod`](https://github.com/agentfront/frontmcp/tree/main/libs/lazy-zod). Issues and pull requests are welcome; see [CONTRIBUTING.md](https://github.com/agentfront/frontmcp/blob/main/CONTRIBUTING.md).
80
79
 
81
80
  ## License
82
81
 
83
- Apache-2.0
82
+ Apache-2.0. See [LICENSE](https://github.com/agentfront/frontmcp/blob/main/LICENSE).
package/esm/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@frontmcp/lazy-zod",
3
- "version": "1.9.6",
4
- "description": "Drop-in zod replacement that lazily constructs compound schemas for dramatic cold-start speedups. Exports `z` (lazy, drop-in), `eagerZ` (real zod, zero overhead), and `lazyZ` (explicit factory wrapper).",
3
+ "version": "1.10.0",
4
+ "description": "Zod 4's z with compound schemas built on first use, for faster start-up. Exports z (lazy), eagerZ (Zod's own) and lazyZ",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "license": "Apache-2.0",
7
7
  "keywords": [
@@ -24,7 +24,7 @@
24
24
  "bugs": {
25
25
  "url": "https://github.com/agentfront/frontmcp/issues"
26
26
  },
27
- "homepage": "https://github.com/agentfront/frontmcp/blob/main/libs/lazy-zod/README.md",
27
+ "homepage": "https://frontmcp.dev/reference/sdk#z-eagerz-and-lazyz",
28
28
  "type": "module",
29
29
  "main": "../index.js",
30
30
  "module": "./index.mjs",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@frontmcp/lazy-zod",
3
- "version": "1.9.6",
4
- "description": "Drop-in zod replacement that lazily constructs compound schemas for dramatic cold-start speedups. Exports `z` (lazy, drop-in), `eagerZ` (real zod, zero overhead), and `lazyZ` (explicit factory wrapper).",
3
+ "version": "1.10.0",
4
+ "description": "Zod 4's z with compound schemas built on first use, for faster start-up. Exports z (lazy), eagerZ (Zod's own) and lazyZ",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "license": "Apache-2.0",
7
7
  "keywords": [
@@ -24,7 +24,7 @@
24
24
  "bugs": {
25
25
  "url": "https://github.com/agentfront/frontmcp/issues"
26
26
  },
27
- "homepage": "https://github.com/agentfront/frontmcp/blob/main/libs/lazy-zod/README.md",
27
+ "homepage": "https://frontmcp.dev/reference/sdk#z-eagerz-and-lazyz",
28
28
  "type": "commonjs",
29
29
  "main": "./index.js",
30
30
  "module": "./esm/index.mjs",