zodbridge 0.2.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.
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Rule kinds for {@link createMap} and the dot-path get/set helpers they use.
3
+ *
4
+ * Rule kinds (by JS type):
5
+ * - `string` — rename: copy `source[ruleValue]` to the dest key. Auto-reversible.
6
+ * - `(source) => value` — computed function, one-way (no reverse unless paired).
7
+ * - `{ to, from }` — explicit both-directions, reversible.
8
+ * - `FromResolver` — value pulled from a resolver graph (async path, Phase 5).
9
+ */
10
+ /** A function rule: derive a dest value from the whole source object. */
11
+ type FnRule<S, V> = (source: S) => V;
12
+ /** A reversible rule with explicit forward (`to`) and inverse (`from`) maps. */
13
+ interface PairRule<S, V> {
14
+ to: (source: S) => V;
15
+ from: (value: V) => unknown;
16
+ }
17
+ /** Marker for a dest field resolved from a resolver graph (consumed by Phase 5). */
18
+ interface FromResolver {
19
+ readonly __kind: "fromResolver";
20
+ readonly field: string;
21
+ }
22
+ /**
23
+ * Default-value rule: read `source` (a source key, defaults to the dest key)
24
+ * and fall back to `value` when the source is `undefined`. Reverse-safe: the
25
+ * default is dropped on reverse and only the read key round-trips.
26
+ */
27
+ interface DefaultRule<V = unknown> {
28
+ readonly __kind: "default";
29
+ readonly value: V;
30
+ readonly source?: string;
31
+ }
32
+ /** Any rule a dest key may be configured with. */
33
+ type Rule<S = any, V = any> = string | FnRule<S, V> | PairRule<S, V> | FromResolver | DefaultRule<V>;
34
+ /** Build a {@link FromResolver} marker for `field` in the resolver graph. */
35
+ declare function fromResolver(field: string): FromResolver;
36
+ /**
37
+ * Build a {@link DefaultRule}: use `source` (or the dest key) from the entity,
38
+ * falling back to `value` when absent.
39
+ */
40
+ declare function withDefault<V>(value: V, source?: string): DefaultRule<V>;
41
+ declare function isStringRule(rule: Rule): rule is string;
42
+ declare function isFromResolverRule(rule: Rule): rule is FromResolver;
43
+ declare function isPairRule(rule: Rule): rule is PairRule<any, any>;
44
+ declare function isDefaultRule(rule: Rule): rule is DefaultRule;
45
+ declare function isFnRule(rule: Rule): rule is FnRule<any, any>;
46
+ /**
47
+ * Read a nested value by dot-path. Returns `undefined` if any segment is
48
+ * missing or if a segment is a forbidden prototype key (read is skipped, not
49
+ * served from the prototype chain).
50
+ */
51
+ declare function getPath(source: unknown, path: string): unknown;
52
+ /**
53
+ * Write a nested value by dot-path, auto-vivifying intermediate objects.
54
+ * Forbidden prototype keys at any segment are skipped entirely, so a hostile
55
+ * `__proto__.isAdmin` path can never mutate `Object.prototype`.
56
+ */
57
+ declare function setPath(target: Record<string, unknown>, path: string, value: unknown): void;
58
+
59
+ export { type DefaultRule as D, type FnRule as F, type PairRule as P, type Rule as R, type FromResolver as a, isFnRule as b, isFromResolverRule as c, isPairRule as d, isStringRule as e, fromResolver as f, getPath as g, isDefaultRule as i, setPath as s, withDefault as w };
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Rule kinds for {@link createMap} and the dot-path get/set helpers they use.
3
+ *
4
+ * Rule kinds (by JS type):
5
+ * - `string` — rename: copy `source[ruleValue]` to the dest key. Auto-reversible.
6
+ * - `(source) => value` — computed function, one-way (no reverse unless paired).
7
+ * - `{ to, from }` — explicit both-directions, reversible.
8
+ * - `FromResolver` — value pulled from a resolver graph (async path, Phase 5).
9
+ */
10
+ /** A function rule: derive a dest value from the whole source object. */
11
+ type FnRule<S, V> = (source: S) => V;
12
+ /** A reversible rule with explicit forward (`to`) and inverse (`from`) maps. */
13
+ interface PairRule<S, V> {
14
+ to: (source: S) => V;
15
+ from: (value: V) => unknown;
16
+ }
17
+ /** Marker for a dest field resolved from a resolver graph (consumed by Phase 5). */
18
+ interface FromResolver {
19
+ readonly __kind: "fromResolver";
20
+ readonly field: string;
21
+ }
22
+ /**
23
+ * Default-value rule: read `source` (a source key, defaults to the dest key)
24
+ * and fall back to `value` when the source is `undefined`. Reverse-safe: the
25
+ * default is dropped on reverse and only the read key round-trips.
26
+ */
27
+ interface DefaultRule<V = unknown> {
28
+ readonly __kind: "default";
29
+ readonly value: V;
30
+ readonly source?: string;
31
+ }
32
+ /** Any rule a dest key may be configured with. */
33
+ type Rule<S = any, V = any> = string | FnRule<S, V> | PairRule<S, V> | FromResolver | DefaultRule<V>;
34
+ /** Build a {@link FromResolver} marker for `field` in the resolver graph. */
35
+ declare function fromResolver(field: string): FromResolver;
36
+ /**
37
+ * Build a {@link DefaultRule}: use `source` (or the dest key) from the entity,
38
+ * falling back to `value` when absent.
39
+ */
40
+ declare function withDefault<V>(value: V, source?: string): DefaultRule<V>;
41
+ declare function isStringRule(rule: Rule): rule is string;
42
+ declare function isFromResolverRule(rule: Rule): rule is FromResolver;
43
+ declare function isPairRule(rule: Rule): rule is PairRule<any, any>;
44
+ declare function isDefaultRule(rule: Rule): rule is DefaultRule;
45
+ declare function isFnRule(rule: Rule): rule is FnRule<any, any>;
46
+ /**
47
+ * Read a nested value by dot-path. Returns `undefined` if any segment is
48
+ * missing or if a segment is a forbidden prototype key (read is skipped, not
49
+ * served from the prototype chain).
50
+ */
51
+ declare function getPath(source: unknown, path: string): unknown;
52
+ /**
53
+ * Write a nested value by dot-path, auto-vivifying intermediate objects.
54
+ * Forbidden prototype keys at any segment are skipped entirely, so a hostile
55
+ * `__proto__.isAdmin` path can never mutate `Object.prototype`.
56
+ */
57
+ declare function setPath(target: Record<string, unknown>, path: string, value: unknown): void;
58
+
59
+ export { type DefaultRule as D, type FnRule as F, type PairRule as P, type Rule as R, type FromResolver as a, isFnRule as b, isFromResolverRule as c, isPairRule as d, isStringRule as e, fromResolver as f, getPath as g, isDefaultRule as i, setPath as s, withDefault as w };
@@ -0,0 +1,258 @@
1
+ 'use strict';
2
+
3
+ // src/serialize/json-types.ts
4
+ var CodecError = class extends Error {
5
+ /** Path to the offending value, e.g. `user.createdAt`. */
6
+ path;
7
+ constructor(message, path = []) {
8
+ const where = path.length ? ` (at ${path.join(".")})` : "";
9
+ super(`${message}${where}`);
10
+ this.name = "CodecError";
11
+ this.path = path;
12
+ }
13
+ };
14
+ var AsyncSchemaError = class extends Error {
15
+ constructor() {
16
+ super(
17
+ "deserialize is sync-only; this schema has async refinements. Remove async .refine()/.superRefine() or validate separately with parseAsync."
18
+ );
19
+ this.name = "AsyncSchemaError";
20
+ }
21
+ };
22
+ var LIMITS = {
23
+ /** Max characters in a BigInt wire string (sign + digits). */
24
+ bigintStringLength: 4096,
25
+ /** Max entries when rebuilding a Map from a wire array. */
26
+ mapEntries: 1e5
27
+ };
28
+ function dateToIso(value, path) {
29
+ if (!(value instanceof Date) || Number.isNaN(value.getTime())) {
30
+ throw new CodecError("expected a valid Date", path);
31
+ }
32
+ return value.toISOString();
33
+ }
34
+ function isoToDate(value, path) {
35
+ if (typeof value !== "string") {
36
+ throw new CodecError("expected an ISO date string", path);
37
+ }
38
+ const ms = Date.parse(value);
39
+ if (Number.isNaN(ms)) {
40
+ throw new CodecError("invalid ISO date string", path);
41
+ }
42
+ return new Date(ms);
43
+ }
44
+ function bigintToString(value, path) {
45
+ if (typeof value !== "bigint") {
46
+ throw new CodecError("expected a bigint", path);
47
+ }
48
+ return value.toString();
49
+ }
50
+ function stringToBigint(value, path) {
51
+ if (typeof value !== "string") {
52
+ throw new CodecError("expected a bigint string", path);
53
+ }
54
+ if (value.length > LIMITS.bigintStringLength) {
55
+ throw new CodecError(
56
+ `bigint string exceeds ${LIMITS.bigintStringLength} chars`,
57
+ path
58
+ );
59
+ }
60
+ if (!/^-?\d+$/.test(value)) {
61
+ throw new CodecError("malformed bigint string", path);
62
+ }
63
+ return BigInt(value);
64
+ }
65
+ function mapToEntries(value, path) {
66
+ if (!(value instanceof Map)) {
67
+ throw new CodecError("expected a Map", path);
68
+ }
69
+ return Array.from(value.entries());
70
+ }
71
+ function entriesToArray(value, path) {
72
+ if (!Array.isArray(value)) {
73
+ throw new CodecError("expected a Map entries array", path);
74
+ }
75
+ if (value.length > LIMITS.mapEntries) {
76
+ throw new CodecError(`Map entries exceed ${LIMITS.mapEntries}`, path);
77
+ }
78
+ for (const entry of value) {
79
+ if (!Array.isArray(entry) || entry.length !== 2) {
80
+ throw new CodecError("malformed Map entry (expected [key, value])", path);
81
+ }
82
+ }
83
+ return value;
84
+ }
85
+ function setToArray(value, path) {
86
+ if (!(value instanceof Set)) {
87
+ throw new CodecError("expected a Set", path);
88
+ }
89
+ return Array.from(value.values());
90
+ }
91
+ function arrayToSetItems(value, path) {
92
+ if (!Array.isArray(value)) {
93
+ throw new CodecError("expected a Set values array", path);
94
+ }
95
+ if (value.length > LIMITS.mapEntries) {
96
+ throw new CodecError(`Set values exceed ${LIMITS.mapEntries}`, path);
97
+ }
98
+ return value;
99
+ }
100
+
101
+ // src/serialize/codec.ts
102
+ function defOf(schema) {
103
+ return schema._zod.def;
104
+ }
105
+ function typeOf(schema) {
106
+ return defOf(schema).type;
107
+ }
108
+ function unwrap(schema) {
109
+ let current = schema;
110
+ for (; ; ) {
111
+ const def = defOf(current);
112
+ switch (def.type) {
113
+ case "optional":
114
+ case "nullable":
115
+ case "default":
116
+ case "nonoptional":
117
+ case "readonly":
118
+ case "catch":
119
+ current = def.innerType;
120
+ break;
121
+ case "pipe":
122
+ current = def.in;
123
+ break;
124
+ case "lazy":
125
+ current = def.getter();
126
+ break;
127
+ default:
128
+ return current;
129
+ }
130
+ }
131
+ }
132
+ function walk(schema, value, dir, path) {
133
+ if (value === null || value === void 0) return value;
134
+ const node = unwrap(schema);
135
+ const def = defOf(node);
136
+ switch (def.type) {
137
+ case "object": {
138
+ if (typeof value !== "object" || Array.isArray(value)) {
139
+ throw new CodecError("expected an object", path);
140
+ }
141
+ const shape = def.shape;
142
+ const src = value;
143
+ const out = {};
144
+ for (const key of Object.keys(shape)) {
145
+ if (Object.prototype.hasOwnProperty.call(src, key)) {
146
+ out[key] = walk(shape[key], src[key], dir, [...path, key]);
147
+ }
148
+ }
149
+ return out;
150
+ }
151
+ case "array": {
152
+ if (!Array.isArray(value)) throw new CodecError("expected an array", path);
153
+ const element = def.element;
154
+ return value.map((item, i) => walk(element, item, dir, [...path, i]));
155
+ }
156
+ case "map": {
157
+ const keyType = def.keyType;
158
+ const valueType = def.valueType;
159
+ if (dir === "serialize") {
160
+ const entries2 = mapToEntries(value, path);
161
+ return entries2.map(([k, v], i) => [
162
+ walk(keyType, k, dir, [...path, i, "key"]),
163
+ walk(valueType, v, dir, [...path, i, "value"])
164
+ ]);
165
+ }
166
+ const entries = entriesToArray(value, path);
167
+ const out = /* @__PURE__ */ new Map();
168
+ entries.forEach(([k, v], i) => {
169
+ out.set(
170
+ walk(keyType, k, dir, [...path, i, "key"]),
171
+ walk(valueType, v, dir, [...path, i, "value"])
172
+ );
173
+ });
174
+ return out;
175
+ }
176
+ case "set": {
177
+ const valueType = def.valueType;
178
+ if (dir === "serialize") {
179
+ const items2 = setToArray(value, path);
180
+ return items2.map((item, i) => walk(valueType, item, dir, [...path, i]));
181
+ }
182
+ const items = arrayToSetItems(value, path);
183
+ return new Set(items.map((item, i) => walk(valueType, item, dir, [...path, i])));
184
+ }
185
+ case "union": {
186
+ const options = def.options;
187
+ let lastError = new CodecError("no union member matched", path);
188
+ for (const option of options) {
189
+ try {
190
+ return walk(option, value, dir, path);
191
+ } catch (err) {
192
+ if (!(err instanceof CodecError)) throw err;
193
+ lastError = err;
194
+ }
195
+ }
196
+ throw lastError;
197
+ }
198
+ case "date":
199
+ return dir === "serialize" ? dateToIso(value, path) : isoToDate(value, path);
200
+ case "bigint":
201
+ return dir === "serialize" ? bigintToString(value, path) : stringToBigint(value, path);
202
+ // Scalars and explicit escape hatches pass through untouched.
203
+ case "string":
204
+ case "number":
205
+ case "boolean":
206
+ case "nan":
207
+ case "null":
208
+ case "undefined":
209
+ case "literal":
210
+ case "enum":
211
+ case "any":
212
+ case "unknown":
213
+ case "void":
214
+ case "custom":
215
+ return value;
216
+ default:
217
+ throw new CodecError(`unsupported schema node "${def.type}"`, path);
218
+ }
219
+ }
220
+ function serialize(value, schema) {
221
+ return walk(schema, value, "serialize", []);
222
+ }
223
+ function isZodAsyncError(err) {
224
+ const name = err?.constructor?.name;
225
+ return name === "$ZodAsyncError";
226
+ }
227
+ function deserialize(json, schema) {
228
+ const rebuilt = walk(schema, json, "deserialize", []);
229
+ try {
230
+ return schema.parse(rebuilt);
231
+ } catch (err) {
232
+ if (isZodAsyncError(err)) throw new AsyncSchemaError();
233
+ throw err;
234
+ }
235
+ }
236
+ async function deserializeAsync(json, schema) {
237
+ const rebuilt = walk(schema, json, "deserialize", []);
238
+ return await schema.parseAsync(rebuilt);
239
+ }
240
+
241
+ exports.AsyncSchemaError = AsyncSchemaError;
242
+ exports.CodecError = CodecError;
243
+ exports.LIMITS = LIMITS;
244
+ exports.arrayToSetItems = arrayToSetItems;
245
+ exports.bigintToString = bigintToString;
246
+ exports.dateToIso = dateToIso;
247
+ exports.deserialize = deserialize;
248
+ exports.deserializeAsync = deserializeAsync;
249
+ exports.entriesToArray = entriesToArray;
250
+ exports.isoToDate = isoToDate;
251
+ exports.mapToEntries = mapToEntries;
252
+ exports.serialize = serialize;
253
+ exports.setToArray = setToArray;
254
+ exports.stringToBigint = stringToBigint;
255
+ exports.typeOf = typeOf;
256
+ exports.unwrap = unwrap;
257
+ //# sourceMappingURL=index.cjs.map
258
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/serialize/json-types.ts","../../src/serialize/codec.ts"],"names":["entries","items"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Leaf transforms between rich JS values and their JSON-safe wire forms.\n * Each inverse (wire -> JS) transform validates its input and throws a\n * {@link CodecError} on malformed data, so a hostile wire payload surfaces a\n * typed error instead of a raw `TypeError`/`SyntaxError` or an unbounded stall.\n */\n\n/** Thrown for malformed wire input or unsupported schema nodes during codec walk. */\nexport class CodecError extends Error {\n /** Path to the offending value, e.g. `user.createdAt`. */\n readonly path: ReadonlyArray<string | number>;\n constructor(message: string, path: ReadonlyArray<string | number> = []) {\n const where = path.length ? ` (at ${path.join(\".\")})` : \"\";\n super(`${message}${where}`);\n this.name = \"CodecError\";\n this.path = path;\n }\n}\n\n/** Thrown when `deserialize` is given a schema containing async refinements. */\nexport class AsyncSchemaError extends Error {\n constructor() {\n super(\n \"deserialize is sync-only; this schema has async refinements. \" +\n \"Remove async .refine()/.superRefine() or validate separately with parseAsync.\",\n );\n this.name = \"AsyncSchemaError\";\n }\n}\n\n/**\n * DoS guards on attacker-controlled wire input. A BigInt parsed from a very\n * long numeric string, or a Map rebuilt from a huge entries array, can stall\n * the event loop; these caps reject such input up front.\n */\nexport const LIMITS = {\n /** Max characters in a BigInt wire string (sign + digits). */\n bigintStringLength: 4096,\n /** Max entries when rebuilding a Map from a wire array. */\n mapEntries: 100_000,\n} as const;\n\n// --- Date <-> ISO string ---\n\nexport function dateToIso(value: Date, path: ReadonlyArray<string | number>): string {\n if (!(value instanceof Date) || Number.isNaN(value.getTime())) {\n throw new CodecError(\"expected a valid Date\", path);\n }\n return value.toISOString();\n}\n\nexport function isoToDate(value: unknown, path: ReadonlyArray<string | number>): Date {\n if (typeof value !== \"string\") {\n throw new CodecError(\"expected an ISO date string\", path);\n }\n const ms = Date.parse(value);\n if (Number.isNaN(ms)) {\n throw new CodecError(\"invalid ISO date string\", path);\n }\n return new Date(ms);\n}\n\n// --- BigInt <-> string ---\n\nexport function bigintToString(value: bigint, path: ReadonlyArray<string | number>): string {\n if (typeof value !== \"bigint\") {\n throw new CodecError(\"expected a bigint\", path);\n }\n return value.toString();\n}\n\nexport function stringToBigint(value: unknown, path: ReadonlyArray<string | number>): bigint {\n if (typeof value !== \"string\") {\n throw new CodecError(\"expected a bigint string\", path);\n }\n if (value.length > LIMITS.bigintStringLength) {\n throw new CodecError(\n `bigint string exceeds ${LIMITS.bigintStringLength} chars`,\n path,\n );\n }\n if (!/^-?\\d+$/.test(value)) {\n throw new CodecError(\"malformed bigint string\", path);\n }\n return BigInt(value);\n}\n\n// --- Map <-> entries array ---\n\nexport function mapToEntries(\n value: Map<unknown, unknown>,\n path: ReadonlyArray<string | number>,\n): Array<[unknown, unknown]> {\n if (!(value instanceof Map)) {\n throw new CodecError(\"expected a Map\", path);\n }\n return Array.from(value.entries());\n}\n\nexport function entriesToArray(\n value: unknown,\n path: ReadonlyArray<string | number>,\n): Array<[unknown, unknown]> {\n if (!Array.isArray(value)) {\n throw new CodecError(\"expected a Map entries array\", path);\n }\n if (value.length > LIMITS.mapEntries) {\n throw new CodecError(`Map entries exceed ${LIMITS.mapEntries}`, path);\n }\n for (const entry of value) {\n if (!Array.isArray(entry) || entry.length !== 2) {\n throw new CodecError(\"malformed Map entry (expected [key, value])\", path);\n }\n }\n return value as Array<[unknown, unknown]>;\n}\n\n// --- Set <-> array ---\n\nexport function setToArray(\n value: Set<unknown>,\n path: ReadonlyArray<string | number>,\n): unknown[] {\n if (!(value instanceof Set)) {\n throw new CodecError(\"expected a Set\", path);\n }\n return Array.from(value.values());\n}\n\nexport function arrayToSetItems(\n value: unknown,\n path: ReadonlyArray<string | number>,\n): unknown[] {\n if (!Array.isArray(value)) {\n throw new CodecError(\"expected a Set values array\", path);\n }\n if (value.length > LIMITS.mapEntries) {\n throw new CodecError(`Set values exceed ${LIMITS.mapEntries}`, path);\n }\n return value;\n}\n","/**\n * Schema-driven JSON-safe codec for Zod 4 schemas.\n *\n * `serialize` walks a value alongside its Zod schema and replaces rich runtime\n * types (Date, BigInt, Map) with JSON-safe representations; `deserialize` walks\n * the wire form back into rich values and then validates with Zod.\n *\n * Zod-4 only: all schema-shape reads go through {@link typeOf}/{@link unwrap},\n * which dispatch on the Zod 4 internal `_zod.def.type` (lowercase strings).\n * Zod 3's `_def.typeName` is intentionally unsupported.\n */\nimport type { z } from \"zod\";\nimport {\n AsyncSchemaError,\n CodecError,\n bigintToString,\n arrayToSetItems,\n dateToIso,\n entriesToArray,\n isoToDate,\n mapToEntries,\n setToArray,\n stringToBigint,\n} from \"./json-types.js\";\n\ntype AnyZod = z.ZodType;\ntype Path = ReadonlyArray<string | number>;\ntype Direction = \"serialize\" | \"deserialize\";\n\n// Minimal structural view of the Zod 4 internal def. Centralizes the one place\n// the library couples to `_zod.def`, so a Zod minor bump touches only this file.\ninterface ZodDef {\n type: string;\n innerType?: AnyZod;\n element?: AnyZod;\n shape?: Record<string, AnyZod>;\n keyType?: AnyZod;\n valueType?: AnyZod;\n options?: AnyZod[];\n getter?: () => AnyZod;\n in?: AnyZod;\n}\n\nfunction defOf(schema: AnyZod): ZodDef {\n return (schema as unknown as { _zod: { def: ZodDef } })._zod.def;\n}\n\n/** The Zod 4 node kind, e.g. `\"object\"`, `\"array\"`, `\"date\"`. */\nexport function typeOf(schema: AnyZod): string {\n return defOf(schema).type;\n}\n\n/**\n * Peel wrapper nodes that do not change the JSON-safe shape:\n * optional/nullable/default (innerType), pipe/transform (the `in` schema is the\n * wire-facing shape), and lazy (resolve the getter). Object `.refine()` in Zod\n * 4 stays a plain `object` node with its `shape` intact, so it needs no peeling.\n */\nexport function unwrap(schema: AnyZod): AnyZod {\n let current = schema;\n // Bounded by schema nesting depth; each step strictly descends.\n for (;;) {\n const def = defOf(current);\n switch (def.type) {\n case \"optional\":\n case \"nullable\":\n case \"default\":\n case \"nonoptional\":\n case \"readonly\":\n case \"catch\":\n current = def.innerType as AnyZod;\n break;\n case \"pipe\":\n // `.transform()` and `.pipe()` both produce a pipe; the `in` side is the\n // shape that wire data is validated against.\n current = def.in as AnyZod;\n break;\n case \"lazy\":\n current = (def.getter as () => AnyZod)();\n break;\n default:\n return current;\n }\n }\n}\n\nfunction walk(schema: AnyZod, value: unknown, dir: Direction, path: Path): unknown {\n if (value === null || value === undefined) return value;\n\n const node = unwrap(schema);\n const def = defOf(node);\n\n switch (def.type) {\n case \"object\": {\n if (typeof value !== \"object\" || Array.isArray(value)) {\n throw new CodecError(\"expected an object\", path);\n }\n const shape = def.shape as Record<string, AnyZod>;\n const src = value as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const key of Object.keys(shape)) {\n if (Object.prototype.hasOwnProperty.call(src, key)) {\n out[key] = walk(shape[key] as AnyZod, src[key], dir, [...path, key]);\n }\n }\n return out;\n }\n\n case \"array\": {\n if (!Array.isArray(value)) throw new CodecError(\"expected an array\", path);\n const element = def.element as AnyZod;\n return value.map((item, i) => walk(element, item, dir, [...path, i]));\n }\n\n case \"map\": {\n const keyType = def.keyType as AnyZod;\n const valueType = def.valueType as AnyZod;\n if (dir === \"serialize\") {\n const entries = mapToEntries(value as Map<unknown, unknown>, path);\n return entries.map(([k, v], i) => [\n walk(keyType, k, dir, [...path, i, \"key\"]),\n walk(valueType, v, dir, [...path, i, \"value\"]),\n ]);\n }\n const entries = entriesToArray(value, path);\n const out = new Map<unknown, unknown>();\n entries.forEach(([k, v], i) => {\n out.set(\n walk(keyType, k, dir, [...path, i, \"key\"]),\n walk(valueType, v, dir, [...path, i, \"value\"]),\n );\n });\n return out;\n }\n\n case \"set\": {\n const valueType = def.valueType as AnyZod;\n if (dir === \"serialize\") {\n const items = setToArray(value as Set<unknown>, path);\n return items.map((item, i) => walk(valueType, item, dir, [...path, i]));\n }\n const items = arrayToSetItems(value, path);\n return new Set(items.map((item, i) => walk(valueType, item, dir, [...path, i])));\n }\n\n case \"union\": {\n // Try each member; first that walks without a CodecError wins. Mirrors\n // Zod's own \"first match\" union semantics for the JSON-safe shape. A\n // non-CodecError (e.g. a throwing z.lazy getter) is a real fault and\n // propagates immediately rather than being treated as a failed match.\n const options = def.options as AnyZod[];\n let lastError: CodecError = new CodecError(\"no union member matched\", path);\n for (const option of options) {\n try {\n return walk(option, value, dir, path);\n } catch (err) {\n if (!(err instanceof CodecError)) throw err;\n lastError = err;\n }\n }\n throw lastError;\n }\n\n case \"date\":\n return dir === \"serialize\"\n ? dateToIso(value as Date, path)\n : isoToDate(value, path);\n\n case \"bigint\":\n return dir === \"serialize\"\n ? bigintToString(value as bigint, path)\n : stringToBigint(value, path);\n\n // Scalars and explicit escape hatches pass through untouched.\n case \"string\":\n case \"number\":\n case \"boolean\":\n case \"nan\":\n case \"null\":\n case \"undefined\":\n case \"literal\":\n case \"enum\":\n case \"any\":\n case \"unknown\":\n case \"void\":\n case \"custom\":\n return value;\n\n default:\n // Fail closed: an unhandled object-like node would otherwise silently\n // skip its inner schema. Use z.custom() for genuinely opaque values.\n throw new CodecError(`unsupported schema node \"${def.type}\"`, path);\n }\n}\n\n/**\n * Convert a rich value into a JSON-safe plain value per its Zod schema.\n * Date -> ISO string, BigInt -> string, Map -> `[key, value][]`, recursing\n * through objects, arrays, maps and unions. The result survives\n * `JSON.parse(JSON.stringify(...))` with no loss for supported types.\n */\nexport function serialize<S extends AnyZod>(value: z.infer<S>, schema: S): unknown {\n return walk(schema, value, \"serialize\", []);\n}\n\nfunction isZodAsyncError(err: unknown): boolean {\n const name = (err as { constructor?: { name?: string } } | null)?.constructor?.name;\n return name === \"$ZodAsyncError\";\n}\n\n/**\n * Rebuild rich values from their JSON-safe wire form per `schema`, then\n * validate with Zod. Leaf transforms validate their input and surface a typed\n * {@link CodecError} on malformed data, so untrusted JSON never escapes as a\n * raw throw or an unbounded stall. Sync-only: an async-refined schema throws\n * {@link AsyncSchemaError}.\n */\nexport function deserialize<S extends AnyZod>(json: unknown, schema: S): z.infer<S> {\n const rebuilt = walk(schema, json, \"deserialize\", []);\n try {\n return schema.parse(rebuilt) as z.infer<S>;\n } catch (err) {\n if (isZodAsyncError(err)) throw new AsyncSchemaError();\n throw err;\n }\n}\n\n/**\n * Async variant of {@link deserialize}: rebuilds rich values then validates with\n * `parseAsync`, so schemas containing async `.refine`/`.superRefine` are\n * supported (no {@link AsyncSchemaError}). The same leaf-transform safety and\n * DoS bounds apply during the rebuild.\n */\nexport async function deserializeAsync<S extends AnyZod>(\n json: unknown,\n schema: S,\n): Promise<z.infer<S>> {\n const rebuilt = walk(schema, json, \"deserialize\", []);\n return (await schema.parseAsync(rebuilt)) as z.infer<S>;\n}\n"]}
@@ -0,0 +1,84 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Schema-driven JSON-safe codec for Zod 4 schemas.
5
+ *
6
+ * `serialize` walks a value alongside its Zod schema and replaces rich runtime
7
+ * types (Date, BigInt, Map) with JSON-safe representations; `deserialize` walks
8
+ * the wire form back into rich values and then validates with Zod.
9
+ *
10
+ * Zod-4 only: all schema-shape reads go through {@link typeOf}/{@link unwrap},
11
+ * which dispatch on the Zod 4 internal `_zod.def.type` (lowercase strings).
12
+ * Zod 3's `_def.typeName` is intentionally unsupported.
13
+ */
14
+
15
+ type AnyZod = z.ZodType;
16
+ /** The Zod 4 node kind, e.g. `"object"`, `"array"`, `"date"`. */
17
+ declare function typeOf(schema: AnyZod): string;
18
+ /**
19
+ * Peel wrapper nodes that do not change the JSON-safe shape:
20
+ * optional/nullable/default (innerType), pipe/transform (the `in` schema is the
21
+ * wire-facing shape), and lazy (resolve the getter). Object `.refine()` in Zod
22
+ * 4 stays a plain `object` node with its `shape` intact, so it needs no peeling.
23
+ */
24
+ declare function unwrap(schema: AnyZod): AnyZod;
25
+ /**
26
+ * Convert a rich value into a JSON-safe plain value per its Zod schema.
27
+ * Date -> ISO string, BigInt -> string, Map -> `[key, value][]`, recursing
28
+ * through objects, arrays, maps and unions. The result survives
29
+ * `JSON.parse(JSON.stringify(...))` with no loss for supported types.
30
+ */
31
+ declare function serialize<S extends AnyZod>(value: z.infer<S>, schema: S): unknown;
32
+ /**
33
+ * Rebuild rich values from their JSON-safe wire form per `schema`, then
34
+ * validate with Zod. Leaf transforms validate their input and surface a typed
35
+ * {@link CodecError} on malformed data, so untrusted JSON never escapes as a
36
+ * raw throw or an unbounded stall. Sync-only: an async-refined schema throws
37
+ * {@link AsyncSchemaError}.
38
+ */
39
+ declare function deserialize<S extends AnyZod>(json: unknown, schema: S): z.infer<S>;
40
+ /**
41
+ * Async variant of {@link deserialize}: rebuilds rich values then validates with
42
+ * `parseAsync`, so schemas containing async `.refine`/`.superRefine` are
43
+ * supported (no {@link AsyncSchemaError}). The same leaf-transform safety and
44
+ * DoS bounds apply during the rebuild.
45
+ */
46
+ declare function deserializeAsync<S extends AnyZod>(json: unknown, schema: S): Promise<z.infer<S>>;
47
+
48
+ /**
49
+ * Leaf transforms between rich JS values and their JSON-safe wire forms.
50
+ * Each inverse (wire -> JS) transform validates its input and throws a
51
+ * {@link CodecError} on malformed data, so a hostile wire payload surfaces a
52
+ * typed error instead of a raw `TypeError`/`SyntaxError` or an unbounded stall.
53
+ */
54
+ /** Thrown for malformed wire input or unsupported schema nodes during codec walk. */
55
+ declare class CodecError extends Error {
56
+ /** Path to the offending value, e.g. `user.createdAt`. */
57
+ readonly path: ReadonlyArray<string | number>;
58
+ constructor(message: string, path?: ReadonlyArray<string | number>);
59
+ }
60
+ /** Thrown when `deserialize` is given a schema containing async refinements. */
61
+ declare class AsyncSchemaError extends Error {
62
+ constructor();
63
+ }
64
+ /**
65
+ * DoS guards on attacker-controlled wire input. A BigInt parsed from a very
66
+ * long numeric string, or a Map rebuilt from a huge entries array, can stall
67
+ * the event loop; these caps reject such input up front.
68
+ */
69
+ declare const LIMITS: {
70
+ /** Max characters in a BigInt wire string (sign + digits). */
71
+ readonly bigintStringLength: 4096;
72
+ /** Max entries when rebuilding a Map from a wire array. */
73
+ readonly mapEntries: 100000;
74
+ };
75
+ declare function dateToIso(value: Date, path: ReadonlyArray<string | number>): string;
76
+ declare function isoToDate(value: unknown, path: ReadonlyArray<string | number>): Date;
77
+ declare function bigintToString(value: bigint, path: ReadonlyArray<string | number>): string;
78
+ declare function stringToBigint(value: unknown, path: ReadonlyArray<string | number>): bigint;
79
+ declare function mapToEntries(value: Map<unknown, unknown>, path: ReadonlyArray<string | number>): Array<[unknown, unknown]>;
80
+ declare function entriesToArray(value: unknown, path: ReadonlyArray<string | number>): Array<[unknown, unknown]>;
81
+ declare function setToArray(value: Set<unknown>, path: ReadonlyArray<string | number>): unknown[];
82
+ declare function arrayToSetItems(value: unknown, path: ReadonlyArray<string | number>): unknown[];
83
+
84
+ export { AsyncSchemaError, CodecError, LIMITS, arrayToSetItems, bigintToString, dateToIso, deserialize, deserializeAsync, entriesToArray, isoToDate, mapToEntries, serialize, setToArray, stringToBigint, typeOf, unwrap };
@@ -0,0 +1,84 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Schema-driven JSON-safe codec for Zod 4 schemas.
5
+ *
6
+ * `serialize` walks a value alongside its Zod schema and replaces rich runtime
7
+ * types (Date, BigInt, Map) with JSON-safe representations; `deserialize` walks
8
+ * the wire form back into rich values and then validates with Zod.
9
+ *
10
+ * Zod-4 only: all schema-shape reads go through {@link typeOf}/{@link unwrap},
11
+ * which dispatch on the Zod 4 internal `_zod.def.type` (lowercase strings).
12
+ * Zod 3's `_def.typeName` is intentionally unsupported.
13
+ */
14
+
15
+ type AnyZod = z.ZodType;
16
+ /** The Zod 4 node kind, e.g. `"object"`, `"array"`, `"date"`. */
17
+ declare function typeOf(schema: AnyZod): string;
18
+ /**
19
+ * Peel wrapper nodes that do not change the JSON-safe shape:
20
+ * optional/nullable/default (innerType), pipe/transform (the `in` schema is the
21
+ * wire-facing shape), and lazy (resolve the getter). Object `.refine()` in Zod
22
+ * 4 stays a plain `object` node with its `shape` intact, so it needs no peeling.
23
+ */
24
+ declare function unwrap(schema: AnyZod): AnyZod;
25
+ /**
26
+ * Convert a rich value into a JSON-safe plain value per its Zod schema.
27
+ * Date -> ISO string, BigInt -> string, Map -> `[key, value][]`, recursing
28
+ * through objects, arrays, maps and unions. The result survives
29
+ * `JSON.parse(JSON.stringify(...))` with no loss for supported types.
30
+ */
31
+ declare function serialize<S extends AnyZod>(value: z.infer<S>, schema: S): unknown;
32
+ /**
33
+ * Rebuild rich values from their JSON-safe wire form per `schema`, then
34
+ * validate with Zod. Leaf transforms validate their input and surface a typed
35
+ * {@link CodecError} on malformed data, so untrusted JSON never escapes as a
36
+ * raw throw or an unbounded stall. Sync-only: an async-refined schema throws
37
+ * {@link AsyncSchemaError}.
38
+ */
39
+ declare function deserialize<S extends AnyZod>(json: unknown, schema: S): z.infer<S>;
40
+ /**
41
+ * Async variant of {@link deserialize}: rebuilds rich values then validates with
42
+ * `parseAsync`, so schemas containing async `.refine`/`.superRefine` are
43
+ * supported (no {@link AsyncSchemaError}). The same leaf-transform safety and
44
+ * DoS bounds apply during the rebuild.
45
+ */
46
+ declare function deserializeAsync<S extends AnyZod>(json: unknown, schema: S): Promise<z.infer<S>>;
47
+
48
+ /**
49
+ * Leaf transforms between rich JS values and their JSON-safe wire forms.
50
+ * Each inverse (wire -> JS) transform validates its input and throws a
51
+ * {@link CodecError} on malformed data, so a hostile wire payload surfaces a
52
+ * typed error instead of a raw `TypeError`/`SyntaxError` or an unbounded stall.
53
+ */
54
+ /** Thrown for malformed wire input or unsupported schema nodes during codec walk. */
55
+ declare class CodecError extends Error {
56
+ /** Path to the offending value, e.g. `user.createdAt`. */
57
+ readonly path: ReadonlyArray<string | number>;
58
+ constructor(message: string, path?: ReadonlyArray<string | number>);
59
+ }
60
+ /** Thrown when `deserialize` is given a schema containing async refinements. */
61
+ declare class AsyncSchemaError extends Error {
62
+ constructor();
63
+ }
64
+ /**
65
+ * DoS guards on attacker-controlled wire input. A BigInt parsed from a very
66
+ * long numeric string, or a Map rebuilt from a huge entries array, can stall
67
+ * the event loop; these caps reject such input up front.
68
+ */
69
+ declare const LIMITS: {
70
+ /** Max characters in a BigInt wire string (sign + digits). */
71
+ readonly bigintStringLength: 4096;
72
+ /** Max entries when rebuilding a Map from a wire array. */
73
+ readonly mapEntries: 100000;
74
+ };
75
+ declare function dateToIso(value: Date, path: ReadonlyArray<string | number>): string;
76
+ declare function isoToDate(value: unknown, path: ReadonlyArray<string | number>): Date;
77
+ declare function bigintToString(value: bigint, path: ReadonlyArray<string | number>): string;
78
+ declare function stringToBigint(value: unknown, path: ReadonlyArray<string | number>): bigint;
79
+ declare function mapToEntries(value: Map<unknown, unknown>, path: ReadonlyArray<string | number>): Array<[unknown, unknown]>;
80
+ declare function entriesToArray(value: unknown, path: ReadonlyArray<string | number>): Array<[unknown, unknown]>;
81
+ declare function setToArray(value: Set<unknown>, path: ReadonlyArray<string | number>): unknown[];
82
+ declare function arrayToSetItems(value: unknown, path: ReadonlyArray<string | number>): unknown[];
83
+
84
+ export { AsyncSchemaError, CodecError, LIMITS, arrayToSetItems, bigintToString, dateToIso, deserialize, deserializeAsync, entriesToArray, isoToDate, mapToEntries, serialize, setToArray, stringToBigint, typeOf, unwrap };
@@ -0,0 +1,3 @@
1
+ export { AsyncSchemaError, CodecError, LIMITS, arrayToSetItems, bigintToString, dateToIso, deserialize, deserializeAsync, entriesToArray, isoToDate, mapToEntries, serialize, setToArray, stringToBigint, typeOf, unwrap } from '../chunk-U3W6PGFE.js';
2
+ //# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}