@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 +55 -56
- package/esm/package.json +3 -3
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,83 +1,82 @@
|
|
|
1
1
|
# @frontmcp/lazy-zod
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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
|
+
[](https://www.npmjs.com/package/@frontmcp/lazy-zod) [](https://github.com/agentfront/frontmcp/blob/main/LICENSE)
|
|
21
6
|
|
|
22
7
|
## Install
|
|
23
8
|
|
|
24
|
-
```
|
|
9
|
+
```bash
|
|
25
10
|
npm install @frontmcp/lazy-zod zod
|
|
26
11
|
```
|
|
27
12
|
|
|
28
|
-
`zod` is a peer dependency
|
|
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
|
-
|
|
34
|
-
import { z } from '@frontmcp/lazy-zod';
|
|
20
|
+
import { eagerZ, lazyZ, toJSONSchema, z } from '@frontmcp/lazy-zod';
|
|
35
21
|
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
42
|
-
schema.parse({ name: 'Ada', age: 36 });
|
|
43
|
-
```
|
|
27
|
+
type Ticket = z.infer<typeof Ticket>;
|
|
44
28
|
|
|
45
|
-
|
|
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
|
|
52
|
-
```
|
|
31
|
+
const jsonSchema = toJSONSchema(Ticket);
|
|
53
32
|
|
|
54
|
-
|
|
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
|
|
60
|
-
deferred.parse({ foo: 'bar' }); // materializes on first call
|
|
35
|
+
const Deferred = lazyZ(() => eagerZ.object({ id: eagerZ.string() }));
|
|
61
36
|
```
|
|
62
37
|
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
##
|
|
76
|
+
## Contributing
|
|
67
77
|
|
|
68
|
-
|
|
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.
|
|
4
|
-
"description": "
|
|
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://
|
|
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.
|
|
4
|
-
"description": "
|
|
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://
|
|
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",
|