diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index cf63786431..13bb0ed494 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -5,9 +5,9 @@ name: Node.js CI on: push: - branches: [ master, v21, v22, v23, v24 ] + branches: [ master, v25 ] pull_request: - branches: [ master, v21, v22, v23, v24 ] + branches: [ master, v25 ] jobs: build: diff --git a/CHANGELOG.md b/CHANGELOG.md index 389fc87bea..44bd713688 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Version 25 +### v25.6.3 + +- Limited Zod compatibility to `>=4.0.0 <4.4.0`: + - Zod 4.4.0 introduced a breaking change to how `brand` method works, making the current plugin approach incompatible; + - Supporting Zod 4.4+ requires a breaking change and will be addressed in v28. + ### v25.6.2 - Fixed performance regression since v24.0.0: diff --git a/example/example.documentation.yaml b/example/example.documentation.yaml index 9007949935..a6f729098f 100644 --- a/example/example.documentation.yaml +++ b/example/example.documentation.yaml @@ -132,10 +132,10 @@ paths: required: true description: PATCH /v1/user/:id Parameter schema: - examples: - - "1234567890" type: string minLength: 1 + examples: + - "1234567890" examples: example1: value: "1234567890" @@ -144,9 +144,9 @@ paths: required: true description: PATCH /v1/user/:id Parameter schema: + type: string examples: - "12" - type: string examples: example1: value: "12" @@ -158,15 +158,15 @@ paths: type: object properties: key: + type: string + minLength: 1 examples: - 1234-5678-90 + name: type: string minLength: 1 - name: examples: - John Doe - type: string - minLength: 1 birthday: description: the day of birth type: string @@ -205,9 +205,9 @@ paths: type: object properties: name: + type: string examples: - John Doe - type: string createdAt: description: account creation date type: string @@ -275,11 +275,11 @@ paths: type: object properties: name: + type: string + pattern: ^\w+ \w+$ description: first name and last name examples: - John Doe - type: string - pattern: ^\w+ \w+$ required: - name examples: diff --git a/express-zod-api/src/diagnostics.ts b/express-zod-api/src/diagnostics.ts index 024f4ffcfc..fc4e43d688 100644 --- a/express-zod-api/src/diagnostics.ts +++ b/express-zod-api/src/diagnostics.ts @@ -19,7 +19,7 @@ export class Diagnostics { public checkSchema(endpoint: AbstractEndpoint, ctx: FlatObject): void { if (this.#verifiedEndpoints.has(endpoint)) return; for (const dir of ["input", "output"] as const) { - const stack = [ + const stack: z.core.JSONSchema.BaseSchema[] = [ z.toJSONSchema(endpoint[`${dir}Schema`], { unrepresentable: "any" }), ]; while (stack.length > 0) { diff --git a/express-zod-api/tests/__snapshots__/documentation.spec.ts.snap b/express-zod-api/tests/__snapshots__/documentation.spec.ts.snap index 0b85b46fb1..bc5a3b1dbe 100644 --- a/express-zod-api/tests/__snapshots__/documentation.spec.ts.snap +++ b/express-zod-api/tests/__snapshots__/documentation.spec.ts.snap @@ -2072,6 +2072,8 @@ paths: const: only additionalProperties: type: boolean + required: + - only union: type: object propertyNames: @@ -2082,6 +2084,9 @@ paths: const: option2 additionalProperties: type: boolean + required: + - option1 + - option2 enum: type: object propertyNames: @@ -2091,6 +2096,9 @@ paths: - option2 additionalProperties: type: boolean + required: + - option1 + - option2 required: - simple - stringy @@ -3594,8 +3602,8 @@ paths: required: true description: GET /v1/getSomething Parameter schema: - deprecated: true type: string + deprecated: true responses: "200": description: GET /v1/getSomething Positive response @@ -3653,8 +3661,8 @@ paths: required: true description: HEAD /v1/getSomething Parameter schema: - deprecated: true type: string + deprecated: true responses: "200": description: HEAD /v1/getSomething Positive response @@ -3713,11 +3721,6 @@ paths: type: string const: success data: - examples: - - a: first - b: prefix_first - - a: second - b: prefix_second type: object properties: a: @@ -3728,6 +3731,11 @@ paths: - a - b additionalProperties: false + examples: + - a: first + b: prefix_first + - a: second + b: prefix_second required: - status - data @@ -3937,8 +3945,6 @@ paths: type: string const: success data: - examples: - - num: 123 type: object properties: num: @@ -3946,6 +3952,8 @@ paths: required: - num additionalProperties: false + examples: + - num: 123 required: - status - data @@ -4017,13 +4025,13 @@ paths: type: object properties: key: + type: string examples: - 1234-56789-01 - type: string str: + type: string examples: - test - type: string required: - key - str @@ -4048,9 +4056,9 @@ paths: type: object properties: num: + type: number examples: - 123 - type: number required: - num additionalProperties: false @@ -4141,8 +4149,6 @@ paths: type: string const: success data: - examples: - - numericStr: "123" type: object properties: numericStr: @@ -4150,6 +4156,8 @@ paths: required: - numericStr additionalProperties: false + examples: + - numericStr: "123" required: - status - data @@ -4258,8 +4266,6 @@ paths: type: string const: success data: - examples: - - numericStr: "123" type: object properties: numericStr: @@ -4267,6 +4273,8 @@ paths: required: - numericStr additionalProperties: false + examples: + - numericStr: "123" required: - status - data @@ -4336,9 +4344,9 @@ paths: required: true description: GET /v1/getSomething Parameter schema: + type: string examples: - "123" - type: string examples: example1: value: "123" @@ -4411,9 +4419,9 @@ paths: required: true description: HEAD /v1/getSomething Parameter schema: + type: string examples: - "123" - type: string examples: example1: value: "123" @@ -4455,9 +4463,9 @@ paths: type: object properties: strNum: + type: string examples: - "123" - type: string required: - strNum examples: @@ -4557,8 +4565,8 @@ paths: required: true description: here is the test schema: - description: here is the test type: string + description: here is the test responses: "200": description: GET /v1/getSomething Positive response @@ -4574,10 +4582,10 @@ paths: type: object properties: result: - description: some positive integer type: integer exclusiveMinimum: 0 maximum: 9007199254740991 + description: some positive integer required: - result additionalProperties: false @@ -4621,8 +4629,8 @@ paths: required: true description: here is the test schema: - description: here is the test type: string + description: here is the test responses: "200": description: HEAD /v1/getSomething Positive response diff --git a/express-zod-api/tests/__snapshots__/env.spec.ts.snap b/express-zod-api/tests/__snapshots__/env.spec.ts.snap index 3793ac2c9a..e0390176d1 100644 --- a/express-zod-api/tests/__snapshots__/env.spec.ts.snap +++ b/express-zod-api/tests/__snapshots__/env.spec.ts.snap @@ -23,6 +23,7 @@ exports[`Environment checks > Zod checks/refinements > Snapshot control 'ZodEmai ], "parse": [Function], "pattern": /\\^\\(\\?!\\\\\\.\\)\\(\\?!\\.\\*\\\\\\.\\\\\\.\\)\\(\\[A-Za-z0-9_'\\+\\\\-\\\\\\.\\]\\*\\)\\[A-Za-z0-9_\\+-\\]@\\(\\[A-Za-z0-9\\]\\[A-Za-z0-9\\\\-\\]\\*\\\\\\.\\)\\+\\[A-Za-z\\]\\{2,\\}\\$/, + "processJSONSchema": [Function], "run": [Function], "traits": Set { "ZodEmail", @@ -60,8 +61,13 @@ exports[`Environment checks > Zod checks/refinements > Snapshot control 'ZodNumb "type": "number", }, "deferred": [], + "parent": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "number", + }, "parse": [Function], "pattern": /\\^-\\?\\\\d\\+\\$/, + "processJSONSchema": [Function], "run": [Function], "traits": Set { "ZodNumber", @@ -94,6 +100,7 @@ exports[`Environment checks > Zod checks/refinements > Snapshot control 'ZodNumb ], "parse": [Function], "pattern": /\\^-\\?\\\\d\\+\\$/, + "processJSONSchema": [Function], "run": [Function], "traits": Set { "ZodNumberFormat", @@ -130,6 +137,7 @@ exports[`Environment checks > Zod checks/refinements > Snapshot control 'ZodNumb ], "parse": [Function], "pattern": /\\^-\\?\\\\d\\+\\$/, + "processJSONSchema": [Function], "run": [Function], "traits": Set { "ZodNumberFormat", @@ -167,8 +175,15 @@ exports[`Environment checks > Zod checks/refinements > Snapshot control 'ZodNumb "onattach": [ [Function], ], + "parent": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer", + }, "parse": [Function], "pattern": /\\^-\\?\\\\d\\+\\$/, + "processJSONSchema": [Function], "run": [Function], "traits": Set { "ZodNumberFormat", @@ -204,8 +219,13 @@ exports[`Environment checks > Zod checks/refinements > Snapshot control 'ZodStri "type": "string", }, "deferred": [], + "parent": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "string", + }, "parse": [Function], "pattern": /\\^\\(\\?!\\\\\\.\\)\\(\\?!\\.\\*\\\\\\.\\\\\\.\\)\\(\\[A-Za-z0-9_'\\+\\\\-\\\\\\.\\]\\*\\)\\[A-Za-z0-9_\\+-\\]@\\(\\[A-Za-z0-9\\]\\[A-Za-z0-9\\\\-\\]\\*\\\\\\.\\)\\+\\[A-Za-z\\]\\{2,\\}\\$/, + "processJSONSchema": [Function], "run": [Function], "traits": Set { "ZodString", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4c5276aa85..d4130d7fbc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,8 +46,8 @@ catalogs: specifier: ^8.46.1 version: 8.48.0 zod: - specifier: ^4.0.0 - version: 4.1.13 + specifier: ~4.3.4 + version: 4.3.6 prod: ramda: specifier: ^0.32.0 @@ -113,7 +113,7 @@ importers: version: 5.9.3 zod: specifier: catalog:dev - version: 4.1.13 + version: 4.3.6 compat-test: devDependencies: @@ -149,7 +149,7 @@ importers: version: link:../express-zod-api zod: specifier: catalog:dev - version: 4.1.13 + version: 4.3.6 example: devDependencies: @@ -176,7 +176,7 @@ importers: version: 5.9.3 zod: specifier: catalog:dev - version: 4.1.13 + version: 4.3.6 express-zod-api: dependencies: @@ -255,7 +255,7 @@ importers: version: 7.16.0 zod: specifier: catalog:dev - version: 4.1.13 + version: 4.3.6 issue952-test: dependencies: @@ -273,7 +273,7 @@ importers: version: 5.9.3 zod: specifier: catalog:dev - version: 4.1.13 + version: 4.3.6 migration: devDependencies: @@ -301,7 +301,7 @@ importers: version: 5.9.3 zod: specifier: catalog:dev - version: 4.1.13 + version: 4.3.6 packages: @@ -2306,8 +2306,8 @@ packages: zod@4.0.0: resolution: {integrity: sha512-9diLdTPc/L7w/5jI4C3gHYNiGHDV9IZYxo1e5LSD8cabi65WVTWWb+g2BGPEpUUCOxR4D+6O5B0AzyMdUAXwrw==} - zod@4.1.13: - resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==} + zod@4.3.6: + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} snapshots: @@ -4255,4 +4255,4 @@ snapshots: zod@4.0.0: {} - zod@4.1.13: {} + zod@4.3.6: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 1896bb2e0d..d53c12516a 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -48,7 +48,7 @@ catalogs: prod: "ramda": "^0.32.0" peer: - "zod": "^4.0.0" + "zod": ">=4.0.0 <4.4.0" dev: "@types/compression": "^1.8.1" "@types/express": "^5.0.3" @@ -63,6 +63,6 @@ catalogs: "http-errors": "^2.0.0" "typescript": "^5.9.2" "typescript-eslint": "^8.46.1" - "zod": "^4.0.0" + "zod": "~4.3.4" overrides: "@scarf/scarf": "npm:empty-npm-package@1.0.0" diff --git a/zod-plugin/CHANGELOG.md b/zod-plugin/CHANGELOG.md index 8e204219e4..ba240def35 100644 --- a/zod-plugin/CHANGELOG.md +++ b/zod-plugin/CHANGELOG.md @@ -2,6 +2,12 @@ ## Version 2 +### v2.1.1 + +- Limited compatibility to Zod versions `>=4.0.0 <4.4.0`: + - Zod 4.4.0 introduced a breaking change to how `brand` method works, making the current plugin approach incompatible; + - Support for Zod 4.4+ will be added in v5. + ### v2.1.0 - `ZodObject::remap()` now throws an `Error` if duplicate target keys found in its argument. diff --git a/zod-plugin/README.md b/zod-plugin/README.md index a181b59cd6..4e1856b9c7 100644 --- a/zod-plugin/README.md +++ b/zod-plugin/README.md @@ -18,7 +18,8 @@ This module extends Zod functionality when it's imported: ## Requirements -- Zod `^4.0.0` +- Compatible with Zod versions `>=4.0.0 <4.4.0`; +- Zod 4.4+ support will be available in v5. ## Basic usage