@bram-dc/fastify-type-provider-zod 5.0.3 → 7.0.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.
Files changed (41) hide show
  1. package/README.md +34 -4
  2. package/dist/cjs/core.cjs +33 -45
  3. package/dist/cjs/core.cjs.map +1 -1
  4. package/dist/cjs/core.d.cts +11 -12
  5. package/dist/cjs/errors.cjs +1 -1
  6. package/dist/cjs/errors.cjs.map +1 -1
  7. package/dist/cjs/registry.cjs +43 -0
  8. package/dist/cjs/registry.cjs.map +1 -0
  9. package/dist/cjs/registry.d.cts +9 -0
  10. package/dist/cjs/utils.cjs +21 -0
  11. package/dist/cjs/utils.cjs.map +1 -0
  12. package/dist/cjs/utils.d.cts +12 -0
  13. package/dist/cjs/zod-to-json.cjs +36 -41
  14. package/dist/cjs/zod-to-json.cjs.map +1 -1
  15. package/dist/cjs/zod-to-json.d.cts +7 -7
  16. package/dist/esm/core.d.ts +11 -12
  17. package/dist/esm/core.js +34 -46
  18. package/dist/esm/core.js.map +1 -1
  19. package/dist/esm/errors.js +1 -1
  20. package/dist/esm/errors.js.map +1 -1
  21. package/dist/esm/registry.d.ts +9 -0
  22. package/dist/esm/registry.js +43 -0
  23. package/dist/esm/registry.js.map +1 -0
  24. package/dist/esm/utils.d.ts +12 -0
  25. package/dist/esm/utils.js +21 -0
  26. package/dist/esm/utils.js.map +1 -0
  27. package/dist/esm/zod-to-json.d.ts +7 -7
  28. package/dist/esm/zod-to-json.js +36 -41
  29. package/dist/esm/zod-to-json.js.map +1 -1
  30. package/package.json +13 -11
  31. package/src/core.ts +44 -60
  32. package/src/registry.ts +64 -0
  33. package/src/utils.ts +33 -0
  34. package/src/zod-to-json.ts +62 -52
  35. package/dist/cjs/json-to-oas.cjs +0 -85
  36. package/dist/cjs/json-to-oas.cjs.map +0 -1
  37. package/dist/cjs/json-to-oas.d.cts +0 -9
  38. package/dist/esm/json-to-oas.d.ts +0 -9
  39. package/dist/esm/json-to-oas.js +0 -85
  40. package/dist/esm/json-to-oas.js.map +0 -1
  41. package/src/json-to-oas.ts +0 -109
package/README.md CHANGED
@@ -6,10 +6,18 @@
6
6
 
7
7
  ## Zod compatibility
8
8
 
9
- | fastify-type-provider-zod | zod |
10
- |---------------------------|------|
11
- | <=4.x | v3 |
12
- | >=5.x | v4 |
9
+ | fastify-type-provider-zod | zod |
10
+ |---------------------------|-------|
11
+ | <=4.x | v3 |
12
+ | >=5.x <7.x | v4 |
13
+ | >=7.x | v4.2+ |
14
+
15
+ > **Important (v7+)**
16
+ >
17
+ > Starting from **v7**, this library uses Zod’s `.encode()` / `.decode()` APIs introduced in **Zod 4.3**.
18
+ > Because of this change, **response serialization is now based on `z.output<T>` instead of `z.input<T>`**.
19
+ >
20
+ > This means Fastify serializers always expect the **post-transformation output type** of your Zod schemas.
13
21
 
14
22
  ## How to use?
15
23
 
@@ -285,3 +293,25 @@ const plugin: FastifyPluginAsyncZod = async function (fastify, _opts) {
285
293
  });
286
294
  };
