zod-nest 1.4.0 → 1.5.1

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
@@ -433,6 +433,14 @@ A compact, link-out index. Type signatures and detailed semantics live in the co
433
433
  **Schema engine** — single-schema mode and extension points
434
434
  - `toOpenApi(schema, opts)`, `createRegistry()`, `defaultRegistry`, `ZodNestRegistry`, `Override`, `OverrideContext`, `overrideJSONSchema(schema, fragment | { input?, output? })`, `OverrideJSONSchemaArg`, `ZodNestError`, `ZodNestUnrepresentableError`, `extend`, `getLineage`, `LineageEntry`
435
435
 
436
+ **Helpers** (subpath: `zod-nest/helpers`) — common JSON Schema fragments + presets for assembling overrides
437
+ - **Fragment catalog** (frozen consts): `dateTimeFragment`, `dateFragment`, `timeFragment`, `uuidFragment`, `emailFragment`, `uriFragment`, `hostnameFragment`, `ipv4Fragment`, `ipv6Fragment`, `binaryFragment`, `byteFragment`, `int32Fragment`, `int64Fragment`, `floatFragment`, `doubleFragment`, `opaqueFragment`
438
+ - **Sugar functions**: `binary(opts?)`, `opaque(opts?)`
439
+ - **Type-strict composition**: `enrich(base, extras)` — extras are typed per fragment family
440
+ - **Pre-registered Zod schemas**: `FileSchema`, `BlobSchema`, `BufferSchema` (all `z.instanceof(...)` + `binaryFragment`)
441
+
442
+ See [`docs/recipes/custom-openapi-overrides.md`](docs/recipes/custom-openapi-overrides.md) for the full catalog and usage patterns.
443
+
436
444
  ## Documentation
437
445
 
438
446
  | Topic | Doc |