287
295
  ```
296
+
297
+ ## How to specify different OpenAPI targets
298
+
299
+ You can specify different JSON Schema targets for OpenAPI compatibility using the `createJsonSchemaTransform` function with the `zodToJsonConfig.target` option.
300
+
301
+ By default target "openapi-3.0" is used for documents with "openapi" field set to "3.0.x", and target "draft-2020-12" is used for documents with "openapi" field set to "3.1.x".
302
+
303
+ ### Usage
304
+
305
+ ```typescript
306
+ import { createJsonSchemaTransform } from "fastify-type-provider-zod";
307
+
308
+ // For OpenAPI 3.0.x compatibility
309
+ const transform = createJsonSchemaTransform({
310
+ zodToJsonConfig: { target: "openapi-3.0" },
311
+ });
312
+
313
+ // For OpenAPI 3.1+
314
+ const transform = createJsonSchemaTransform({
315
+ zodToJsonConfig: { target: "draft-2020-12" },
316
+ });
317
+ ```
package/dist/cjs/core.cjs CHANGED
@@ -2,7 +2,8 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const core = require("zod/v4/core");
4
4
  const errors = require("./errors.cjs");
5
- const jsonToOas = require("./json-to-oas.cjs");
5
+ const registry = require("./registry.cjs");
6
+ const utils = require("./utils.cjs");
6
7
  const zodToJson = require("./zod-to-json.cjs");
7
8
  const defaultSkipList = [
8
9
  "/documentation/",
@@ -15,19 +16,24 @@ const defaultSkipList = [
15
16
  ];
16
17
  const createJsonSchemaTransform = ({
17
18
  skipList = defaultSkipList,
18
- schemaRegistry = core.globalRegistry
19
+ schemaRegistry = core.globalRegistry,
20
+ zodToJsonConfig = {}
19
21
  }) => {
20
- return (input) => {
21
- if ("swaggerObject" in input) {
22
- throw new Error("OpenAPI 2.0 is not supported");
23
- }
24
- const { schema, url } = input;
22
+ return (document) => {
23
+ utils.assertIsOpenAPIObject(document);
24
+ const { schema, url } = document;
25
25
  if (!schema) {
26
26
  return {
27
27
  schema,
28
28
  url
29
29
  };
30
30
  }
31
+ const target = utils.getJSONSchemaTarget(document.openapiObject.openapi);
32
+ const config = {
33
+ target,
34
+ ...zodToJsonConfig
35
+ };
36
+ const { inputRegistry, outputRegistry } = registry.generateIORegistries(schemaRegistry);
31
37
  const { response, headers, querystring, body, params, hide, ...rest } = schema;
32
38
  const transformed = {};
33
39
  if (skipList.includes(url) || hide) {
@@ -35,26 +41,17 @@ const createJsonSchemaTransform = ({
35
41
  return { schema: transformed, url };
36
42
  }
37
43
  const zodSchemas = { headers, querystring, body, params };
38
- const oasVersion = jsonToOas.getOASVersion(input);
39
44
  for (const prop in zodSchemas) {
40
45
  const zodSchema = zodSchemas[prop];
41
46
  if (zodSchema) {
42
- const jsonSchema = zodToJson.zodSchemaToJson(zodSchema, schemaRegistry, "input");
43
- const oasSchema = jsonToOas.jsonSchemaToOAS(jsonSchema, oasVersion);
44
- transformed[prop] = oasSchema;
47
+ transformed[prop] = zodToJson.zodSchemaToJson(zodSchema, inputRegistry, "input", config);
45
48
  }
46
49
  }
47
50
  if (response) {
48
51
  transformed.response = {};
49
52
  for (const prop in response) {
50
53
  const zodSchema = resolveSchema(response[prop]);
51
- const jsonSchema = zodToJson.zodSchemaToJson(zodSchema, schemaRegistry, "output");
52
- if (jsonSchema.type === "null") {
53
- transformed.response[prop] = jsonSchema;
54
- continue;
55
- }
56
- const oasSchema = jsonToOas.jsonSchemaToOAS(jsonSchema, oasVersion);
57
- transformed.response[prop] = oasSchema;
54
+ transformed.response[prop] = zodToJson.zodSchemaToJson(zodSchema, outputRegistry, "output", config);
58
55
  }
59
56
  }
60
57
  for (const prop in rest) {
@@ -68,42 +65,33 @@ const createJsonSchemaTransform = ({
68
65
  };
69
66
  const jsonSchemaTransform = createJsonSchemaTransform({});
70
67
  const createJsonSchemaTransformObject = ({
71
- schemaRegistry = core.globalRegistry
72
- }) => (input) => {
73
- if ("swaggerObject" in input) {
74
- throw new Error("OpenAPI 2.0 is not supported");
75
- }
76
- const oasVersion = jsonToOas.getOASVersion(input);
77
- const inputSchemas = zodToJson.zodRegistryToJson(schemaRegistry, "input");
78
- const outputSchemas = zodToJson.zodRegistryToJson(schemaRegistry, "output");
79
- for (const key in outputSchemas) {
80
- if (inputSchemas[key]) {
81
- throw new Error(
82
- `Collision detected for schema "${key}". The is already an input schema with the same name.`
83
- );
84
- }
85
- }
86
- const jsonSchemas = {
87
- ...inputSchemas,
88
- ...outputSchemas
68
+ schemaRegistry = core.globalRegistry,
69
+ zodToJsonConfig = {}
70
+ }) => (document) => {
71
+ utils.assertIsOpenAPIObject(document);
72
+ const target = utils.getJSONSchemaTarget(document.openapiObject.openapi);
73
+ const config = {
74
+ target,
75
+ ...zodToJsonConfig
89
76
  };
90
- const oasSchemas = Object.fromEntries(
91
- Object.entries(jsonSchemas).map(([key, value]) => [key, jsonToOas.jsonSchemaToOAS(value, oasVersion)])
92
- );
77
+ const { inputRegistry, outputRegistry } = registry.generateIORegistries(schemaRegistry);
78
+ const inputSchemas = zodToJson.zodRegistryToJson(inputRegistry, "input", config);
79
+ const outputSchemas = zodToJson.zodRegistryToJson(outputRegistry, "output", config);
93
80
  return {
94
- ...input.openapiObject,
81
+ ...document.openapiObject,
95
82
  components: {
96
- ...input.openapiObject.components,
83
+ ...document.openapiObject.components,
97
84
  schemas: {
98
- ...input.openapiObject.components?.schemas,
99
- ...oasSchemas
85
+ ...document.openapiObject.components?.schemas,
86
+ ...inputSchemas,
87
+ ...outputSchemas
100
88
  }
101
89
  }
102
90
  };
103
91
  };
104
92
  const jsonSchemaTransformObject = createJsonSchemaTransformObject({});
105
93
  const validatorCompiler = ({ schema }) => (data) => {
106
- const result = core.safeParse(schema, data);
94
+ const result = core.safeDecode(schema, data);
107
95
  if (result.error) {
108
96
  return { error: errors.createValidationError(result.error) };
109
97
  }
@@ -120,7 +108,7 @@ function resolveSchema(maybeSchema) {
120
108
  }
121
109
  const createSerializerCompiler = (options) => ({ schema: maybeSchema, method, url }) => (data) => {
122
110
  const schema = resolveSchema(maybeSchema);
123
- const result = core.safeParse(schema, data);
111
+ const result = core.safeEncode(schema, data);
124
112
  if (result.error) {
125
113
  throw new errors.ResponseSerializationError(method, url, { cause: result.error });
126
114
  }
@@ -1 +1 @@
1
- {"version":3,"file":"core.cjs","sources":["../../src/core.ts"],"sourcesContent":["import type { SwaggerTransform, SwaggerTransformObject } from '@fastify/swagger'\nimport type {\n FastifyPluginAsync,\n FastifyPluginCallback,\n FastifyPluginOptions,\n FastifySchema,\n FastifySchemaCompiler,\n FastifyTypeProvider,\n RawServerBase,\n RawServerDefault,\n} from 'fastify'\nimport type { FastifySerializerCompiler } from 'fastify/types/schema'\nimport type { $ZodRegistry, input, output } from 'zod/v4/core'\nimport { $ZodType, globalRegistry, safeParse } from 'zod/v4/core'\nimport { createValidationError, InvalidSchemaError, ResponseSerializationError } from './errors'\nimport { getOASVersion, jsonSchemaToOAS } from './json-to-oas'\nimport { zodRegistryToJson, zodSchemaToJson } from './zod-to-json'\n\ntype FreeformRecord = Record<string, any>\n\nconst defaultSkipList = [\n '/documentation/',\n '/documentation/initOAuth',\n '/documentation/json',\n '/documentation/uiConfig',\n '/documentation/yaml',\n '/documentation/*',\n '/documentation/static/*',\n]\n\nexport interface ZodTypeProvider extends FastifyTypeProvider {\n validator: this['schema'] extends $ZodType ? output<this['schema']> : unknown\n serializer: this['schema'] extends $ZodType ? input<this['schema']> : unknown\n}\n\ninterface Schema extends FastifySchema {\n hide?: boolean\n}\n\ntype CreateJsonSchemaTransformOptions = {\n skipList?: readonly string[]\n schemaRegistry?: $ZodRegistry<{ id?: string | undefined }>\n}\n\nexport const createJsonSchemaTransform = ({\n skipList = defaultSkipList,\n schemaRegistry = globalRegistry,\n}: CreateJsonSchemaTransformOptions): SwaggerTransform<Schema> => {\n return (input) => {\n if ('swaggerObject' in input) {\n throw new Error('OpenAPI 2.0 is not supported')\n }\n\n const { schema, url } = input\n\n if (!schema) {\n return {\n schema,\n url,\n }\n }\n\n const { response, headers, querystring, body, params, hide, ...rest } = schema\n\n const transformed: FreeformRecord = {}\n\n if (skipList.includes(url) || hide) {\n transformed.hide = true\n return { schema: transformed, url }\n }\n\n const zodSchemas: FreeformRecord = { headers, querystring, body, params }\n\n const oasVersion = getOASVersion(input)\n\n for (const prop in zodSchemas) {\n const zodSchema = zodSchemas[prop]\n if (zodSchema) {\n const jsonSchema = zodSchemaToJson(zodSchema, schemaRegistry, 'input')\n const oasSchema = jsonSchemaToOAS(jsonSchema, oasVersion)\n\n transformed[prop] = oasSchema\n }\n }\n\n if (response) {\n transformed.response = {}\n\n for (const prop in response as any) {\n const zodSchema = resolveSchema((response as any)[prop])\n const jsonSchema = zodSchemaToJson(zodSchema, schemaRegistry, 'output')\n\n // Check is the JSON schema is null then return as it is since fastify-swagger will handle it\n if (jsonSchema.type === 'null') {\n transformed.response[prop] = jsonSchema\n continue\n }\n\n const oasSchema = jsonSchemaToOAS(jsonSchema, oasVersion)\n\n transformed.response[prop] = oasSchema\n }\n }\n\n for (const prop in rest) {\n const meta = rest[prop as keyof typeof rest]\n if (meta) {\n transformed[prop] = meta\n }\n }\n\n return { schema: transformed, url }\n }\n}\n\nexport const jsonSchemaTransform: SwaggerTransform<Schema> = createJsonSchemaTransform({})\n\ntype CreateJsonSchemaTransformObjectOptions = {\n schemaRegistry?: $ZodRegistry<{ id?: string | undefined }>\n}\n\nexport const createJsonSchemaTransformObject =\n ({\n schemaRegistry = globalRegistry,\n }: CreateJsonSchemaTransformObjectOptions): SwaggerTransformObject =>\n (input) => {\n if ('swaggerObject' in input) {\n throw new Error('OpenAPI 2.0 is not supported')\n }\n\n const oasVersion = getOASVersion(input)\n\n const inputSchemas = zodRegistryToJson(schemaRegistry, 'input')\n const outputSchemas = zodRegistryToJson(schemaRegistry, 'output')\n\n for (const key in outputSchemas) {\n if (inputSchemas[key]) {\n throw new Error(\n `Collision detected for schema \"${key}\". The is already an input schema with the same name.`,\n )\n }\n }\n\n const jsonSchemas = {\n ...inputSchemas,\n ...outputSchemas,\n }\n\n const oasSchemas = Object.fromEntries(\n Object.entries(jsonSchemas).map(([key, value]) => [key, jsonSchemaToOAS(value, oasVersion)]),\n )\n\n return {\n ...input.openapiObject,\n components: {\n ...input.openapiObject.components,\n schemas: {\n ...input.openapiObject.components?.schemas,\n ...oasSchemas,\n },\n },\n } as ReturnType<SwaggerTransformObject>\n }\n\nexport const jsonSchemaTransformObject: SwaggerTransformObject = createJsonSchemaTransformObject({})\n\nexport const validatorCompiler: FastifySchemaCompiler<$ZodType> =\n ({ schema }) =>\n (data) => {\n const result = safeParse(schema, data)\n if (result.error) {\n return { error: createValidationError(result.error) as unknown as Error }\n }\n\n return { value: result.data }\n }\n\nfunction resolveSchema(maybeSchema: $ZodType | { properties: $ZodType }): $ZodType {\n if (maybeSchema instanceof $ZodType) {\n return maybeSchema\n }\n if ('properties' in maybeSchema && maybeSchema.properties instanceof $ZodType) {\n return maybeSchema.properties\n }\n throw new InvalidSchemaError(JSON.stringify(maybeSchema))\n}\n\ntype ReplacerFunction = (this: any, key: string, value: any) => any\n\nexport type ZodSerializerCompilerOptions = {\n replacer?: ReplacerFunction\n}\n\nexport const createSerializerCompiler =\n (\n options?: ZodSerializerCompilerOptions,\n ): FastifySerializerCompiler<$ZodType | { properties: $ZodType }> =>\n ({ schema: maybeSchema, method, url }) =>\n (data) => {\n const schema = resolveSchema(maybeSchema)\n\n const result = safeParse(schema, data)\n if (result.error) {\n throw new ResponseSerializationError(method, url, { cause: result.error })\n }\n\n return JSON.stringify(result.data, options?.replacer)\n }\n\nexport const serializerCompiler: ReturnType<typeof createSerializerCompiler> =\n createSerializerCompiler({})\n\n/**\n * FastifyPluginCallbackZod with Zod automatic type inference\n *\n * @example\n * ```typescript\n * import { FastifyPluginCallbackZod } from \"fastify-type-provider-zod\"\n *\n * const plugin: FastifyPluginCallbackZod = (fastify, options, done) => {\n * done()\n * }\n * ```\n */\nexport type FastifyPluginCallbackZod<\n Options extends FastifyPluginOptions = Record<never, never>,\n Server extends RawServerBase = RawServerDefault,\n> = FastifyPluginCallback<Options, Server, ZodTypeProvider>\n\n/**\n * FastifyPluginAsyncZod with Zod automatic type inference\n *\n * @example\n * ```typescript\n * import { FastifyPluginAsyncZod } from \"fastify-type-provider-zod\"\n *\n * const plugin: FastifyPluginAsyncZod = async (fastify, options) => {\n * }\n * ```\n */\nexport type FastifyPluginAsyncZod<\n Options extends FastifyPluginOptions = Record<never, never>,\n Server extends RawServerBase = RawServerDefault,\n> = FastifyPluginAsync<Options, Server, ZodTypeProvider>\n"],"names":["globalRegistry","getOASVersion","zodSchemaToJson","jsonSchemaToOAS","zodRegistryToJson","safeParse","createValidationError","$ZodType","InvalidSchemaError","ResponseSerializationError"],"mappings":";;;;;;AAoBA,MAAM,kBAAkB;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAgBO,MAAM,4BAA4B,CAAC;AAAA,EACxC,WAAW;AAAA,EACX,iBAAiBA,KAAAA;AACnB,MAAkE;AAChE,SAAO,CAAC,UAAU;AAChB,QAAI,mBAAmB,OAAO;AAC5B,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AAEA,UAAM,EAAE,QAAQ,IAAA,IAAQ;AAExB,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,QACL;AAAA,QACA;AAAA,MAAA;AAAA,IAEJ;AAEA,UAAM,EAAE,UAAU,SAAS,aAAa,MAAM,QAAQ,MAAM,GAAG,KAAA,IAAS;AAExE,UAAM,cAA8B,CAAA;AAEpC,QAAI,SAAS,SAAS,GAAG,KAAK,MAAM;AAClC,kBAAY,OAAO;AACnB,aAAO,EAAE,QAAQ,aAAa,IAAA;AAAA,IAChC;AAEA,UAAM,aAA6B,EAAE,SAAS,aAAa,MAAM,OAAA;AAEjE,UAAM,aAAaC,UAAAA,cAAc,KAAK;AAEtC,eAAW,QAAQ,YAAY;AAC7B,YAAM,YAAY,WAAW,IAAI;AACjC,UAAI,WAAW;AACb,cAAM,aAAaC,UAAAA,gBAAgB,WAAW,gBAAgB,OAAO;AACrE,cAAM,YAAYC,UAAAA,gBAAgB,YAAY,UAAU;AAExD,oBAAY,IAAI,IAAI;AAAA,MACtB;AAAA,IACF;AAEA,QAAI,UAAU;AACZ,kBAAY,WAAW,CAAA;AAEvB,iBAAW,QAAQ,UAAiB;AAClC,cAAM,YAAY,cAAe,SAAiB,IAAI,CAAC;AACvD,cAAM,aAAaD,UAAAA,gBAAgB,WAAW,gBAAgB,QAAQ;AAGtE,YAAI,WAAW,SAAS,QAAQ;AAC9B,sBAAY,SAAS,IAAI,IAAI;AAC7B;AAAA,QACF;AAEA,cAAM,YAAYC,UAAAA,gBAAgB,YAAY,UAAU;AAExD,oBAAY,SAAS,IAAI,IAAI;AAAA,MAC/B;AAAA,IACF;AAEA,eAAW,QAAQ,MAAM;AACvB,YAAM,OAAO,KAAK,IAAyB;AAC3C,UAAI,MAAM;AACR,oBAAY,IAAI,IAAI;AAAA,MACtB;AAAA,IACF;AAEA,WAAO,EAAE,QAAQ,aAAa,IAAA;AAAA,EAChC;AACF;AAEO,MAAM,sBAAgD,0BAA0B,CAAA,CAAE;AAMlF,MAAM,kCACX,CAAC;AAAA,EACC,iBAAiBH,KAAAA;AACnB,MACA,CAAC,UAAU;AACT,MAAI,mBAAmB,OAAO;AAC5B,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAChD;AAEA,QAAM,aAAaC,UAAAA,cAAc,KAAK;AAEtC,QAAM,eAAeG,UAAAA,kBAAkB,gBAAgB,OAAO;AAC9D,QAAM,gBAAgBA,UAAAA,kBAAkB,gBAAgB,QAAQ;AAEhE,aAAW,OAAO,eAAe;AAC/B,QAAI,aAAa,GAAG,GAAG;AACrB,YAAM,IAAI;AAAA,QACR,kCAAkC,GAAG;AAAA,MAAA;AAAA,IAEzC;AAAA,EACF;AAEA,QAAM,cAAc;AAAA,IAClB,GAAG;AAAA,IACH,GAAG;AAAA,EAAA;AAGL,QAAM,aAAa,OAAO;AAAA,IACxB,OAAO,QAAQ,WAAW,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,KAAKD,UAAAA,gBAAgB,OAAO,UAAU,CAAC,CAAC;AAAA,EAAA;AAG7F,SAAO;AAAA,IACL,GAAG,MAAM;AAAA,IACT,YAAY;AAAA,MACV,GAAG,MAAM,cAAc;AAAA,MACvB,SAAS;AAAA,QACP,GAAG,MAAM,cAAc,YAAY;AAAA,QACnC,GAAG;AAAA,MAAA;AAAA,IACL;AAAA,EACF;AAEJ;AAEK,MAAM,4BAAoD,gCAAgC,CAAA,CAAE;AAE5F,MAAM,oBACX,CAAC,EAAE,OAAA,MACH,CAAC,SAAS;AACR,QAAM,SAASE,KAAAA,UAAU,QAAQ,IAAI;AACrC,MAAI,OAAO,OAAO;AAChB,WAAO,EAAE,OAAOC,OAAAA,sBAAsB,OAAO,KAAK,EAAA;AAAA,EACpD;AAEA,SAAO,EAAE,OAAO,OAAO,KAAA;AACzB;AAEF,SAAS,cAAc,aAA4D;AACjF,MAAI,uBAAuBC,KAAAA,UAAU;AACnC,WAAO;AAAA,EACT;AACA,MAAI,gBAAgB,eAAe,YAAY,sBAAsBA,KAAAA,UAAU;AAC7E,WAAO,YAAY;AAAA,EACrB;AACA,QAAM,IAAIC,OAAAA,mBAAmB,KAAK,UAAU,WAAW,CAAC;AAC1D;AAQO,MAAM,2BACX,CACE,YAEF,CAAC,EAAE,QAAQ,aAAa,QAAQ,UAChC,CAAC,SAAS;AACR,QAAM,SAAS,cAAc,WAAW;AAExC,QAAM,SAASH,KAAAA,UAAU,QAAQ,IAAI;AACrC,MAAI,OAAO,OAAO;AAChB,UAAM,IAAII,OAAAA,2BAA2B,QAAQ,KAAK,EAAE,OAAO,OAAO,OAAO;AAAA,EAC3E;AAEA,SAAO,KAAK,UAAU,OAAO,MAAM,SAAS,QAAQ;AACtD;AAEK,MAAM,qBACX,yBAAyB,CAAA,CAAE;;;;;;;;"}
1
+ {"version":3,"file":"core.cjs","sources":["../../src/core.ts"],"sourcesContent":["import type { SwaggerTransform, SwaggerTransformObject } from '@fastify/swagger'\nimport type {\n FastifyPluginAsync,\n FastifyPluginCallback,\n FastifyPluginOptions,\n FastifySchema,\n FastifySchemaCompiler,\n FastifySerializerCompiler,\n FastifyTypeProvider,\n RawServerBase,\n RawServerDefault,\n} from 'fastify'\nimport type { $ZodRegistry, output } from 'zod/v4/core'\nimport { $ZodType, globalRegistry, safeDecode, safeEncode } from 'zod/v4/core'\nimport { createValidationError, InvalidSchemaError, ResponseSerializationError } from './errors'\nimport { generateIORegistries, type SchemaRegistryMeta } from './registry'\nimport { assertIsOpenAPIObject, getJSONSchemaTarget } from './utils'\nimport { type ZodToJsonConfig, zodRegistryToJson, zodSchemaToJson } from './zod-to-json'\n\ntype FreeformRecord = Record<string, any>\n\nconst defaultSkipList = [\n '/documentation/',\n '/documentation/initOAuth',\n '/documentation/json',\n '/documentation/uiConfig',\n '/documentation/yaml',\n '/documentation/*',\n '/documentation/static/*',\n]\n\nexport interface ZodTypeProvider extends FastifyTypeProvider {\n validator: this['schema'] extends $ZodType ? output<this['schema']> : unknown\n serializer: this['schema'] extends $ZodType ? output<this['schema']> : unknown\n}\n\ninterface Schema extends FastifySchema {\n hide?: boolean\n}\n\ntype CreateJsonSchemaTransformOptions = {\n skipList?: readonly string[]\n schemaRegistry?: $ZodRegistry<SchemaRegistryMeta>\n zodToJsonConfig?: ZodToJsonConfig\n}\n\nexport const createJsonSchemaTransform = ({\n skipList = defaultSkipList,\n schemaRegistry = globalRegistry,\n zodToJsonConfig = {},\n}: CreateJsonSchemaTransformOptions): SwaggerTransform<Schema> => {\n return (document) => {\n assertIsOpenAPIObject(document)\n\n const { schema, url } = document\n\n if (!schema) {\n return {\n schema,\n url,\n }\n }\n\n const target = getJSONSchemaTarget(document.openapiObject.openapi)\n const config = {\n target,\n ...zodToJsonConfig,\n }\n\n const { inputRegistry, outputRegistry } = generateIORegistries(schemaRegistry)\n\n const { response, headers, querystring, body, params, hide, ...rest } = schema\n\n const transformed: FreeformRecord = {}\n\n if (skipList.includes(url) || hide) {\n transformed.hide = true\n return { schema: transformed, url }\n }\n\n const zodSchemas: FreeformRecord = { headers, querystring, body, params }\n\n for (const prop in zodSchemas) {\n const zodSchema = zodSchemas[prop]\n if (zodSchema) {\n transformed[prop] = zodSchemaToJson(zodSchema, inputRegistry, 'input', config)\n }\n }\n\n if (response) {\n transformed.response = {}\n\n for (const prop in response as any) {\n const zodSchema = resolveSchema((response as any)[prop])\n\n transformed.response[prop] = zodSchemaToJson(zodSchema, outputRegistry, 'output', config)\n }\n }\n\n for (const prop in rest) {\n const meta = rest[prop as keyof typeof rest]\n if (meta) {\n transformed[prop] = meta\n }\n }\n\n return { schema: transformed, url }\n }\n}\n\nexport const jsonSchemaTransform: SwaggerTransform<Schema> = createJsonSchemaTransform({})\n\ntype CreateJsonSchemaTransformObjectOptions = {\n schemaRegistry?: $ZodRegistry<SchemaRegistryMeta>\n zodToJsonConfig?: ZodToJsonConfig\n}\n\nexport const createJsonSchemaTransformObject =\n ({\n schemaRegistry = globalRegistry,\n zodToJsonConfig = {},\n }: CreateJsonSchemaTransformObjectOptions): SwaggerTransformObject =>\n (document) => {\n assertIsOpenAPIObject(document)\n\n const target = getJSONSchemaTarget(document.openapiObject.openapi)\n const config = {\n target,\n ...zodToJsonConfig,\n }\n\n const { inputRegistry, outputRegistry } = generateIORegistries(schemaRegistry)\n const inputSchemas = zodRegistryToJson(inputRegistry, 'input', config)\n const outputSchemas = zodRegistryToJson(outputRegistry, 'output', config)\n\n return {\n ...document.openapiObject,\n components: {\n ...document.openapiObject.components,\n schemas: {\n ...document.openapiObject.components?.schemas,\n ...inputSchemas,\n ...outputSchemas,\n },\n },\n } as ReturnType<SwaggerTransformObject>\n }\n\nexport const jsonSchemaTransformObject: SwaggerTransformObject = createJsonSchemaTransformObject({})\n\nexport const validatorCompiler: FastifySchemaCompiler<$ZodType> =\n ({ schema }) =>\n (data) => {\n const result = safeDecode(schema, data)\n if (result.error) {\n return { error: createValidationError(result.error) as unknown as Error }\n }\n\n return { value: result.data }\n }\n\nfunction resolveSchema(maybeSchema: $ZodType | { properties: $ZodType }): $ZodType {\n if (maybeSchema instanceof $ZodType) {\n return maybeSchema as $ZodType\n }\n if ('properties' in maybeSchema && maybeSchema.properties instanceof $ZodType) {\n return maybeSchema.properties as $ZodType\n }\n throw new InvalidSchemaError(JSON.stringify(maybeSchema))\n}\n\ntype ReplacerFunction = (this: any, key: string, value: any) => any\n\nexport type ZodSerializerCompilerOptions = {\n replacer?: ReplacerFunction\n}\n\nexport const createSerializerCompiler =\n (\n options?: ZodSerializerCompilerOptions,\n ): FastifySerializerCompiler<$ZodType | { properties: $ZodType }> =>\n ({ schema: maybeSchema, method, url }) =>\n (data) => {\n const schema = resolveSchema(maybeSchema)\n\n const result = safeEncode(schema, data)\n if (result.error) {\n throw new ResponseSerializationError(method, url, { cause: result.error })\n }\n\n return JSON.stringify(result.data, options?.replacer)\n }\n\nexport const serializerCompiler: ReturnType<typeof createSerializerCompiler> =\n createSerializerCompiler({})\n\n/**\n * FastifyPluginCallbackZod with Zod automatic type inference\n *\n * @example\n * ```typescript\n * import { FastifyPluginCallbackZod } from \"fastify-type-provider-zod\"\n *\n * const plugin: FastifyPluginCallbackZod = (fastify, options, done) => {\n * done()\n * }\n * ```\n */\nexport type FastifyPluginCallbackZod<\n Options extends FastifyPluginOptions = Record<never, never>,\n Server extends RawServerBase = RawServerDefault,\n> = FastifyPluginCallback<Options, Server, ZodTypeProvider>\n\n/**\n * FastifyPluginAsyncZod with Zod automatic type inference\n *\n * @example\n * ```typescript\n * import { FastifyPluginAsyncZod } from \"fastify-type-provider-zod\"\n *\n * const plugin: FastifyPluginAsyncZod = async (fastify, options) => {\n * }\n * ```\n */\nexport type FastifyPluginAsyncZod<\n Options extends FastifyPluginOptions = Record<never, never>,\n Server extends RawServerBase = RawServerDefault,\n> = FastifyPluginAsync<Options, Server, ZodTypeProvider>\n"],"names":["globalRegistry","assertIsOpenAPIObject","getJSONSchemaTarget","generateIORegistries","zodSchemaToJson","zodRegistryToJson","safeDecode","createValidationError","$ZodType","InvalidSchemaError","safeEncode","ResponseSerializationError"],"mappings":"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"}
@@ -1,29 +1,28 @@
1
1
  import type { SwaggerTransform, SwaggerTransformObject } from "@fastify/swagger";
2
- import type { FastifyPluginAsync, FastifyPluginCallback, FastifyPluginOptions, FastifySchema, FastifySchemaCompiler, FastifyTypeProvider, RawServerBase, RawServerDefault } from "fastify";
3
- import type { FastifySerializerCompiler } from "fastify/types/schema";
4
- import type { $ZodRegistry, input, output } from "zod/v4/core";
2
+ import type { FastifyPluginAsync, FastifyPluginCallback, FastifyPluginOptions, FastifySchema, FastifySchemaCompiler, FastifySerializerCompiler, FastifyTypeProvider, RawServerBase, RawServerDefault } from "fastify";
3
+ import type { $ZodRegistry, output } from "zod/v4/core";
5
4
  import { $ZodType } from "zod/v4/core";
5
+ import { type SchemaRegistryMeta } from "../cjs/registry.cjs";
6
+ import { type ZodToJsonConfig } from "../cjs/zod-to-json.cjs";
6
7
  export interface ZodTypeProvider extends FastifyTypeProvider {
7
8
  validator: this["schema"] extends $ZodType ? output<this["schema"]> : unknown;
8
- serializer: this["schema"] extends $ZodType ? input<this["schema"]> : unknown;
9
+ serializer: this["schema"] extends $ZodType ? output<this["schema"]> : unknown;
9
10
  }