@@ -0,0 +1,167 @@
1
+ import { S as SchemaObject } from '../openapi.types-CFBG3Zz9.mjs';
2
+ import * as buffer from 'buffer';
3
+ import { z } from 'zod';
4
+ import 'zod/v4/core';
5
+
6
+ /**
7
+ * Common JSON Schema fragment catalog — reusable building blocks for assembling
8
+ * fragments by hand: alongside `z.custom<T>()`, in `overrideJSONSchema` calls,
9
+ * in custom override callbacks, in tests that build expected fragments.
10
+ *
11
+ * The catalog overlaps with what Zod constructs already emit (`z.uuid()` →
12
+ * `uuidFragment` shape, `z.email()` → `emailFragment` shape, etc.) — the
13
+ * helpers don't *replace* those Zod constructs; they're a parallel catalog
14
+ * for programmatic fragment assembly.
15
+ *
16
+ * Each fragment is `as const satisfies SchemaObject` so its literal type
17
+ * powers the dispatch in {@link enrich} — passing wrong-family options
18
+ * fails at compile time.
19
+ */
20
+ declare const dateTimeFragment: {
21
+ readonly type: "string";
22
+ readonly format: "date-time";
23
+ };
24
+ declare const dateFragment: {
25
+ readonly type: "string";
26
+ readonly format: "date";
27
+ };
28
+ declare const timeFragment: {
29
+ readonly type: "string";
30
+ readonly format: "time";
31
+ };
32
+ declare const uuidFragment: {
33
+ readonly type: "string";
34
+ readonly format: "uuid";
35
+ };
36
+ declare const emailFragment: {
37
+ readonly type: "string";
38
+ readonly format: "email";
39
+ };
40
+ declare const uriFragment: {
41
+ readonly type: "string";
42
+ readonly format: "uri";
43
+ };
44
+ declare const hostnameFragment: {
45
+ readonly type: "string";
46
+ readonly format: "hostname";
47
+ };
48
+ declare const ipv4Fragment: {
49
+ readonly type: "string";
50
+ readonly format: "ipv4";
51
+ };
52
+ declare const ipv6Fragment: {
53
+ readonly type: "string";
54
+ readonly format: "ipv6";
55
+ };
56
+ declare const binaryFragment: {
57
+ readonly type: "string";
58
+ readonly format: "binary";
59
+ };
60
+ declare const byteFragment: {
61
+ readonly type: "string";
62
+ readonly format: "byte";
63
+ };
64
+ declare const int32Fragment: {
65
+ readonly type: "integer";
66
+ readonly format: "int32";
67
+ };
68
+ declare const int64Fragment: {
69
+ readonly type: "integer";
70
+ readonly format: "int64";
71
+ };
72
+ declare const floatFragment: {
73
+ readonly type: "number";
74
+ readonly format: "float";
75
+ };
76
+ declare const doubleFragment: {
77
+ readonly type: "number";
78
+ readonly format: "double";
79
+ };
80
+ declare const opaqueFragment: {
81
+ readonly type: "object";
82
+ readonly additionalProperties: true;
83
+ };
84
+ interface StringFormatOptions {
85
+ description?: string;
86
+ examples?: string[];
87
+ minLength?: number;
88
+ maxLength?: number;
89
+ pattern?: string;
90
+ }
91
+ interface BinaryFragmentOptions {
92
+ description?: string;
93
+ contentMediaType?: string;
94
+ contentEncoding?: string;
95
+ }
96
+ interface NumberFormatOptions {
97
+ description?: string;
98
+ examples?: number[];
99
+ minimum?: number;
100
+ maximum?: number;
101
+ exclusiveMinimum?: number;
102
+ exclusiveMaximum?: number;
103
+ multipleOf?: number;
104
+ }
105
+ interface OpaqueFragmentOptions {
106
+ description?: string;
107
+ }
108
+ type OptionsFor<T> = T extends {
109
+ readonly format: 'binary';
110
+ } ? BinaryFragmentOptions : T extends {
111
+ readonly format: 'date-time' | 'date' | 'time' | 'uuid' | 'email' | 'uri' | 'hostname' | 'ipv4' | 'ipv6' | 'byte';
112
+ } ? StringFormatOptions : T extends {
113
+ readonly format: 'int32' | 'int64' | 'float' | 'double';
114
+ } ? NumberFormatOptions : T extends {
115
+ readonly type: 'object';
116
+ readonly additionalProperties: true;
117
+ } ? OpaqueFragmentOptions : never;
118
+ /**
119
+ * Merge a catalog fragment with extras whose shape is dictated by the base
120
+ * fragment's family. Passing wrong-family extras (e.g. a `contentMediaType`
121
+ * onto `uuidFragment`) is a compile-time error.
122
+ *
123
+ * Returns a fresh `SchemaObject` — the original fragment is never mutated.
124
+ */
125
+ declare const enrich: <T extends SchemaObject>(base: T, extras: OptionsFor<T>) => SchemaObject;
126
+ /**
127
+ * Binary-content fragment with typed enrichment. Sugar for
128
+ * `enrich(binaryFragment, opts)` — exists because the `binary` option set
129
+ * (`contentMediaType` / `contentEncoding`) is nuanced enough to deserve a
130
+ * dedicated entry point and discoverable via auto-complete.
131
+ *
132
+ * @example
133
+ * overrideJSONSchema(z.instanceof(File), binary());
134
+ * overrideJSONSchema(z.instanceof(File), binary({ contentMediaType: 'application/pdf' }));
135
+ */
136
+ declare const binary: (opts?: BinaryFragmentOptions) => SchemaObject;
137
+ /**
138
+ * Opaque-object fragment with typed enrichment. Sugar for
139
+ * `enrich(opaqueFragment, opts)` — exists for parity with {@link binary}
140
+ * and because opaque passthrough payloads commonly carry a description
141
+ * explaining why the API doesn't introspect them.
142
+ *
143
+ * @example
144
+ * overrideJSONSchema(z.unknown(), opaque({ description: 'JWT passthrough' }));
145
+ */
146
+ declare const opaque: (opts?: OpaqueFragmentOptions) => SchemaObject;
147
+
148
+ /**
149
+ * Pre-registered Zod schemas for the common binary runtime types. Each
150
+ * schema is wired through `overrideJSONSchema` so it emits `binaryFragment`
151
+ * verbatim in OpenAPI — drop into a DTO without further setup.
152
+ *
153
+ * Node 22+ provides `File`, `Blob`, and `Buffer` as globals (zod-nest's
154
+ * `engines.node >=22`), so `z.instanceof(...)` at module load is safe.
155
+ *
156
+ * @example
157
+ * import { FileSchema } from 'zod-nest/helpers';
158
+ *
159
+ * class UploadDto extends createZodDto(
160
+ * z.object({ file: FileSchema }),
161
+ * ) {}
162
+ */
163
+ declare const FileSchema: z.ZodCustom<buffer.File, buffer.File>;
164
+ declare const BlobSchema: z.ZodCustom<buffer.Blob, buffer.Blob>;
165
+ declare const BufferSchema: z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>;
166
+
167
+ export { type BinaryFragmentOptions, BlobSchema, BufferSchema, FileSchema, type NumberFormatOptions, type OpaqueFragmentOptions, type StringFormatOptions, binary, binaryFragment, byteFragment, dateFragment, dateTimeFragment, doubleFragment, emailFragment, enrich, floatFragment, hostnameFragment, int32Fragment, int64Fragment, ipv4Fragment, ipv6Fragment, opaque, opaqueFragment, timeFragment, uriFragment, uuidFragment };
@@ -0,0 +1,167 @@
1
+ import { S as SchemaObject } from '../openapi.types-CFBG3Zz9.js';
2
+ import * as buffer from 'buffer';
3
+ import { z } from 'zod';
4
+ import 'zod/v4/core';
5
+
6
+ /**
7
+ * Common JSON Schema fragment catalog — reusable building blocks for assembling
8
+ * fragments by hand: alongside `z.custom<T>()`, in `overrideJSONSchema` calls,
9
+ * in custom override callbacks, in tests that build expected fragments.
10
+ *
11
+ * The catalog overlaps with what Zod constructs already emit (`z.uuid()` →
12
+ * `uuidFragment` shape, `z.email()` → `emailFragment` shape, etc.) — the
13
+ * helpers don't *replace* those Zod constructs; they're a parallel catalog
14
+ * for programmatic fragment assembly.
15
+ *
16
+ * Each fragment is `as const satisfies SchemaObject` so its literal type
17
+ * powers the dispatch in {@link enrich} — passing wrong-family options
18
+ * fails at compile time.
19
+ */
20
+ declare const dateTimeFragment: {
21
+ readonly type: "string";
22
+ readonly format: "date-time";
23
+ };
24
+ declare const dateFragment: {
25
+ readonly type: "string";
26
+ readonly format: "date";
27
+ };
28
+ declare const timeFragment: {
29
+ readonly type: "string";
30
+ readonly format: "time";
31
+ };
32
+ declare const uuidFragment: {
33
+ readonly type: "string";
34
+ readonly format: "uuid";
35
+ };
36
+ declare const emailFragment: {
37
+ readonly type: "string";
38
+ readonly format: "email";
39
+ };
40
+ declare const uriFragment: {
41
+ readonly type: "string";
42
+ readonly format: "uri";
43
+ };
44
+ declare const hostnameFragment: {
45
+ readonly type: "string";
46
+ readonly format: "hostname";
47
+ };
48
+ declare const ipv4Fragment: {
49
+ readonly type: "string";
50
+ readonly format: "ipv4";
51
+ };
52
+ declare const ipv6Fragment: {
53
+ readonly type: "string";
54
+ readonly format: "ipv6";
55
+ };
56
+ declare const binaryFragment: {
57
+ readonly type: "string";
58
+ readonly format: "binary";
59
+ };
60
+ declare const byteFragment: {
61
+ readonly type: "string";
62
+ readonly format: "byte";
63
+ };
64
+ declare const int32Fragment: {
65
+ readonly type: "integer";
66
+ readonly format: "int32";
67
+ };
68
+ declare const int64Fragment: {
69
+ readonly type: "integer";
70
+ readonly format: "int64";
71
+ };
72
+ declare const floatFragment: {
73
+ readonly type: "number";
74
+ readonly format: "float";
75
+ };
76
+ declare const doubleFragment: {
77
+ readonly type: "number";
78
+ readonly format: "double";
79
+ };
80
+ declare const opaqueFragment: {
81
+ readonly type: "object";
82
+ readonly additionalProperties: true;
83
+ };
84
+ interface StringFormatOptions {
85
+ description?: string;
86
+ examples?: string[];
87
+ minLength?: number;
88
+ maxLength?: number;
89
+ pattern?: string;
90
+ }
91
+ interface BinaryFragmentOptions {
92
+ description?: string;
93
+ contentMediaType?: string;
94
+ contentEncoding?: string;
95
+ }
96
+ interface NumberFormatOptions {
97
+ description?: string;
98
+ examples?: number[];
99
+ minimum?: number;
100
+ maximum?: number;
101
+ exclusiveMinimum?: number;
102
+ exclusiveMaximum?: number;
103
+ multipleOf?: number;
104
+ }
105
+ interface OpaqueFragmentOptions {
106
+ description?: string;
107
+ }
108
+ type OptionsFor<T> = T extends {
109
+ readonly format: 'binary';
110
+ } ? BinaryFragmentOptions : T extends {
111
+ readonly format: 'date-time' | 'date' | 'time' | 'uuid' | 'email' | 'uri' | 'hostname' | 'ipv4' | 'ipv6' | 'byte';
112
+ } ? StringFormatOptions : T extends {
113
+ readonly format: 'int32' | 'int64' | 'float' | 'double';
114
+ } ? NumberFormatOptions : T extends {
115
+ readonly type: 'object';
116
+ readonly additionalProperties: true;
117
+ } ? OpaqueFragmentOptions : never;
118
+ /**
119
+ * Merge a catalog fragment with extras whose shape is dictated by the base
120
+ * fragment's family. Passing wrong-family extras (e.g. a `contentMediaType`
121
+ * onto `uuidFragment`) is a compile-time error.
122
+ *
123
+ * Returns a fresh `SchemaObject` — the original fragment is never mutated.
124
+ */
125
+ declare const enrich: <T extends SchemaObject>(base: T, extras: OptionsFor<T>) => SchemaObject;
126
+ /**
127
+ * Binary-content fragment with typed enrichment. Sugar for
128
+ * `enrich(binaryFragment, opts)` — exists because the `binary` option set
129
+ * (`contentMediaType` / `contentEncoding`) is nuanced enough to deserve a
130
+ * dedicated entry point and discoverable via auto-complete.
131
+ *
132
+ * @example
133
+ * overrideJSONSchema(z.instanceof(File), binary());
134
+ * overrideJSONSchema(z.instanceof(File), binary({ contentMediaType: 'application/pdf' }));
135
+ */
136
+ declare const binary: (opts?: BinaryFragmentOptions) => SchemaObject;
137
+ /**
138
+ * Opaque-object fragment with typed enrichment. Sugar for
139
+ * `enrich(opaqueFragment, opts)` — exists for parity with {@link binary}
140
+ * and because opaque passthrough payloads commonly carry a description
141
+ * explaining why the API doesn't introspect them.
142
+ *
143
+ * @example
144
+ * overrideJSONSchema(z.unknown(), opaque({ description: 'JWT passthrough' }));
145
+ */
146
+ declare const opaque: (opts?: OpaqueFragmentOptions) => SchemaObject;
147
+
148
+ /**
149
+ * Pre-registered Zod schemas for the common binary runtime types. Each
150
+ * schema is wired through `overrideJSONSchema` so it emits `binaryFragment`
151
+ * verbatim in OpenAPI — drop into a DTO without further setup.
152
+ *
153
+ * Node 22+ provides `File`, `Blob`, and `Buffer` as globals (zod-nest's
154
+ * `engines.node >=22`), so `z.instanceof(...)` at module load is safe.
155
+ *
156
+ * @example
157
+ * import { FileSchema } from 'zod-nest/helpers';
158
+ *
159
+ * class UploadDto extends createZodDto(
160
+ * z.object({ file: FileSchema }),
161
+ * ) {}
162
+ */
163
+ declare const FileSchema: z.ZodCustom<buffer.File, buffer.File>;
164
+ declare const BlobSchema: z.ZodCustom<buffer.Blob, buffer.Blob>;
165
+ declare const BufferSchema: z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>;
166
+
167
+ export { type BinaryFragmentOptions, BlobSchema, BufferSchema, FileSchema, type NumberFormatOptions, type OpaqueFragmentOptions, type StringFormatOptions, binary, binaryFragment, byteFragment, dateFragment, dateTimeFragment, doubleFragment, emailFragment, enrich, floatFragment, hostnameFragment, int32Fragment, int64Fragment, ipv4Fragment, ipv6Fragment, opaque, opaqueFragment, timeFragment, uriFragment, uuidFragment };
@@ -0,0 +1,132 @@
1
+ 'use strict';
2
+
3
+ var zod = require('zod');
4
+
5
+ var __defProp = Object.defineProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+
8
+ // src/helpers/fragments.ts
9
+ var dateTimeFragment = {
10
+ type: "string",
11
+ format: "date-time"
12
+ };
13
+ var dateFragment = {
14
+ type: "string",
15
+ format: "date"
16
+ };
17
+ var timeFragment = {
18
+ type: "string",
19
+ format: "time"
20
+ };
21
+ var uuidFragment = {
22
+ type: "string",
23
+ format: "uuid"
24
+ };
25
+ var emailFragment = {
26
+ type: "string",
27
+ format: "email"
28
+ };
29
+ var uriFragment = {
30
+ type: "string",
31
+ format: "uri"
32
+ };
33
+ var hostnameFragment = {
34
+ type: "string",
35
+ format: "hostname"
36
+ };
37
+ var ipv4Fragment = {
38
+ type: "string",
39
+ format: "ipv4"
40
+ };
41
+ var ipv6Fragment = {
42
+ type: "string",
43
+ format: "ipv6"
44
+ };
45
+ var binaryFragment = {
46
+ type: "string",
47
+ format: "binary"
48
+ };
49
+ var byteFragment = {
50
+ type: "string",
51
+ format: "byte"
52
+ };
53
+ var int32Fragment = {
54
+ type: "integer",
55
+ format: "int32"
56
+ };
57
+ var int64Fragment = {
58
+ type: "integer",
59
+ format: "int64"
60
+ };
61
+ var floatFragment = {
62
+ type: "number",
63
+ format: "float"
64
+ };
65
+ var doubleFragment = {
66
+ type: "number",
67
+ format: "double"
68
+ };
69
+ var opaqueFragment = {
70
+ type: "object",
71
+ additionalProperties: true
72
+ };
73
+ var enrich = /* @__PURE__ */ __name((base, extras) => ({
74
+ ...base,
75
+ ...extras
76
+ }), "enrich");
77
+ var binary = /* @__PURE__ */ __name((opts) => ({
78
+ ...binaryFragment,
79
+ ...opts
80
+ }), "binary");
81
+ var opaque = /* @__PURE__ */ __name((opts) => ({
82
+ ...opaqueFragment,
83
+ ...opts
84
+ }), "opaque");
85
+
86
+ // src/schema/custom-override.ts
87
+ var customOverrideMap = /* @__PURE__ */ new WeakMap();
88
+ var isWrapper = /* @__PURE__ */ __name((arg) => "input" in arg || "output" in arg, "isWrapper");
89
+ var overrideJSONSchema = /* @__PURE__ */ __name((schema, arg) => {
90
+ const overrideSchema = isWrapper(arg) ? {
91
+ ...arg
92
+ } : {
93
+ input: arg,
94
+ output: arg
95
+ };
96
+ const schemaDescription = schema.description;
97
+ if (typeof schemaDescription === "string") {
98
+ overrideSchema.description = schemaDescription;
99
+ }
100
+ customOverrideMap.set(schema, overrideSchema);
101
+ return schema;
102
+ }, "overrideJSONSchema");
103
+
104
+ // src/helpers/presets.ts
105
+ var FileSchema = overrideJSONSchema(zod.z.instanceof(File), binaryFragment);
106
+ var BlobSchema = overrideJSONSchema(zod.z.instanceof(Blob), binaryFragment);
107
+ var BufferSchema = overrideJSONSchema(zod.z.instanceof(Buffer), binaryFragment);
108
+
109
+ exports.BlobSchema = BlobSchema;
110
+ exports.BufferSchema = BufferSchema;
111
+ exports.FileSchema = FileSchema;
112
+ exports.binary = binary;
113
+ exports.binaryFragment = binaryFragment;
114
+ exports.byteFragment = byteFragment;
115
+ exports.dateFragment = dateFragment;
116
+ exports.dateTimeFragment = dateTimeFragment;
117
+ exports.doubleFragment = doubleFragment;
118
+ exports.emailFragment = emailFragment;
119
+ exports.enrich = enrich;
120
+ exports.floatFragment = floatFragment;
121
+ exports.hostnameFragment = hostnameFragment;
122
+ exports.int32Fragment = int32Fragment;
123
+ exports.int64Fragment = int64Fragment;
124
+ exports.ipv4Fragment = ipv4Fragment;
125
+ exports.ipv6Fragment = ipv6Fragment;
126
+ exports.opaque = opaque;
127
+ exports.opaqueFragment = opaqueFragment;
128
+ exports.timeFragment = timeFragment;
129
+ exports.uriFragment = uriFragment;
130
+ exports.uuidFragment = uuidFragment;
131
+ //# sourceMappingURL=index.js.map
132
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/helpers/fragments.ts","../../src/schema/custom-override.ts","../../src/helpers/presets.ts"],"names":["dateTimeFragment","type","format","dateFragment","timeFragment","uuidFragment","emailFragment","uriFragment","hostnameFragment","ipv4Fragment","ipv6Fragment","binaryFragment","byteFragment","int32Fragment","int64Fragment","floatFragment","doubleFragment","opaqueFragment","additionalProperties","enrich","base","extras","binary","opts","opaque","customOverrideMap","WeakMap","isWrapper","arg","overrideJSONSchema","schema","overrideSchema","input","output","schemaDescription","description","set","FileSchema","z","instanceof","File","BlobSchema","Blob","BufferSchema","Buffer"],"mappings":"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","file":"index.js","sourcesContent":["import type { SchemaObject } from '../schema/openapi.types.js';\n\n/**\n * Common JSON Schema fragment catalog — reusable building blocks for assembling\n * fragments by hand: alongside `z.custom<T>()`, in `overrideJSONSchema` calls,\n * in custom override callbacks, in tests that build expected fragments.\n *\n * The catalog overlaps with what Zod constructs already emit (`z.uuid()` →\n * `uuidFragment` shape, `z.email()` → `emailFragment` shape, etc.) — the\n * helpers don't *replace* those Zod constructs; they're a parallel catalog\n * for programmatic fragment assembly.\n *\n * Each fragment is `as const satisfies SchemaObject` so its literal type\n * powers the dispatch in {@link enrich} — passing wrong-family options\n * fails at compile time.\n */\n\n// ---------------------------------------------------------------------------\n// Layer 1 — Fragment catalog\n// ---------------------------------------------------------------------------\n\n// String formats (RFC-defined)\nexport const dateTimeFragment = {\n type: 'string',\n format: 'date-time',\n} as const satisfies SchemaObject;\nexport const dateFragment = { type: 'string', format: 'date' } as const satisfies SchemaObject;\nexport const timeFragment = { type: 'string', format: 'time' } as const satisfies SchemaObject;\nexport const uuidFragment = { type: 'string', format: 'uuid' } as const satisfies SchemaObject;\nexport const emailFragment = { type: 'string', format: 'email' } as const satisfies SchemaObject;\nexport const uriFragment = { type: 'string', format: 'uri' } as const satisfies SchemaObject;\nexport const hostnameFragment = {\n type: 'string',\n format: 'hostname',\n} as const satisfies SchemaObject;\nexport const ipv4Fragment = { type: 'string', format: 'ipv4' } as const satisfies SchemaObject;\nexport const ipv6Fragment = { type: 'string', format: 'ipv6' } as const satisfies SchemaObject;\n\n// Binary / encoded payloads\nexport const binaryFragment = { type: 'string', format: 'binary' } as const satisfies SchemaObject;\nexport const byteFragment = { type: 'string', format: 'byte' } as const satisfies SchemaObject;\n\n// Numeric formats (OpenAPI 3.1)\nexport const int32Fragment = { type: 'integer', format: 'int32' } as const satisfies SchemaObject;\nexport const int64Fragment = { type: 'integer', format: 'int64' } as const satisfies SchemaObject;\nexport const floatFragment = { type: 'number', format: 'float' } as const satisfies SchemaObject;\nexport const doubleFragment = { type: 'number', format: 'double' } as const satisfies SchemaObject;\n\n// Object passthrough\nexport const opaqueFragment = {\n type: 'object',\n additionalProperties: true,\n} as const satisfies SchemaObject;\n\n// ---------------------------------------------------------------------------\n// Layer 2 — Per-family option types\n// ---------------------------------------------------------------------------\n\nexport interface StringFormatOptions {\n description?: string;\n examples?: string[];\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n}\n\nexport interface BinaryFragmentOptions {\n description?: string;\n contentMediaType?: string;\n contentEncoding?: string;\n}\n\nexport interface NumberFormatOptions {\n description?: string;\n examples?: number[];\n minimum?: number;\n maximum?: number;\n exclusiveMinimum?: number;\n exclusiveMaximum?: number;\n multipleOf?: number;\n}\n\nexport interface OpaqueFragmentOptions {\n description?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Layer 3 — Type-strict generic enrich\n// ---------------------------------------------------------------------------\n\n// `binary` discriminates before the generic string-format branch because its\n// option set diverges (contentMediaType / contentEncoding instead of length\n// constraints). Order matters here.\ntype OptionsFor<T> = T extends { readonly format: 'binary' }\n ? BinaryFragmentOptions\n : T extends {\n readonly format:\n | 'date-time'\n | 'date'\n | 'time'\n | 'uuid'\n | 'email'\n | 'uri'\n | 'hostname'\n | 'ipv4'\n | 'ipv6'\n | 'byte';\n }\n ? StringFormatOptions\n : T extends { readonly format: 'int32' | 'int64' | 'float' | 'double' }\n ? NumberFormatOptions\n : T extends { readonly type: 'object'; readonly additionalProperties: true }\n ? OpaqueFragmentOptions\n : never;\n\n/**\n * Merge a catalog fragment with extras whose shape is dictated by the base\n * fragment's family. Passing wrong-family extras (e.g. a `contentMediaType`\n * onto `uuidFragment`) is a compile-time error.\n *\n * Returns a fresh `SchemaObject` — the original fragment is never mutated.\n */\nexport const enrich = <T extends SchemaObject>(base: T, extras: OptionsFor<T>): SchemaObject => ({\n ...base,\n ...extras,\n});\n\n// ---------------------------------------------------------------------------\n// Layer 3b — Sugar functions\n// ---------------------------------------------------------------------------\n\n/**\n * Binary-content fragment with typed enrichment. Sugar for\n * `enrich(binaryFragment, opts)` — exists because the `binary` option set\n * (`contentMediaType` / `contentEncoding`) is nuanced enough to deserve a\n * dedicated entry point and discoverable via auto-complete.\n *\n * @example\n * overrideJSONSchema(z.instanceof(File), binary());\n * overrideJSONSchema(z.instanceof(File), binary({ contentMediaType: 'application/pdf' }));\n */\nexport const binary = (opts?: BinaryFragmentOptions): SchemaObject => ({\n ...binaryFragment,\n ...opts,\n});\n\n/**\n * Opaque-object fragment with typed enrichment. Sugar for\n * `enrich(opaqueFragment, opts)` — exists for parity with {@link binary}\n * and because opaque passthrough payloads commonly carry a description\n * explaining why the API doesn't introspect them.\n *\n * @example\n * overrideJSONSchema(z.unknown(), opaque({ description: 'JWT passthrough' }));\n */\nexport const opaque = (opts?: OpaqueFragmentOptions): SchemaObject => ({\n ...opaqueFragment,\n ...opts,\n});\n","import type { z } from 'zod';\nimport type { $ZodType } from 'zod/v4/core';\nimport type { SchemaObject } from './openapi.types.js';\nimport type { Override } from './override.js';\n\n/**\n * Argument shape for {@link overrideJSONSchema}. Two forms:\n *\n * - A raw `SchemaObject` — applied to both input and output emission.\n * - A `{ input?, output? }` wrapper — distinct fragments per emission side,\n * for coercion shapes where input and output diverge (e.g.\n * `z.union([z.array(item), item.transform((v) => [v])])` accepts\n * `T | T[]` on input but always emits `T[]` on output).\n *\n * The wrapper form is detected by the presence of an `input` or `output`\n * key. Neither is a JSON Schema / OpenAPI 3.1 keyword, so the discriminator\n * is unambiguous in practice.\n */\nexport type OverrideJSONSchemaArg = SchemaObject | { input?: SchemaObject; output?: SchemaObject };\n\nexport interface StoredFragments {\n input?: SchemaObject;\n output?: SchemaObject;\n /**\n * Description captured from the Zod schema at `overrideJSONSchema(...)` call\n * time (`.describe(...)` / `.meta({ description })` both write to\n * `z.globalRegistry`). Applied as a fallback at emission time when the\n * per-direction fragment doesn't supply its own `description`. Fragment-\n * supplied descriptions still win.\n */\n description?: string;\n}\n\n/**\n * Per-instance JSON Schema registration store. Keyed by the Zod core type\n * (`$ZodType`) because that's what the override sees on `ctx.zodSchema`;\n * `z.ZodType` widens to `$ZodType` without a cast at the public API boundary.\n * Same WeakMap pattern as `composition.ts`'s `lineageMap`\n * (CLAUDE.md: \"transient, per-instance → WeakMap\").\n *\n * Value holds the per-direction fragments separately so the override factory\n * can pick the right one without surfacing `io` on `OverrideContext`.\n */\nconst customOverrideMap = new WeakMap<$ZodType, StoredFragments>();\n\nconst isWrapper = (\n arg: OverrideJSONSchemaArg,\n): arg is { input?: SchemaObject; output?: SchemaObject } => 'input' in arg || 'output' in arg;\n\n/**\n * Register a fixed JSON Schema fragment for a specific Zod schema instance.\n *\n * Designed for shapes JSON Schema can't model directly — `z.custom<T>()` and\n * `z.instanceof(...)` (e.g. multipart `File` fields) — which Zod emits as `{}`,\n * tripping `ZodNestUnrepresentableError` in strict mode. Also useful for\n * coercion shapes where input and output diverge (`singleOrArray`-style\n * helpers).\n *\n * Two call shapes:\n *\n * ```ts\n * // 1. Single fragment — applied verbatim to both input and output emission.\n * overrideJSONSchema(FileSchema, { type: 'string', format: 'binary' });\n *\n * // 2. Divergent fragments — separate fragments per emission side. Omit a\n * // side to leave Zod's default emission untouched on that side.\n * overrideJSONSchema(arrayOrItem, {\n * input: { anyOf: [arrFrag, itemFrag] },\n * output: arrFrag,\n * });\n * ```\n *\n * Idempotent: subsequent calls for the same schema overwrite the prior\n * registration (last-write-wins).\n */\nexport const overrideJSONSchema = <T extends z.ZodType>(\n schema: T,\n arg: OverrideJSONSchemaArg,\n): T => {\n const overrideSchema: StoredFragments = isWrapper(arg) ? { ...arg } : { input: arg, output: arg };\n\n const schemaDescription = schema.description;\n if (typeof schemaDescription === 'string') {\n overrideSchema.description = schemaDescription;\n }\n\n customOverrideMap.set(schema, overrideSchema);\n\n return schema;\n};\n\n/**\n * Read-only lookup into the registration store. Used by the engine to detect\n * when a pipe-typed schema covers its inner descent target with a relevant-io\n * fragment — see `buildToJsonSchemaOptions` in `engine.ts`. Returning a\n * possibly-`undefined` `StoredFragments` keeps the engine ignorant of the\n * underlying WeakMap.\n */\nexport const peekRegistration = (schema: $ZodType): StoredFragments | undefined =>\n customOverrideMap.get(schema);\n\n/**\n * Internal override factory consulted by the engine. Closes over the current\n * emission direction so the lookup can pick the right registered fragment\n * without surfacing `io` on the `OverrideContext` public contract. Mirrors\n * `createCompositionOverride` at `engine.ts:98`.\n *\n * Mutates `ctx.jsonSchema` in-place (clears existing keys, then assigns the\n * fragment) because Zod's override pipeline doesn't propagate\n * `ctx.jsonSchema = newObj` reassignments — only mutations on the existing\n * object reach the caller (see `composition.ts` for the same constraint).\n *\n * Falls back to the schema's captured `description` (from `.describe(...)` /\n * `.meta({ description })`) when the per-direction fragment doesn't supply\n * one. Captured at `overrideJSONSchema(...)` call time so the inheritance\n * doesn't depend on Zod's emission-time metadata pass. `title` is\n * deliberately not inherited.\n *\n * No-ops if the schema isn't registered, or if the registered record has no\n * fragment for the current `io` direction.\n */\nexport const createCustomOverride = (io: 'input' | 'output'): Override => {\n return ({ zodSchema, jsonSchema }) => {\n const record = customOverrideMap.get(zodSchema);\n if (record === undefined) {\n return;\n }\n const fragment = record[io];\n if (fragment === undefined) {\n return;\n }\n for (const key of Object.keys(jsonSchema)) {\n Reflect.deleteProperty(jsonSchema, key);\n }\n Object.assign(jsonSchema, fragment);\n if (fragment.description === undefined && record.description !== undefined) {\n jsonSchema.description = record.description;\n }\n };\n};\n","import { z } from 'zod';\n\nimport { overrideJSONSchema } from '../schema/custom-override.js';\nimport { binaryFragment } from './fragments.js';\n\n/**\n * Pre-registered Zod schemas for the common binary runtime types. Each\n * schema is wired through `overrideJSONSchema` so it emits `binaryFragment`\n * verbatim in OpenAPI — drop into a DTO without further setup.\n *\n * Node 22+ provides `File`, `Blob`, and `Buffer` as globals (zod-nest's\n * `engines.node >=22`), so `z.instanceof(...)` at module load is safe.\n *\n * @example\n * import { FileSchema } from 'zod-nest/helpers';\n *\n * class UploadDto extends createZodDto(\n * z.object({ file: FileSchema }),\n * ) {}\n */\n\nexport const FileSchema = overrideJSONSchema(z.instanceof(File), binaryFragment);\n\nexport const BlobSchema = overrideJSONSchema(z.instanceof(Blob), binaryFragment);\n\nexport const BufferSchema = overrideJSONSchema(z.instanceof(Buffer), binaryFragment);\n"]}
@@ -0,0 +1,109 @@
1
+ import { z } from 'zod';
2
+
3
+ var __defProp = Object.defineProperty;
4
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
5
+
6
+ // src/helpers/fragments.ts
7
+ var dateTimeFragment = {
8
+ type: "string",
9
+ format: "date-time"
10
+ };
11
+ var dateFragment = {
12
+ type: "string",
13
+ format: "date"
14
+ };
15
+ var timeFragment = {
16
+ type: "string",
17
+ format: "time"
18
+ };
19
+ var uuidFragment = {
20
+ type: "string",
21
+ format: "uuid"
22
+ };
23
+ var emailFragment = {
24
+ type: "string",
25
+ format: "email"
26
+ };
27
+ var uriFragment = {
28
+ type: "string",
29
+ format: "uri"
30
+ };
31
+ var hostnameFragment = {
32
+ type: "string",
33
+ format: "hostname"
34
+ };
35
+ var ipv4Fragment = {
36
+ type: "string",
37
+ format: "ipv4"
38
+ };
39
+ var ipv6Fragment = {
40
+ type: "string",
41
+ format: "ipv6"
42
+ };
43
+ var binaryFragment = {
44
+ type: "string",
45
+ format: "binary"
46
+ };
47
+ var byteFragment = {
48
+ type: "string",
49
+ format: "byte"
50
+ };
51
+ var int32Fragment = {
52
+ type: "integer",
53
+ format: "int32"
54
+ };
55
+ var int64Fragment = {
56
+ type: "integer",
57
+ format: "int64"
58
+ };
59
+ var floatFragment = {
60
+ type: "number",
61
+ format: "float"
62
+ };
63
+ var doubleFragment = {
64
+ type: "number",
65
+ format: "double"
66
+ };
67
+ var opaqueFragment = {
68
+ type: "object",
69
+ additionalProperties: true
70
+ };
71
+ var enrich = /* @__PURE__ */ __name((base, extras) => ({
72
+ ...base,
73
+ ...extras
74
+ }), "enrich");
75
+ var binary = /* @__PURE__ */ __name((opts) => ({
76
+ ...binaryFragment,
77
+ ...opts
78
+ }), "binary");
79
+ var opaque = /* @__PURE__ */ __name((opts) => ({
80
+ ...opaqueFragment,
81
+ ...opts
82
+ }), "opaque");
83
+
84
+ // src/schema/custom-override.ts
85
+ var customOverrideMap = /* @__PURE__ */ new WeakMap();
86
+ var isWrapper = /* @__PURE__ */ __name((arg) => "input" in arg || "output" in arg, "isWrapper");
87
+ var overrideJSONSchema = /* @__PURE__ */ __name((schema, arg) => {
88
+ const overrideSchema = isWrapper(arg) ? {
89
+ ...arg
90
+ } : {
91
+ input: arg,
92
+ output: arg
93
+ };
94
+ const schemaDescription = schema.description;
95
+ if (typeof schemaDescription === "string") {
96
+ overrideSchema.description = schemaDescription;
97
+ }
98
+ customOverrideMap.set(schema, overrideSchema);
99
+ return schema;
100
+ }, "overrideJSONSchema");
101
+
102
+ // src/helpers/presets.ts
103
+ var FileSchema = overrideJSONSchema(z.instanceof(File), binaryFragment);
104
+ var BlobSchema = overrideJSONSchema(z.instanceof(Blob), binaryFragment);
105
+ var BufferSchema = overrideJSONSchema(z.instanceof(Buffer), binaryFragment);
106
+
107
+ export { BlobSchema, BufferSchema, FileSchema, binary, binaryFragment, byteFragment, dateFragment, dateTimeFragment, doubleFragment, emailFragment, enrich, floatFragment, hostnameFragment, int32Fragment, int64Fragment, ipv4Fragment, ipv6Fragment, opaque, opaqueFragment, timeFragment, uriFragment, uuidFragment };
108
+ //# sourceMappingURL=index.mjs.map
109
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/helpers/fragments.ts","../../src/schema/custom-override.ts","../../src/helpers/presets.ts"],"names":["dateTimeFragment","type","format","dateFragment","timeFragment","uuidFragment","emailFragment","uriFragment","hostnameFragment","ipv4Fragment","ipv6Fragment","binaryFragment","byteFragment","int32Fragment","int64Fragment","floatFragment","doubleFragment","opaqueFragment","additionalProperties","enrich","base","extras","binary","opts","opaque","customOverrideMap","WeakMap","isWrapper","arg","overrideJSONSchema","schema","overrideSchema","input","output","schemaDescription","description","set","FileSchema","z","instanceof","File","BlobSchema","Blob","BufferSchema","Buffer"],"mappings":"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","file":"index.mjs","sourcesContent":["import type { SchemaObject } from '../schema/openapi.types.js';\n\n/**\n * Common JSON Schema fragment catalog — reusable building blocks for assembling\n * fragments by hand: alongside `z.custom<T>()`, in `overrideJSONSchema` calls,\n * in custom override callbacks, in tests that build expected fragments.\n *\n * The catalog overlaps with what Zod constructs already emit (`z.uuid()` →\n * `uuidFragment` shape, `z.email()` → `emailFragment` shape, etc.) — the\n * helpers don't *replace* those Zod constructs; they're a parallel catalog\n * for programmatic fragment assembly.\n *\n * Each fragment is `as const satisfies SchemaObject` so its literal type\n * powers the dispatch in {@link enrich} — passing wrong-family options\n * fails at compile time.\n */\n\n// ---------------------------------------------------------------------------\n// Layer 1 — Fragment catalog\n// ---------------------------------------------------------------------------\n\n// String formats (RFC-defined)\nexport const dateTimeFragment = {\n type: 'string',\n format: 'date-time',\n} as const satisfies SchemaObject;\nexport const dateFragment = { type: 'string', format: 'date' } as const satisfies SchemaObject;\nexport const timeFragment = { type: 'string', format: 'time' } as const satisfies SchemaObject;\nexport const uuidFragment = { type: 'string', format: 'uuid' } as const satisfies SchemaObject;\nexport const emailFragment = { type: 'string', format: 'email' } as const satisfies SchemaObject;\nexport const uriFragment = { type: 'string', format: 'uri' } as const satisfies SchemaObject;\nexport const hostnameFragment = {\n type: 'string',\n format: 'hostname',\n} as const satisfies SchemaObject;\nexport const ipv4Fragment = { type: 'string', format: 'ipv4' } as const satisfies SchemaObject;\nexport const ipv6Fragment = { type: 'string', format: 'ipv6' } as const satisfies SchemaObject;\n\n// Binary / encoded payloads\nexport const binaryFragment = { type: 'string', format: 'binary' } as const satisfies SchemaObject;\nexport const byteFragment = { type: 'string', format: 'byte' } as const satisfies SchemaObject;\n\n// Numeric formats (OpenAPI 3.1)\nexport const int32Fragment = { type: 'integer', format: 'int32' } as const satisfies SchemaObject;\nexport const int64Fragment = { type: 'integer', format: 'int64' } as const satisfies SchemaObject;\nexport const floatFragment = { type: 'number', format: 'float' } as const satisfies SchemaObject;\nexport const doubleFragment = { type: 'number', format: 'double' } as const satisfies SchemaObject;\n\n// Object passthrough\nexport const opaqueFragment = {\n type: 'object',\n additionalProperties: true,\n} as const satisfies SchemaObject;\n\n// ---------------------------------------------------------------------------\n// Layer 2 — Per-family option types\n// ---------------------------------------------------------------------------\n\nexport interface StringFormatOptions {\n description?: string;\n examples?: string[];\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n}\n\nexport interface BinaryFragmentOptions {\n description?: string;\n contentMediaType?: string;\n contentEncoding?: string;\n}\n\nexport interface NumberFormatOptions {\n description?: string;\n examples?: number[];\n minimum?: number;\n maximum?: number;\n exclusiveMinimum?: number;\n exclusiveMaximum?: number;\n multipleOf?: number;\n}\n\nexport interface OpaqueFragmentOptions {\n description?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Layer 3 — Type-strict generic enrich\n// ---------------------------------------------------------------------------\n\n// `binary` discriminates before the generic string-format branch because its\n// option set diverges (contentMediaType / contentEncoding instead of length\n// constraints). Order matters here.\ntype OptionsFor<T> = T extends { readonly format: 'binary' }\n ? BinaryFragmentOptions\n : T extends {\n readonly format:\n | 'date-time'\n | 'date'\n | 'time'\n | 'uuid'\n | 'email'\n | 'uri'\n | 'hostname'\n | 'ipv4'\n | 'ipv6'\n | 'byte';\n }\n ? StringFormatOptions\n : T extends { readonly format: 'int32' | 'int64' | 'float' | 'double' }\n ? NumberFormatOptions\n : T extends { readonly type: 'object'; readonly additionalProperties: true }\n ? OpaqueFragmentOptions\n : never;\n\n/**\n * Merge a catalog fragment with extras whose shape is dictated by the base\n * fragment's family. Passing wrong-family extras (e.g. a `contentMediaType`\n * onto `uuidFragment`) is a compile-time error.\n *\n * Returns a fresh `SchemaObject` — the original fragment is never mutated.\n */\nexport const enrich = <T extends SchemaObject>(base: T, extras: OptionsFor<T>): SchemaObject => ({\n ...base,\n ...extras,\n});\n\n// ---------------------------------------------------------------------------\n// Layer 3b — Sugar functions\n// ---------------------------------------------------------------------------\n\n/**\n * Binary-content fragment with typed enrichment. Sugar for\n * `enrich(binaryFragment, opts)` — exists because the `binary` option set\n * (`contentMediaType` / `contentEncoding`) is nuanced enough to deserve a\n * dedicated entry point and discoverable via auto-complete.\n *\n * @example\n * overrideJSONSchema(z.instanceof(File), binary());\n * overrideJSONSchema(z.instanceof(File), binary({ contentMediaType: 'application/pdf' }));\n */\nexport const binary = (opts?: BinaryFragmentOptions): SchemaObject => ({\n ...binaryFragment,\n ...opts,\n});\n\n/**\n * Opaque-object fragment with typed enrichment. Sugar for\n * `enrich(opaqueFragment, opts)` — exists for parity with {@link binary}\n * and because opaque passthrough payloads commonly carry a description\n * explaining why the API doesn't introspect them.\n *\n * @example\n * overrideJSONSchema(z.unknown(), opaque({ description: 'JWT passthrough' }));\n */\nexport const opaque = (opts?: OpaqueFragmentOptions): SchemaObject => ({\n ...opaqueFragment,\n ...opts,\n});\n","import type { z } from 'zod';\nimport type { $ZodType } from 'zod/v4/core';\nimport type { SchemaObject } from './openapi.types.js';\nimport type { Override } from './override.js';\n\n/**\n * Argument shape for {@link overrideJSONSchema}. Two forms:\n *\n * - A raw `SchemaObject` — applied to both input and output emission.\n * - A `{ input?, output? }` wrapper — distinct fragments per emission side,\n * for coercion shapes where input and output diverge (e.g.\n * `z.union([z.array(item), item.transform((v) => [v])])` accepts\n * `T | T[]` on input but always emits `T[]` on output).\n *\n * The wrapper form is detected by the presence of an `input` or `output`\n * key. Neither is a JSON Schema / OpenAPI 3.1 keyword, so the discriminator\n * is unambiguous in practice.\n */\nexport type OverrideJSONSchemaArg = SchemaObject | { input?: SchemaObject; output?: SchemaObject };\n\nexport interface StoredFragments {\n input?: SchemaObject;\n output?: SchemaObject;\n /**\n * Description captured from the Zod schema at `overrideJSONSchema(...)` call\n * time (`.describe(...)` / `.meta({ description })` both write to\n * `z.globalRegistry`). Applied as a fallback at emission time when the\n * per-direction fragment doesn't supply its own `description`. Fragment-\n * supplied descriptions still win.\n */\n description?: string;\n}\n\n/**\n * Per-instance JSON Schema registration store. Keyed by the Zod core type\n * (`$ZodType`) because that's what the override sees on `ctx.zodSchema`;\n * `z.ZodType` widens to `$ZodType` without a cast at the public API boundary.\n * Same WeakMap pattern as `composition.ts`'s `lineageMap`\n * (CLAUDE.md: \"transient, per-instance → WeakMap\").\n *\n * Value holds the per-direction fragments separately so the override factory\n * can pick the right one without surfacing `io` on `OverrideContext`.\n */\nconst customOverrideMap = new WeakMap<$ZodType, StoredFragments>();\n\nconst isWrapper = (\n arg: OverrideJSONSchemaArg,\n): arg is { input?: SchemaObject; output?: SchemaObject } => 'input' in arg || 'output' in arg;\n\n/**\n * Register a fixed JSON Schema fragment for a specific Zod schema instance.\n *\n * Designed for shapes JSON Schema can't model directly — `z.custom<T>()` and\n * `z.instanceof(...)` (e.g. multipart `File` fields) — which Zod emits as `{}`,\n * tripping `ZodNestUnrepresentableError` in strict mode. Also useful for\n * coercion shapes where input and output diverge (`singleOrArray`-style\n * helpers).\n *\n * Two call shapes:\n *\n * ```ts\n * // 1. Single fragment — applied verbatim to both input and output emission.\n * overrideJSONSchema(FileSchema, { type: 'string', format: 'binary' });\n *\n * // 2. Divergent fragments — separate fragments per emission side. Omit a\n * // side to leave Zod's default emission untouched on that side.\n * overrideJSONSchema(arrayOrItem, {\n * input: { anyOf: [arrFrag, itemFrag] },\n * output: arrFrag,\n * });\n * ```\n *\n * Idempotent: subsequent calls for the same schema overwrite the prior\n * registration (last-write-wins).\n */\nexport const overrideJSONSchema = <T extends z.ZodType>(\n schema: T,\n arg: OverrideJSONSchemaArg,\n): T => {\n const overrideSchema: StoredFragments = isWrapper(arg) ? { ...arg } : { input: arg, output: arg };\n\n const schemaDescription = schema.description;\n if (typeof schemaDescription === 'string') {\n overrideSchema.description = schemaDescription;\n }\n\n customOverrideMap.set(schema, overrideSchema);\n\n return schema;\n};\n\n/**\n * Read-only lookup into the registration store. Used by the engine to detect\n * when a pipe-typed schema covers its inner descent target with a relevant-io\n * fragment — see `buildToJsonSchemaOptions` in `engine.ts`. Returning a\n * possibly-`undefined` `StoredFragments` keeps the engine ignorant of the\n * underlying WeakMap.\n */\nexport const peekRegistration = (schema: $ZodType): StoredFragments | undefined =>\n customOverrideMap.get(schema);\n\n/**\n * Internal override factory consulted by the engine. Closes over the current\n * emission direction so the lookup can pick the right registered fragment\n * without surfacing `io` on the `OverrideContext` public contract. Mirrors\n * `createCompositionOverride` at `engine.ts:98`.\n *\n * Mutates `ctx.jsonSchema` in-place (clears existing keys, then assigns the\n * fragment) because Zod's override pipeline doesn't propagate\n * `ctx.jsonSchema = newObj` reassignments — only mutations on the existing\n * object reach the caller (see `composition.ts` for the same constraint).\n *\n * Falls back to the schema's captured `description` (from `.describe(...)` /\n * `.meta({ description })`) when the per-direction fragment doesn't supply\n * one. Captured at `overrideJSONSchema(...)` call time so the inheritance\n * doesn't depend on Zod's emission-time metadata pass. `title` is\n * deliberately not inherited.\n *\n * No-ops if the schema isn't registered, or if the registered record has no\n * fragment for the current `io` direction.\n */\nexport const createCustomOverride = (io: 'input' | 'output'): Override => {\n return ({ zodSchema, jsonSchema }) => {\n const record = customOverrideMap.get(zodSchema);\n if (record === undefined) {\n return;\n }\n const fragment = record[io];\n if (fragment === undefined) {\n return;\n }\n for (const key of Object.keys(jsonSchema)) {\n Reflect.deleteProperty(jsonSchema, key);\n }\n Object.assign(jsonSchema, fragment);\n if (fragment.description === undefined && record.description !== undefined) {\n jsonSchema.description = record.description;\n }\n };\n};\n","import { z } from 'zod';\n\nimport { overrideJSONSchema } from '../schema/custom-override.js';\nimport { binaryFragment } from './fragments.js';\n\n/**\n * Pre-registered Zod schemas for the common binary runtime types. Each\n * schema is wired through `overrideJSONSchema` so it emits `binaryFragment`\n * verbatim in OpenAPI — drop into a DTO without further setup.\n *\n * Node 22+ provides `File`, `Blob`, and `Buffer` as globals (zod-nest's\n * `engines.node >=22`), so `z.instanceof(...)` at module load is safe.\n *\n * @example\n * import { FileSchema } from 'zod-nest/helpers';\n *\n * class UploadDto extends createZodDto(\n * z.object({ file: FileSchema }),\n * ) {}\n */\n\nexport const FileSchema = overrideJSONSchema(z.instanceof(File), binaryFragment);\n\nexport const BlobSchema = overrideJSONSchema(z.instanceof(Blob), binaryFragment);\n\nexport const BufferSchema = overrideJSONSchema(z.instanceof(Buffer), binaryFragment);\n"]}