10
11
  interface Schema extends FastifySchema {
11
12
  hide?: boolean;
12
13
  }
13
14
  type CreateJsonSchemaTransformOptions = {
14
15
  skipList?: readonly string[];
15
- schemaRegistry?: $ZodRegistry<{
16
- id?: string | undefined;
17
- }>;
16
+ schemaRegistry?: $ZodRegistry<SchemaRegistryMeta>;
17
+ zodToJsonConfig?: ZodToJsonConfig;
18
18
  };
19
- export declare const createJsonSchemaTransform: ({ skipList, schemaRegistry }: CreateJsonSchemaTransformOptions) => SwaggerTransform<Schema>;
19
+ export declare const createJsonSchemaTransform: ({ skipList, schemaRegistry, zodToJsonConfig }: CreateJsonSchemaTransformOptions) => SwaggerTransform<Schema>;
20
20
  export declare const jsonSchemaTransform: SwaggerTransform<Schema>;
21
21
  type CreateJsonSchemaTransformObjectOptions = {
22
- schemaRegistry?: $ZodRegistry<{
23
- id?: string | undefined;
24
- }>;
22
+ schemaRegistry?: $ZodRegistry<SchemaRegistryMeta>;
23
+ zodToJsonConfig?: ZodToJsonConfig;
25
24
  };
26
- export declare const createJsonSchemaTransformObject: ({ schemaRegistry }: CreateJsonSchemaTransformObjectOptions) => SwaggerTransformObject;
25
+ export declare const createJsonSchemaTransformObject: ({ schemaRegistry, zodToJsonConfig }: CreateJsonSchemaTransformObjectOptions) => SwaggerTransformObject;
27
26
  export declare const jsonSchemaTransformObject: SwaggerTransformObject;
28
27
  export declare const validatorCompiler: FastifySchemaCompiler<$ZodType>;
29
28
  type ReplacerFunction = (this: any, key: string, value: any) => any;
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const createError = require("@fastify/error");
4
4
  const InvalidSchemaError = createError("FST_ERR_INVALID_SCHEMA", "Invalid schema passed: %s", 500);
5
- const ZodFastifySchemaValidationErrorSymbol = Symbol.for("ZodFastifySchemaValidationError");
5
+ const ZodFastifySchemaValidationErrorSymbol = /* @__PURE__ */ Symbol.for("ZodFastifySchemaValidationError");
6
6
  const ResponseSerializationBase = createError(
7
7
  "FST_ERR_RESPONSE_SERIALIZATION",
8
8
  "Response doesn't match the schema",
@@ -1 +1 @@
1
- {"version":3,"file":"errors.cjs","sources":["../../src/errors.ts"],"sourcesContent":["import createError, { type FastifyErrorConstructor } from '@fastify/error'\nimport type { FastifyError } from 'fastify'\nimport type { FastifySchemaValidationError } from 'fastify/types/schema'\nimport type { $ZodError } from 'zod/v4/core'\n\nexport const InvalidSchemaError: FastifyErrorConstructor<\n {\n code: string\n },\n [string]\n> = createError<[string]>('FST_ERR_INVALID_SCHEMA', 'Invalid schema passed: %s', 500)\n\nconst ZodFastifySchemaValidationErrorSymbol: symbol = Symbol.for('ZodFastifySchemaValidationError')\n\nexport type ZodFastifySchemaValidationError = FastifySchemaValidationError & {\n [ZodFastifySchemaValidationErrorSymbol]: true\n}\n\nconst ResponseSerializationBase: FastifyErrorConstructor<\n {\n code: string\n },\n [\n {\n cause: $ZodError\n },\n ]\n> = createError<[{ cause: $ZodError }]>(\n 'FST_ERR_RESPONSE_SERIALIZATION',\n \"Response doesn't match the schema\",\n 500,\n)\n\nexport class ResponseSerializationError extends ResponseSerializationBase {\n cause!: $ZodError\n\n constructor(\n public method: string,\n public url: string,\n options: { cause: $ZodError },\n ) {\n super({ cause: options.cause })\n\n this.cause = options.cause\n }\n}\n\nexport function isResponseSerializationError(value: unknown): value is ResponseSerializationError {\n return 'method' in (value as ResponseSerializationError)\n}\n\nfunction isZodFastifySchemaValidationError(\n error: unknown,\n): error is ZodFastifySchemaValidationError {\n return (\n typeof error === 'object' &&\n error !== null &&\n (error as ZodFastifySchemaValidationError)[ZodFastifySchemaValidationErrorSymbol] === true\n )\n}\n\nexport function hasZodFastifySchemaValidationErrors(\n error: unknown,\n): error is Omit<FastifyError, 'validation'> & { validation: ZodFastifySchemaValidationError[] } {\n return (\n typeof error === 'object' &&\n error !== null &&\n 'validation' in error &&\n Array.isArray(error.validation) &&\n error.validation.length > 0 &&\n isZodFastifySchemaValidationError(error.validation[0])\n )\n}\n\nfunction omit<T extends object, K extends keyof T>(obj: T, keys: readonly K[]): Omit<T, K> {\n const result = {} as Omit<T, K>\n for (const key of Object.keys(obj) as Array<keyof T>) {\n if (!keys.includes(key as K)) {\n // @ts-expect-error\n result[key] = obj[key]\n }\n }\n return result\n}\n\nexport function createValidationError(error: $ZodError): ZodFastifySchemaValidationError[] {\n return error.issues.map((issue) => {\n return {\n [ZodFastifySchemaValidationErrorSymbol]: true,\n keyword: issue.code,\n instancePath: `/${issue.path.join('/')}`,\n schemaPath: `#/${issue.path.join('/')}/${issue.code}`,\n message: issue.message,\n params: {\n ...omit(issue, ['path', 'code', 'message']),\n },\n }\n })\n}\n"],"names":[],"mappings":";;;AAKO,MAAM,qBAKT,YAAsB,0BAA0B,6BAA6B,GAAG;AAEpF,MAAM,wCAAgD,OAAO,IAAI,iCAAiC;AAMlG,MAAM,4BASF;AAAA,EACF;AAAA,EACA;AAAA,EACA;AACF;AAEO,MAAM,mCAAmC,0BAA0B;AAAA,EAGxE,YACS,QACA,KACP,SACA;AACA,UAAM,EAAE,OAAO,QAAQ,MAAA,CAAO;AAJvB,SAAA,SAAA;AACA,SAAA,MAAA;AAKP,SAAK,QAAQ,QAAQ;AAAA,EACvB;AAAA,EAVA;AAWF;AAEO,SAAS,6BAA6B,OAAqD;AAChG,SAAO,YAAa;AACtB;AAEA,SAAS,kCACP,OAC0C;AAC1C,SACE,OAAO,UAAU,YACjB,UAAU,QACT,MAA0C,qCAAqC,MAAM;AAE1F;AAEO,SAAS,oCACd,OAC+F;AAC/F,SACE,OAAO,UAAU,YACjB,UAAU,QACV,gBAAgB,SAChB,MAAM,QAAQ,MAAM,UAAU,KAC9B,MAAM,WAAW,SAAS,KAC1B,kCAAkC,MAAM,WAAW,CAAC,CAAC;AAEzD;AAEA,SAAS,KAA0C,KAAQ,MAAgC;AACzF,QAAM,SAAS,CAAA;AACf,aAAW,OAAO,OAAO,KAAK,GAAG,GAAqB;AACpD,QAAI,CAAC,KAAK,SAAS,GAAQ,GAAG;AAE5B,aAAO,GAAG,IAAI,IAAI,GAAG;AAAA,IACvB;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,sBAAsB,OAAqD;AACzF,SAAO,MAAM,OAAO,IAAI,CAAC,UAAU;AACjC,WAAO;AAAA,MACL,CAAC,qCAAqC,GAAG;AAAA,MACzC,SAAS,MAAM;AAAA,MACf,cAAc,IAAI,MAAM,KAAK,KAAK,GAAG,CAAC;AAAA,MACtC,YAAY,KAAK,MAAM,KAAK,KAAK,GAAG,CAAC,IAAI,MAAM,IAAI;AAAA,MACnD,SAAS,MAAM;AAAA,MACf,QAAQ;AAAA,QACN,GAAG,KAAK,OAAO,CAAC,QAAQ,QAAQ,SAAS,CAAC;AAAA,MAAA;AAAA,IAC5C;AAAA,EAEJ,CAAC;AACH;;;;;;"}
1
+ {"version":3,"file":"errors.cjs","sources":["../../src/errors.ts"],"sourcesContent":["import createError, { type FastifyErrorConstructor } from '@fastify/error'\nimport type { FastifyError } from 'fastify'\nimport type { FastifySchemaValidationError } from 'fastify/types/schema'\nimport type { $ZodError } from 'zod/v4/core'\n\nexport const InvalidSchemaError: FastifyErrorConstructor<\n {\n code: string\n },\n [string]\n> = createError<[string]>('FST_ERR_INVALID_SCHEMA', 'Invalid schema passed: %s', 500)\n\nconst ZodFastifySchemaValidationErrorSymbol: symbol = Symbol.for('ZodFastifySchemaValidationError')\n\nexport type ZodFastifySchemaValidationError = FastifySchemaValidationError & {\n [ZodFastifySchemaValidationErrorSymbol]: true\n}\n\nconst ResponseSerializationBase: FastifyErrorConstructor<\n {\n code: string\n },\n [\n {\n cause: $ZodError\n },\n ]\n> = createError<[{ cause: $ZodError }]>(\n 'FST_ERR_RESPONSE_SERIALIZATION',\n \"Response doesn't match the schema\",\n 500,\n)\n\nexport class ResponseSerializationError extends ResponseSerializationBase {\n cause!: $ZodError\n\n constructor(\n public method: string,\n public url: string,\n options: { cause: $ZodError },\n ) {\n super({ cause: options.cause })\n\n this.cause = options.cause\n }\n}\n\nexport function isResponseSerializationError(value: unknown): value is ResponseSerializationError {\n return 'method' in (value as ResponseSerializationError)\n}\n\nfunction isZodFastifySchemaValidationError(\n error: unknown,\n): error is ZodFastifySchemaValidationError {\n return (\n typeof error === 'object' &&\n error !== null &&\n (error as ZodFastifySchemaValidationError)[ZodFastifySchemaValidationErrorSymbol] === true\n )\n}\n\nexport function hasZodFastifySchemaValidationErrors(\n error: unknown,\n): error is Omit<FastifyError, 'validation'> & { validation: ZodFastifySchemaValidationError[] } {\n return (\n typeof error === 'object' &&\n error !== null &&\n 'validation' in error &&\n Array.isArray(error.validation) &&\n error.validation.length > 0 &&\n isZodFastifySchemaValidationError(error.validation[0])\n )\n}\n\nfunction omit<T extends object, K extends keyof T>(obj: T, keys: readonly K[]): Omit<T, K> {\n const result = {} as Omit<T, K>\n for (const key of Object.keys(obj) as Array<keyof T>) {\n if (!keys.includes(key as K)) {\n // @ts-expect-error\n result[key] = obj[key]\n }\n }\n return result\n}\n\nexport function createValidationError(error: $ZodError): ZodFastifySchemaValidationError[] {\n return error.issues.map((issue) => {\n return {\n [ZodFastifySchemaValidationErrorSymbol]: true,\n keyword: issue.code,\n instancePath: `/${issue.path.join('/')}`,\n schemaPath: `#/${issue.path.join('/')}/${issue.code}`,\n message: issue.message,\n params: {\n ...omit(issue, ['path', 'code', 'message']),\n },\n }\n })\n}\n"],"names":[],"mappings":";;;AAKO,MAAM,qBAKT,YAAsB,0BAA0B,6BAA6B,GAAG;AAEpF,MAAM,wCAAgD,uBAAO,IAAI,iCAAiC;AAMlG,MAAM,4BASF;AAAA,EACF;AAAA,EACA;AAAA,EACA;AACF;AAEO,MAAM,mCAAmC,0BAA0B;AAAA,EAGxE,YACS,QACA,KACP,SACA;AACA,UAAM,EAAE,OAAO,QAAQ,MAAA,CAAO;AAJvB,SAAA,SAAA;AACA,SAAA,MAAA;AAKP,SAAK,QAAQ,QAAQ;AAAA,EACvB;AAAA,EAVA;AAWF;AAEO,SAAS,6BAA6B,OAAqD;AAChG,SAAO,YAAa;AACtB;AAEA,SAAS,kCACP,OAC0C;AAC1C,SACE,OAAO,UAAU,YACjB,UAAU,QACT,MAA0C,qCAAqC,MAAM;AAE1F;AAEO,SAAS,oCACd,OAC+F;AAC/F,SACE,OAAO,UAAU,YACjB,UAAU,QACV,gBAAgB,SAChB,MAAM,QAAQ,MAAM,UAAU,KAC9B,MAAM,WAAW,SAAS,KAC1B,kCAAkC,MAAM,WAAW,CAAC,CAAC;AAEzD;AAEA,SAAS,KAA0C,KAAQ,MAAgC;AACzF,QAAM,SAAS,CAAA;AACf,aAAW,OAAO,OAAO,KAAK,GAAG,GAAqB;AACpD,QAAI,CAAC,KAAK,SAAS,GAAQ,GAAG;AAE5B,aAAO,GAAG,IAAI,IAAI,GAAG;AAAA,IACvB;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,sBAAsB,OAAqD;AACzF,SAAO,MAAM,OAAO,IAAI,CAAC,UAAU;AACjC,WAAO;AAAA,MACL,CAAC,qCAAqC,GAAG;AAAA,MACzC,SAAS,MAAM;AAAA,MACf,cAAc,IAAI,MAAM,KAAK,KAAK,GAAG,CAAC;AAAA,MACtC,YAAY,KAAK,MAAM,KAAK,KAAK,GAAG,CAAC,IAAI,MAAM,IAAI;AAAA,MACnD,SAAS,MAAM;AAAA,MACf,QAAQ;AAAA,QACN,GAAG,KAAK,OAAO,CAAC,QAAQ,QAAQ,SAAS,CAAC;AAAA,MAAA;AAAA,IAC5C;AAAA,EAEJ,CAAC;AACH;;;;;;"}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const core = require("zod/v4/core");
4
+ const getSchemaId = (id, io) => {
5
+ return io === "input" ? `${id}Input` : id;
6
+ };
7
+ class WeakMapWithFallback extends WeakMap {
8
+ constructor(fallback) {
9
+ super();
10
+ this.fallback = fallback;
11
+ }
12
+ get(key) {
13
+ return super.get(key) ?? this.fallback.get(key);
14
+ }
15
+ has(key) {
16
+ return super.has(key) || this.fallback.has(key);
17
+ }
18
+ }
19
+ const copyRegistry = (inputRegistry, idReplaceFn) => {
20
+ const outputRegistry = new core.$ZodRegistry();
21
+ outputRegistry._map = new WeakMapWithFallback(inputRegistry._map);
22
+ inputRegistry._idmap.forEach((schema, id) => {
23
+ outputRegistry.add(schema, {
24
+ ...inputRegistry._map.get(schema),
25
+ id: idReplaceFn(id)
26
+ });
27
+ });
28
+ return outputRegistry;
29
+ };
30
+ const generateIORegistries = (baseRegistry) => {
31
+ const inputRegistry = copyRegistry(baseRegistry, (id) => getSchemaId(id, "input"));
32
+ const outputRegistry = copyRegistry(baseRegistry, (id) => getSchemaId(id, "output"));
33
+ inputRegistry._idmap.forEach((_, id) => {
34
+ if (outputRegistry._idmap.has(id)) {
35
+ throw new Error(
36
+ `Collision detected for schema "${id}". There is already an input schema with the same name.`
37
+ );
38
+ }
39
+ });
40
+ return { inputRegistry, outputRegistry };
41
+ };
42
+ exports.generateIORegistries = generateIORegistries;
43
+ //# sourceMappingURL=registry.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.cjs","sources":["../../src/registry.ts"],"sourcesContent":["import { $ZodRegistry, type $ZodType } from 'zod/v4/core'\n\nexport type SchemaRegistryMeta = {\n id?: string | undefined\n [key: string]: unknown\n}\n\nconst getSchemaId = (id: string, io: 'input' | 'output'): string => {\n return io === 'input' ? `${id}Input` : id\n}\n\n// A WeakMap that falls back to another WeakMap when a key is not found, this is to ensure nested metadata is properly resolved\nclass WeakMapWithFallback extends WeakMap<$ZodType, SchemaRegistryMeta> {\n constructor(private fallback: WeakMap<$ZodType, SchemaRegistryMeta>) {\n super()\n }\n\n get(key: $ZodType): SchemaRegistryMeta | undefined {\n return super.get(key) ?? this.fallback.get(key)\n }\n\n has(key: $ZodType): boolean {\n return super.has(key) || this.fallback.has(key)\n }\n}\n\nconst copyRegistry = (\n inputRegistry: $ZodRegistry<SchemaRegistryMeta>,\n idReplaceFn: (id: string) => string,\n): $ZodRegistry<SchemaRegistryMeta> => {\n const outputRegistry = new $ZodRegistry<SchemaRegistryMeta>()\n\n outputRegistry._map = new WeakMapWithFallback(inputRegistry._map)\n\n inputRegistry._idmap.forEach((schema, id) => {\n outputRegistry.add(schema, {\n ...inputRegistry._map.get(schema),\n id: idReplaceFn(id),\n })\n })\n\n return outputRegistry\n}\n\nexport const generateIORegistries = (\n baseRegistry: $ZodRegistry<SchemaRegistryMeta>,\n): {\n inputRegistry: $ZodRegistry<SchemaRegistryMeta>\n outputRegistry: $ZodRegistry<SchemaRegistryMeta>\n} => {\n const inputRegistry = copyRegistry(baseRegistry, (id) => getSchemaId(id, 'input'))\n const outputRegistry = copyRegistry(baseRegistry, (id) => getSchemaId(id, 'output'))\n\n // Detect colliding schemas\n inputRegistry._idmap.forEach((_, id) => {\n if (outputRegistry._idmap.has(id)) {\n throw new Error(\n `Collision detected for schema \"${id}\". There is already an input schema with the same name.`,\n )\n }\n })\n\n return { inputRegistry, outputRegistry }\n}\n"],"names":["$ZodRegistry"],"mappings":";;;AAOA,MAAM,cAAc,CAAC,IAAY,OAAmC;AAClE,SAAO,OAAO,UAAU,GAAG,EAAE,UAAU;AACzC;AAGA,MAAM,4BAA4B,QAAsC;AAAA,EACtE,YAAoB,UAAiD;AACnE,UAAA;AADkB,SAAA,WAAA;AAAA,EAEpB;AAAA,EAEA,IAAI,KAA+C;AACjD,WAAO,MAAM,IAAI,GAAG,KAAK,KAAK,SAAS,IAAI,GAAG;AAAA,EAChD;AAAA,EAEA,IAAI,KAAwB;AAC1B,WAAO,MAAM,IAAI,GAAG,KAAK,KAAK,SAAS,IAAI,GAAG;AAAA,EAChD;AACF;AAEA,MAAM,eAAe,CACnB,eACA,gBACqC;AACrC,QAAM,iBAAiB,IAAIA,kBAAA;AAE3B,iBAAe,OAAO,IAAI,oBAAoB,cAAc,IAAI;AAEhE,gBAAc,OAAO,QAAQ,CAAC,QAAQ,OAAO;AAC3C,mBAAe,IAAI,QAAQ;AAAA,MACzB,GAAG,cAAc,KAAK,IAAI,MAAM;AAAA,MAChC,IAAI,YAAY,EAAE;AAAA,IAAA,CACnB;AAAA,EACH,CAAC;AAED,SAAO;AACT;AAEO,MAAM,uBAAuB,CAClC,iBAIG;AACH,QAAM,gBAAgB,aAAa,cAAc,CAAC,OAAO,YAAY,IAAI,OAAO,CAAC;AACjF,QAAM,iBAAiB,aAAa,cAAc,CAAC,OAAO,YAAY,IAAI,QAAQ,CAAC;AAGnF,gBAAc,OAAO,QAAQ,CAAC,GAAG,OAAO;AACtC,QAAI,eAAe,OAAO,IAAI,EAAE,GAAG;AACjC,YAAM,IAAI;AAAA,QACR,kCAAkC,EAAE;AAAA,MAAA;AAAA,IAExC;AAAA,EACF,CAAC;AAED,SAAO,EAAE,eAAe,eAAA;AAC1B;;"}
@@ -0,0 +1,9 @@
1
+ import { $ZodRegistry } from "zod/v4/core";
2
+ export type SchemaRegistryMeta = {
3
+ id?: string | undefined;
4
+ [key: string]: unknown;
5
+ };
6
+ export declare const generateIORegistries: (baseRegistry: $ZodRegistry<SchemaRegistryMeta>) => {
7
+ inputRegistry: $ZodRegistry<SchemaRegistryMeta>;
8
+ outputRegistry: $ZodRegistry<SchemaRegistryMeta>;
9
+ };
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const assertIsOpenAPIObject = (obj) => {
4
+ if ("swaggerObject" in obj) {
5
+ throw new Error("This package currently does not support component references for Swagger 2.0");
6
+ }
7
+ };
8
+ const getReferenceUri = (input) => {
9
+ const id = input.replace(/^#\/(?:\$defs|definitions|components\/schemas)\//, "");
10
+ return `#/components/schemas/${id}`;
11
+ };
12
+ const getJSONSchemaTarget = (version = "3.0.0") => {
13
+ if (version.startsWith("3.0")) {
14
+ return "openapi-3.0";
15
+ }
16
+ return "draft-2020-12";
17
+ };
18
+ exports.assertIsOpenAPIObject = assertIsOpenAPIObject;
19
+ exports.getJSONSchemaTarget = getJSONSchemaTarget;
20
+ exports.getReferenceUri = getReferenceUri;
21
+ //# sourceMappingURL=utils.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.cjs","sources":["../../src/utils.ts"],"sourcesContent":["import type { OpenAPIV2, OpenAPIV3, OpenAPIV3_1 } from 'openapi-types'\n\ntype SwaggerObject = {\n swaggerObject: Partial<OpenAPIV2.Document>\n}\n\ntype OpenAPIObject = {\n openapiObject: Partial<OpenAPIV3.Document | OpenAPIV3_1.Document>\n}\n\nexport const assertIsOpenAPIObject: (\n obj: SwaggerObject | OpenAPIObject,\n) => asserts obj is OpenAPIObject = (obj) => {\n if ('swaggerObject' in obj) {\n throw new Error('This package currently does not support component references for Swagger 2.0')\n }\n}\n\nexport type JSONSchemaTarget = 'draft-2020-12' | 'openapi-3.0'\n\nexport const getReferenceUri = (input: string): string => {\n const id = input.replace(/^#\\/(?:\\$defs|definitions|components\\/schemas)\\//, '')\n\n return `#/components/schemas/${id}`\n}\n\nexport const getJSONSchemaTarget = (version = '3.0.0'): JSONSchemaTarget => {\n if (version.startsWith('3.0')) {\n return 'openapi-3.0'\n }\n\n return 'draft-2020-12'\n}\n"],"names":[],"mappings":";;AAUO,MAAM,wBAEuB,CAAC,QAAQ;AAC3C,MAAI,mBAAmB,KAAK;AAC1B,UAAM,IAAI,MAAM,8EAA8E;AAAA,EAChG;AACF;AAIO,MAAM,kBAAkB,CAAC,UAA0B;AACxD,QAAM,KAAK,MAAM,QAAQ,oDAAoD,EAAE;AAE/E,SAAO,wBAAwB,EAAE;AACnC;AAEO,MAAM,sBAAsB,CAAC,UAAU,YAA8B;AAC1E,MAAI,QAAQ,WAAW,KAAK,GAAG;AAC7B,WAAO;AAAA,EACT;AAEA,SAAO;AACT;;;;"}
@@ -0,0 +1,12 @@
1
+ import type { OpenAPIV2, OpenAPIV3, OpenAPIV3_1 } from "openapi-types";
2
+ type SwaggerObject = {
3
+ swaggerObject: Partial<OpenAPIV2.Document>;
4
+ };
5
+ type OpenAPIObject = {
6
+ openapiObject: Partial<OpenAPIV3.Document | OpenAPIV3_1.Document>;
7
+ };
8
+ export declare const assertIsOpenAPIObject: (obj: SwaggerObject | OpenAPIObject) => asserts obj is OpenAPIObject;
9
+ export type JSONSchemaTarget = "draft-2020-12" | "openapi-3.0";
10
+ export declare const getReferenceUri: (input: string) => string;
11
+ export declare const getJSONSchemaTarget: (version?: string) => JSONSchemaTarget;
12
+ export {};
@@ -1,12 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const core = require("zod/v4/core");
4
- const getSchemaId = (id, io) => {
5
- return io === "input" ? `${id}Input` : id;
6
- };
7
- const getReferenceUri = (id, io) => {
8
- return `#/components/schemas/${getSchemaId(id, io)}`;
9
- };
4
+ const utils = require("./utils.cjs");
5
+ const SCHEMA_REGISTRY_ID_PLACEHOLDER = "__SCHEMA__ID__PLACEHOLDER__";
6
+ const SCHEMA_URI_PLACEHOLDER = "__SCHEMA__PLACEHOLDER__";
10
7
  function isZodDate(entity) {
11
8
  return entity instanceof core.$ZodType && entity._zod.def.type === "date";
12
9
  }
@@ -32,64 +29,62 @@ const getOverride = (ctx, io) => {
32
29
  }
33
30
  }
34
31
  };
35
- const zodSchemaToJson = (zodSchema, registry, io) => {
32
+ const deleteInvalidProperties = (schema) => {
33
+ const object = { ...schema };
34
+ delete object.id;
35
+ delete object.$schema;
36
+ delete object.$id;
37
+ return object;
38
+ };
39
+ const zodSchemaToJson = (zodSchema, registry, io, config) => {
36
40
  const schemaRegistryEntry = registry.get(zodSchema);
37
41
  if (schemaRegistryEntry?.id) {
38
- return {
39
- $ref: getReferenceUri(schemaRegistryEntry.id, io)
40
- };
42
+ return { $ref: utils.getReferenceUri(schemaRegistryEntry.id) };
41
43
  }
42
- const tempID = "GEN";
43
44
  const tempRegistry = new core.$ZodRegistry();
44
- tempRegistry.add(zodSchema, { id: tempID });
45
+ tempRegistry.add(zodSchema, { id: SCHEMA_REGISTRY_ID_PLACEHOLDER });
45
46
  const {
46
- schemas: { [tempID]: result }
47
+ schemas: { [SCHEMA_REGISTRY_ID_PLACEHOLDER]: result }
47
48
  } = core.toJSONSchema(tempRegistry, {
48
- target: "draft-2020-12",
49
- metadata: registry,
49
+ ...config,
50
50
  io,
51
- unrepresentable: "any",
51
+ target: config.target,
52
+ metadata: registry,
53
+ unrepresentable: config.unrepresentable ?? "any",
52
54
  cycles: "ref",
53
55
  reused: "inline",
54
56
  /**
55
57
  * The uri option only allows customizing the base path of the `$ref`, and it automatically appends a path to it.
56
- * As a workaround, we set a placeholder that looks something like this:
57
- *
58
- * | marker | always added by zod | meta.id |
59
- * |__SCHEMA__PLACEHOLDER__| #/$defs/ | User |
60
- *
61
- * @example `__SCHEMA__PLACEHOLDER__#/$defs/User"`
62
- * @example `__SCHEMA__PLACEHOLDER__#/$defs/Group"`
63
- *
58
+ * As a workaround, we set a placeholder that looks something like this.
64
59
  * @see jsonSchemaReplaceRef
65
60
  * @see https://github.com/colinhacks/zod/issues/4750
66
61
  */
67
- uri: () => `__SCHEMA__PLACEHOLDER__`,
68
- override: (ctx) => getOverride(ctx, io)
62
+ uri: () => SCHEMA_URI_PLACEHOLDER,
63
+ override: config.override ?? ((ctx) => getOverride(ctx, io))
64
+ });
65
+ const jsonSchema = deleteInvalidProperties(result);
66
+ return JSON.parse(JSON.stringify(jsonSchema), (__key, value) => {
67
+ if (typeof value === "string" && value.startsWith(SCHEMA_URI_PLACEHOLDER)) {
68
+ return utils.getReferenceUri(value.slice(SCHEMA_URI_PLACEHOLDER.length));
69
+ }
70
+ return value;
69
71
  });
70
- const jsonSchema = { ...result };
71
- delete jsonSchema.id;
72
- const jsonSchemaReplaceRef = JSON.stringify(jsonSchema).replaceAll(
73
- /"__SCHEMA__PLACEHOLDER__#\/\$defs\/(.+?)"/g,
74
- (_, id) => `"${getReferenceUri(id, io)}"`
75
- );
76
- return JSON.parse(jsonSchemaReplaceRef);
77
72
  };
78
- const zodRegistryToJson = (registry, io) => {
73
+ const zodRegistryToJson = (registry, io, config) => {
79
74
  const result = core.toJSONSchema(registry, {
80
- target: "draft-2020-12",
75
+ ...config,
81
76
  io,
82
- unrepresentable: "any",
77
+ target: config.target,
78
+ metadata: registry,
79
+ unrepresentable: config.unrepresentable ?? "any",
83
80
  cycles: "ref",
84
81
  reused: "inline",
85
- uri: (id) => getReferenceUri(id, io),
86
- override: (ctx) => getOverride(ctx, io)
82
+ uri: (id) => utils.getReferenceUri(id),
83
+ override: config.override ?? ((ctx) => getOverride(ctx, io))
87
84
  }).schemas;
88
85
  const jsonSchemas = {};
89
86
  for (const id in result) {
90
- const jsonSchema = { ...result[id] };
91
- delete jsonSchema.id;
92
- jsonSchemas[getSchemaId(id, io)] = jsonSchema;
87
+ jsonSchemas[id] = deleteInvalidProperties(result[id]);
93
88
  }
94
89
  return jsonSchemas;
95
90
  };
@@ -1 +1 @@
1
- {"version":3,"file":"zod-to-json.cjs","sources":["../../src/zod-to-json.ts"],"sourcesContent":["import type { $ZodDate, $ZodUndefined, $ZodUnion, JSONSchema } from 'zod/v4/core'\nimport { $ZodRegistry, $ZodType, toJSONSchema } from 'zod/v4/core'\n\nconst getSchemaId = (id: string, io: 'input' | 'output') => {\n return io === 'input' ? `${id}Input` : id\n}\n\nconst getReferenceUri = (id: string, io: 'input' | 'output') => {\n return `#/components/schemas/${getSchemaId(id, io)}`\n}\n\nfunction isZodDate(entity: unknown): entity is $ZodDate {\n return entity instanceof $ZodType && entity._zod.def.type === 'date'\n}\n\nfunction isZodUnion(entity: unknown): entity is $ZodUnion {\n return entity instanceof $ZodType && entity._zod.def.type === 'union'\n}\n\nfunction isZodUndefined(entity: unknown): entity is $ZodUndefined {\n return entity instanceof $ZodType && entity._zod.def.type === 'undefined'\n}\n\nconst getOverride = (\n ctx: {\n zodSchema: $ZodType\n jsonSchema: JSONSchema.BaseSchema\n },\n io: 'input' | 'output',\n) => {\n if (isZodUnion(ctx.zodSchema)) {\n // Filter unrepresentable types in unions\n // TODO: Should be fixed upstream and not merged in this plugin.\n // Remove when passed: https://github.com/colinhacks/zod/pull/5013\n ctx.jsonSchema.anyOf = ctx.jsonSchema.anyOf?.filter((schema) => Object.keys(schema).length > 0)\n }\n\n if (isZodDate(ctx.zodSchema)) {\n // Allow dates to be represented as strings in output schemas\n if (io === 'output') {\n ctx.jsonSchema.type = 'string'\n ctx.jsonSchema.format = 'date-time'\n }\n }\n\n if (isZodUndefined(ctx.zodSchema)) {\n // Allow undefined to be represented as null in output schemas\n if (io === 'output') {\n ctx.jsonSchema.type = 'null'\n }\n }\n}\n\nexport const zodSchemaToJson: (\n zodSchema: $ZodType,\n registry: $ZodRegistry<{ id?: string }>,\n io: 'input' | 'output',\n) => JSONSchema.BaseSchema = (zodSchema, registry, io) => {\n const schemaRegistryEntry = registry.get(zodSchema)\n\n /**\n * Checks whether the provided schema is registered in the given registry.\n * If it is present and has an `id`, it can be referenced as component.\n *\n * @see https://github.com/turkerdev/fastify-type-provider-zod/issues/173\n */\n if (schemaRegistryEntry?.id) {\n return {\n $ref: getReferenceUri(schemaRegistryEntry.id, io),\n }\n }\n\n /**\n * Unfortunately, at the time of writing, there is no way to generate a schema with `$ref`\n * using `toJSONSchema` and a zod schema.\n *\n * As a workaround, we create a zod registry containing only the specific schema we want to convert.\n *\n * @see https://github.com/colinhacks/zod/issues/4281\n */\n const tempID = 'GEN'\n const tempRegistry = new $ZodRegistry<{ id?: string }>()\n tempRegistry.add(zodSchema, { id: tempID })\n\n const {\n schemas: { [tempID]: result },\n } = toJSONSchema(tempRegistry, {\n target: 'draft-2020-12',\n metadata: registry,\n io,\n unrepresentable: 'any',\n cycles: 'ref',\n reused: 'inline',\n\n /**\n * The uri option only allows customizing the base path of the `$ref`, and it automatically appends a path to it.\n * As a workaround, we set a placeholder that looks something like this:\n *\n * | marker | always added by zod | meta.id |\n * |__SCHEMA__PLACEHOLDER__| #/$defs/ | User |\n *\n * @example `__SCHEMA__PLACEHOLDER__#/$defs/User\"`\n * @example `__SCHEMA__PLACEHOLDER__#/$defs/Group\"`\n *\n * @see jsonSchemaReplaceRef\n * @see https://github.com/colinhacks/zod/issues/4750\n */\n uri: () => `__SCHEMA__PLACEHOLDER__`,\n override: (ctx) => getOverride(ctx, io),\n })\n\n const jsonSchema = { ...result }\n delete jsonSchema.id\n\n /**\n * Replace the previous generated placeholders with the final `$ref` value\n */\n const jsonSchemaReplaceRef = JSON.stringify(jsonSchema).replaceAll(\n /\"__SCHEMA__PLACEHOLDER__#\\/\\$defs\\/(.+?)\"/g,\n (_, id) => `\"${getReferenceUri(id, io)}\"`,\n )\n\n return JSON.parse(jsonSchemaReplaceRef) as typeof result\n}\n\nexport const zodRegistryToJson: (\n registry: $ZodRegistry<{ id?: string }>,\n io: 'input' | 'output',\n) => Record<string, JSONSchema.BaseSchema> = (registry, io) => {\n const result = toJSONSchema(registry, {\n target: 'draft-2020-12',\n io,\n unrepresentable: 'any',\n cycles: 'ref',\n reused: 'inline',\n uri: (id) => getReferenceUri(id, io),\n override: (ctx) => getOverride(ctx, io),\n }).schemas\n\n const jsonSchemas: Record<string, JSONSchema.BaseSchema> = {}\n for (const id in result) {\n const jsonSchema = { ...result[id] }\n\n delete jsonSchema.id\n\n jsonSchemas[getSchemaId(id, io)] = jsonSchema\n }\n\n return jsonSchemas\n}\n"],"names":["$ZodType","$ZodRegistry","toJSONSchema"],"mappings":";;;AAGA,MAAM,cAAc,CAAC,IAAY,OAA2B;AAC1D,SAAO,OAAO,UAAU,GAAG,EAAE,UAAU;AACzC;AAEA,MAAM,kBAAkB,CAAC,IAAY,OAA2B;AAC9D,SAAO,wBAAwB,YAAY,IAAI,EAAE,CAAC;AACpD;AAEA,SAAS,UAAU,QAAqC;AACtD,SAAO,kBAAkBA,KAAAA,YAAY,OAAO,KAAK,IAAI,SAAS;AAChE;AAEA,SAAS,WAAW,QAAsC;AACxD,SAAO,kBAAkBA,KAAAA,YAAY,OAAO,KAAK,IAAI,SAAS;AAChE;AAEA,SAAS,eAAe,QAA0C;AAChE,SAAO,kBAAkBA,KAAAA,YAAY,OAAO,KAAK,IAAI,SAAS;AAChE;AAEA,MAAM,cAAc,CAClB,KAIA,OACG;AACH,MAAI,WAAW,IAAI,SAAS,GAAG;AAI7B,QAAI,WAAW,QAAQ,IAAI,WAAW,OAAO,OAAO,CAAC,WAAW,OAAO,KAAK,MAAM,EAAE,SAAS,CAAC;AAAA,EAChG;AAEA,MAAI,UAAU,IAAI,SAAS,GAAG;AAE5B,QAAI,OAAO,UAAU;AACnB,UAAI,WAAW,OAAO;AACtB,UAAI,WAAW,SAAS;AAAA,IAC1B;AAAA,EACF;AAEA,MAAI,eAAe,IAAI,SAAS,GAAG;AAEjC,QAAI,OAAO,UAAU;AACnB,UAAI,WAAW,OAAO;AAAA,IACxB;AAAA,EACF;AACF;AAEO,MAAM,kBAIgB,CAAC,WAAW,UAAU,OAAO;AACxD,QAAM,sBAAsB,SAAS,IAAI,SAAS;AAQlD,MAAI,qBAAqB,IAAI;AAC3B,WAAO;AAAA,MACL,MAAM,gBAAgB,oBAAoB,IAAI,EAAE;AAAA,IAAA;AAAA,EAEpD;AAUA,QAAM,SAAS;AACf,QAAM,eAAe,IAAIC,kBAAA;AACzB,eAAa,IAAI,WAAW,EAAE,IAAI,QAAQ;AAE1C,QAAM;AAAA,IACJ,SAAS,EAAE,CAAC,MAAM,GAAG,OAAA;AAAA,EAAO,IAC1BC,KAAAA,aAAa,cAAc;AAAA,IAC7B,QAAQ;AAAA,IACR,UAAU;AAAA,IACV;AAAA,IACA,iBAAiB;AAAA,IACjB,QAAQ;AAAA,IACR,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAeR,KAAK,MAAM;AAAA,IACX,UAAU,CAAC,QAAQ,YAAY,KAAK,EAAE;AAAA,EAAA,CACvC;AAED,QAAM,aAAa,EAAE,GAAG,OAAA;AACxB,SAAO,WAAW;AAKlB,QAAM,uBAAuB,KAAK,UAAU,UAAU,EAAE;AAAA,IACtD;AAAA,IACA,CAAC,GAAG,OAAO,IAAI,gBAAgB,IAAI,EAAE,CAAC;AAAA,EAAA;AAGxC,SAAO,KAAK,MAAM,oBAAoB;AACxC;AAEO,MAAM,oBAGgC,CAAC,UAAU,OAAO;AAC7D,QAAM,SAASA,KAAAA,aAAa,UAAU;AAAA,IACpC,QAAQ;AAAA,IACR;AAAA,IACA,iBAAiB;AAAA,IACjB,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,KAAK,CAAC,OAAO,gBAAgB,IAAI,EAAE;AAAA,IACnC,UAAU,CAAC,QAAQ,YAAY,KAAK,EAAE;AAAA,EAAA,CACvC,EAAE;AAEH,QAAM,cAAqD,CAAA;AAC3D,aAAW,MAAM,QAAQ;AACvB,UAAM,aAAa,EAAE,GAAG,OAAO,EAAE,EAAA;AAEjC,WAAO,WAAW;AAElB,gBAAY,YAAY,IAAI,EAAE,CAAC,IAAI;AAAA,EACrC;AAEA,SAAO;AACT;;;"}
1
+ {"version":3,"file":"zod-to-json.cjs","sources":["../../src/zod-to-json.ts"],"sourcesContent":["import type {\n $ZodDate,\n $ZodUndefined,\n $ZodUnion,\n JSONSchema,\n RegistryToJSONSchemaParams,\n} from 'zod/v4/core'\nimport { $ZodRegistry, $ZodType, toJSONSchema } from 'zod/v4/core'\nimport type { SchemaRegistryMeta } from './registry'\nimport { getReferenceUri } from './utils'\n\nconst SCHEMA_REGISTRY_ID_PLACEHOLDER = '__SCHEMA__ID__PLACEHOLDER__'\nconst SCHEMA_URI_PLACEHOLDER = '__SCHEMA__PLACEHOLDER__'\n\nfunction isZodDate(entity: unknown): entity is $ZodDate {\n return entity instanceof $ZodType && entity._zod.def.type === 'date'\n}\n\nfunction isZodUnion(entity: unknown): entity is $ZodUnion {\n return entity instanceof $ZodType && entity._zod.def.type === 'union'\n}\n\nfunction isZodUndefined(entity: unknown): entity is $ZodUndefined {\n return entity instanceof $ZodType && entity._zod.def.type === 'undefined'\n}\n\nconst getOverride = (\n ctx: {\n zodSchema: $ZodType\n jsonSchema: JSONSchema.BaseSchema\n },\n io: 'input' | 'output',\n) => {\n if (isZodUnion(ctx.zodSchema)) {\n // Filter unrepresentable types in unions\n // TODO: Should be fixed upstream and not merged in this plugin.\n // Remove when passed: https://github.com/colinhacks/zod/pull/5013\n ctx.jsonSchema.anyOf = ctx.jsonSchema.anyOf?.filter((schema) => Object.keys(schema).length > 0)\n }\n\n if (isZodDate(ctx.zodSchema)) {\n // Allow dates to be represented as strings in output schemas\n if (io === 'output') {\n ctx.jsonSchema.type = 'string'\n ctx.jsonSchema.format = 'date-time'\n }\n }\n\n if (isZodUndefined(ctx.zodSchema)) {\n // Allow undefined to be represented as null in output schemas\n if (io === 'output') {\n ctx.jsonSchema.type = 'null'\n }\n }\n}\n\nexport type ZodToJsonConfig = {} & Omit<\n RegistryToJSONSchemaParams,\n 'io' | 'metadata' | 'cycles' | 'reused' | 'uri'\n>\n\nconst deleteInvalidProperties: (\n schema: JSONSchema.BaseSchema,\n) => Omit<JSONSchema.BaseSchema, 'id' | '$schema'> = (schema) => {\n const object = { ...schema }\n\n delete object.id\n delete object.$schema\n\n // ToDo added in newer zod\n delete object.$id\n\n return object\n}\n\nexport const zodSchemaToJson: (\n zodSchema: $ZodType,\n registry: $ZodRegistry<SchemaRegistryMeta>,\n io: 'input' | 'output',\n config: ZodToJsonConfig,\n) => ReturnType<typeof deleteInvalidProperties> = (zodSchema, registry, io, config) => {\n /**\n * Checks whether the provided schema is registered in the given registry.\n * If it is present and has an `id`, it can be referenced as component.\n *\n * @see https://github.com/turkerdev/fastify-type-provider-zod/issues/173\n */\n const schemaRegistryEntry = registry.get(zodSchema)\n if (schemaRegistryEntry?.id) {\n return { $ref: getReferenceUri(schemaRegistryEntry.id) }\n }\n\n /**\n * Unfortunately, at the time of writing, there is no way to generate a schema with `$ref`\n * using `toJSONSchema` and a zod schema.\n *\n * As a workaround, we create a zod registry containing only the specific schema we want to convert.\n *\n * @see https://github.com/colinhacks/zod/issues/4281\n */\n const tempRegistry = new $ZodRegistry<SchemaRegistryMeta>()\n tempRegistry.add(zodSchema, { id: SCHEMA_REGISTRY_ID_PLACEHOLDER })\n\n const {\n schemas: { [SCHEMA_REGISTRY_ID_PLACEHOLDER]: result },\n } = toJSONSchema(tempRegistry, {\n ...config,\n io,\n target: config.target,\n metadata: registry,\n unrepresentable: config.unrepresentable ?? 'any',\n cycles: 'ref',\n reused: 'inline',\n /**\n * The uri option only allows customizing the base path of the `$ref`, and it automatically appends a path to it.\n * As a workaround, we set a placeholder that looks something like this.\n * @see jsonSchemaReplaceRef\n * @see https://github.com/colinhacks/zod/issues/4750\n */\n uri: () => SCHEMA_URI_PLACEHOLDER,\n override: config.override ?? ((ctx) => getOverride(ctx, io)),\n })\n\n const jsonSchema = deleteInvalidProperties(result)\n\n /**\n * Replace the previous generated placeholders with the final `$ref` value\n */\n return JSON.parse(JSON.stringify(jsonSchema), (__key, value) => {\n if (typeof value === 'string' && value.startsWith(SCHEMA_URI_PLACEHOLDER)) {\n return getReferenceUri(value.slice(SCHEMA_URI_PLACEHOLDER.length))\n }\n return value\n }) as typeof result\n}\n\nexport const zodRegistryToJson: (\n registry: $ZodRegistry<SchemaRegistryMeta>,\n io: 'input' | 'output',\n config: ZodToJsonConfig,\n) => Record<string, JSONSchema.BaseSchema> = (registry, io, config) => {\n const result = toJSONSchema(registry, {\n ...config,\n io,\n target: config.target,\n metadata: registry,\n unrepresentable: config.unrepresentable ?? 'any',\n cycles: 'ref',\n reused: 'inline',\n uri: (id) => getReferenceUri(id),\n override: config.override ?? ((ctx) => getOverride(ctx, io)),\n }).schemas\n\n const jsonSchemas: Record<string, JSONSchema.BaseSchema> = {}\n for (const id in result) {\n jsonSchemas[id] = deleteInvalidProperties(result[id])\n }\n\n return jsonSchemas\n}\n"],"names":["$ZodType","getReferenceUri","$ZodRegistry","toJSONSchema"],"mappings":";;;;AAWA,MAAM,iCAAiC;AACvC,MAAM,yBAAyB;AAE/B,SAAS,UAAU,QAAqC;AACtD,SAAO,kBAAkBA,KAAAA,YAAY,OAAO,KAAK,IAAI,SAAS;AAChE;AAEA,SAAS,WAAW,QAAsC;AACxD,SAAO,kBAAkBA,KAAAA,YAAY,OAAO,KAAK,IAAI,SAAS;AAChE;AAEA,SAAS,eAAe,QAA0C;AAChE,SAAO,kBAAkBA,KAAAA,YAAY,OAAO,KAAK,IAAI,SAAS;AAChE;AAEA,MAAM,cAAc,CAClB,KAIA,OACG;AACH,MAAI,WAAW,IAAI,SAAS,GAAG;AAI7B,QAAI,WAAW,QAAQ,IAAI,WAAW,OAAO,OAAO,CAAC,WAAW,OAAO,KAAK,MAAM,EAAE,SAAS,CAAC;AAAA,EAChG;AAEA,MAAI,UAAU,IAAI,SAAS,GAAG;AAE5B,QAAI,OAAO,UAAU;AACnB,UAAI,WAAW,OAAO;AACtB,UAAI,WAAW,SAAS;AAAA,IAC1B;AAAA,EACF;AAEA,MAAI,eAAe,IAAI,SAAS,GAAG;AAEjC,QAAI,OAAO,UAAU;AACnB,UAAI,WAAW,OAAO;AAAA,IACxB;AAAA,EACF;AACF;AAOA,MAAM,0BAE+C,CAAC,WAAW;AAC/D,QAAM,SAAS,EAAE,GAAG,OAAA;AAEpB,SAAO,OAAO;AACd,SAAO,OAAO;AAGd,SAAO,OAAO;AAEd,SAAO;AACT;AAEO,MAAM,kBAKqC,CAAC,WAAW,UAAU,IAAI,WAAW;AAOrF,QAAM,sBAAsB,SAAS,IAAI,SAAS;AAClD,MAAI,qBAAqB,IAAI;AAC3B,WAAO,EAAE,MAAMC,MAAAA,gBAAgB,oBAAoB,EAAE,EAAA;AAAA,EACvD;AAUA,QAAM,eAAe,IAAIC,kBAAA;AACzB,eAAa,IAAI,WAAW,EAAE,IAAI,gCAAgC;AAElE,QAAM;AAAA,IACJ,SAAS,EAAE,CAAC,8BAA8B,GAAG,OAAA;AAAA,EAAO,IAClDC,KAAAA,aAAa,cAAc;AAAA,IAC7B,GAAG;AAAA,IACH;AAAA,IACA,QAAQ,OAAO;AAAA,IACf,UAAU;AAAA,IACV,iBAAiB,OAAO,mBAAmB;AAAA,IAC3C,QAAQ;AAAA,IACR,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOR,KAAK,MAAM;AAAA,IACX,UAAU,OAAO,aAAa,CAAC,QAAQ,YAAY,KAAK,EAAE;AAAA,EAAA,CAC3D;AAED,QAAM,aAAa,wBAAwB,MAAM;AAKjD,SAAO,KAAK,MAAM,KAAK,UAAU,UAAU,GAAG,CAAC,OAAO,UAAU;AAC9D,QAAI,OAAO,UAAU,YAAY,MAAM,WAAW,sBAAsB,GAAG;AACzE,aAAOF,MAAAA,gBAAgB,MAAM,MAAM,uBAAuB,MAAM,CAAC;AAAA,IACnE;AACA,WAAO;AAAA,EACT,CAAC;AACH;AAEO,MAAM,oBAIgC,CAAC,UAAU,IAAI,WAAW;AACrE,QAAM,SAASE,KAAAA,aAAa,UAAU;AAAA,IACpC,GAAG;AAAA,IACH;AAAA,IACA,QAAQ,OAAO;AAAA,IACf,UAAU;AAAA,IACV,iBAAiB,OAAO,mBAAmB;AAAA,IAC3C,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,KAAK,CAAC,OAAOF,MAAAA,gBAAgB,EAAE;AAAA,IAC/B,UAAU,OAAO,aAAa,CAAC,QAAQ,YAAY,KAAK,EAAE;AAAA,EAAA,CAC3D,EAAE;AAEH,QAAM,cAAqD,CAAA;AAC3D,aAAW,MAAM,QAAQ;AACvB,gBAAY,EAAE,IAAI,wBAAwB,OAAO,EAAE,CAAC;AAAA,EACtD;AAEA,SAAO;AACT;;;"}
@@ -1,8 +1,8 @@
1
- import type { JSONSchema } from "zod/v4/core";
1
+ import type { JSONSchema, RegistryToJSONSchemaParams } from "zod/v4/core";
2
2
  import { $ZodRegistry, $ZodType } from "zod/v4/core";
3
- export declare const zodSchemaToJson: (zodSchema: $ZodType, registry: $ZodRegistry<{
4
- id?: string;
5
- }>, io: "input" | "output") => JSONSchema.BaseSchema;
6
- export declare const zodRegistryToJson: (registry: $ZodRegistry<{
7
- id?: string;
8
- }>, io: "input" | "output") => Record<string, JSONSchema.BaseSchema>;
3
+ import type { SchemaRegistryMeta } from "../cjs/registry.cjs";
4
+ export type ZodToJsonConfig = {} & Omit<RegistryToJSONSchemaParams, "io" | "metadata" | "cycles" | "reused" | "uri">;
5
+ declare const deleteInvalidProperties: (schema: JSONSchema.BaseSchema) => Omit<JSONSchema.BaseSchema, "id" | "$schema">;
6
+ export declare const zodSchemaToJson: (zodSchema: $ZodType, registry: $ZodRegistry<SchemaRegistryMeta>, io: "input" | "output", config: ZodToJsonConfig) => ReturnType<typeof deleteInvalidProperties>;
7
+ export declare const zodRegistryToJson: (registry: $ZodRegistry<SchemaRegistryMeta>, io: "input" | "output", config: ZodToJsonConfig) => Record<string, JSONSchema.BaseSchema>;
8
+ export {};