diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 4f5ec45e1f..e988dfc308 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, v24 ] pull_request: - branches: [ master, v21, v22, v23, v24 ] + branches: [ master, v24 ] jobs: build: diff --git a/CHANGELOG.md b/CHANGELOG.md index 45ea91e41b..a7339fd421 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Version 24 +### v24.7.6 + +- Limited Zod compatibility to `^3.25.35 || >=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. + ### v24.7.5 - Fixed performance regression in v24.0.0: diff --git a/example/example.documentation.yaml b/example/example.documentation.yaml index 488c0c473f..8c2741fc92 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/package.json b/express-zod-api/package.json index a4101a28a8..2ef5afc841 100644 --- a/express-zod-api/package.json +++ b/express-zod-api/package.json @@ -64,7 +64,7 @@ "express-fileupload": "^1.5.0", "http-errors": "^2.0.0", "typescript": "^5.1.3", - "zod": "^3.25.35 || ^4.0.0" + "zod": "^3.25.35 || >=4.0.0 <4.4.0" }, "peerDependenciesMeta": { "@types/compression": { diff --git a/express-zod-api/src/diagnostics.ts b/express-zod-api/src/diagnostics.ts index a0580c2c32..31d44dbed5 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 ef43dbf30f..ff32cdee69 100644 --- a/express-zod-api/tests/__snapshots__/documentation.spec.ts.snap +++ b/express-zod-api/tests/__snapshots__/documentation.spec.ts.snap @@ -853,7 +853,7 @@ paths: content: application/json: schema: - anyOf: + oneOf: - type: object properties: type: @@ -889,7 +889,7 @@ paths: type: string const: success data: - anyOf: + oneOf: - type: object properties: status: @@ -1834,7 +1834,7 @@ paths: uuid: type: string format: uuid - pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000)$ + pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$ cuid: type: string format: cuid @@ -2106,6 +2106,8 @@ paths: const: only additionalProperties: type: boolean + required: + - only union: type: object propertyNames: @@ -2116,6 +2118,9 @@ paths: const: option2 additionalProperties: type: boolean + required: + - option1 + - option2 enum: type: object propertyNames: @@ -2125,6 +2130,9 @@ paths: - option2 additionalProperties: type: boolean + required: + - option1 + - option2 required: - simple - stringy @@ -3628,8 +3636,8 @@ paths: required: true description: GET /v1/getSomething Parameter schema: - deprecated: true type: string + deprecated: true responses: "200": description: GET /v1/getSomething Positive response @@ -3687,8 +3695,8 @@ paths: required: true description: HEAD /v1/getSomething Parameter schema: - deprecated: true type: string + deprecated: true responses: "200": description: HEAD /v1/getSomething Positive response @@ -3747,11 +3755,6 @@ paths: type: string const: success data: - examples: - - a: first - b: prefix_first - - a: second - b: prefix_second type: object properties: a: @@ -3762,6 +3765,11 @@ paths: - a - b additionalProperties: false + examples: + - a: first + b: prefix_first + - a: second + b: prefix_second required: - status - data @@ -3971,8 +3979,6 @@ paths: type: string const: success data: - examples: - - num: 123 type: object properties: num: @@ -3980,6 +3986,8 @@ paths: required: - num additionalProperties: false + examples: + - num: 123 required: - status - data @@ -4051,13 +4059,13 @@ paths: type: object properties: key: + type: string examples: - 1234-56789-01 - type: string str: + type: string examples: - test - type: string required: - key - str @@ -4082,9 +4090,9 @@ paths: type: object properties: num: + type: number examples: - 123 - type: number required: - num additionalProperties: false @@ -4175,8 +4183,6 @@ paths: type: string const: success data: - examples: - - numericStr: "123" type: object properties: numericStr: @@ -4184,6 +4190,8 @@ paths: required: - numericStr additionalProperties: false + examples: + - numericStr: "123" required: - status - data @@ -4292,8 +4300,6 @@ paths: type: string const: success data: - examples: - - numericStr: "123" type: object properties: numericStr: @@ -4301,6 +4307,8 @@ paths: required: - numericStr additionalProperties: false + examples: + - numericStr: "123" required: - status - data @@ -4370,9 +4378,9 @@ paths: required: true description: GET /v1/getSomething Parameter schema: + type: string examples: - "123" - type: string examples: example1: value: "123" @@ -4445,9 +4453,9 @@ paths: required: true description: HEAD /v1/getSomething Parameter schema: + type: string examples: - "123" - type: string examples: example1: value: "123" @@ -4489,9 +4497,9 @@ paths: type: object properties: strNum: + type: string examples: - "123" - type: string required: - strNum examples: @@ -4591,8 +4599,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 @@ -4608,10 +4616,10 @@ paths: type: object properties: result: - description: some positive integer type: integer exclusiveMinimum: 0 maximum: 9007199254740991 + description: some positive integer required: - result additionalProperties: false @@ -4655,8 +4663,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 d2b97921a2..e0390176d1 100644 --- a/express-zod-api/tests/__snapshots__/env.spec.ts.snap +++ b/express-zod-api/tests/__snapshots__/env.spec.ts.snap @@ -20,10 +20,10 @@ exports[`Environment checks > Zod checks/refinements > Snapshot control 'ZodEmai "deferred": [], "onattach": [ [Function], - [Function], ], "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", @@ -46,7 +46,7 @@ exports[`Environment checks > Zod checks/refinements > Snapshot control 'ZodNumb "format": "safeint", "maximum": 9007199254740991, "minimum": -9007199254740991, - "pattern": /\\^\\\\d\\+\\$/, + "pattern": /\\^-\\?\\\\d\\+\\$/, }, "constr": [Function], "def": { @@ -61,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\\+\\$/, + "pattern": /\\^-\\?\\\\d\\+\\$/, + "processJSONSchema": [Function], "run": [Function], "traits": Set { "ZodNumber", @@ -79,7 +84,7 @@ exports[`Environment checks > Zod checks/refinements > Snapshot control 'ZodNumb "format": "safeint", "maximum": 9007199254740991, "minimum": -9007199254740991, - "pattern": /\\^\\\\d\\+\\$/, + "pattern": /\\^-\\?\\\\d\\+\\$/, }, "check": [Function], "constr": [Function], @@ -94,13 +99,15 @@ exports[`Environment checks > Zod checks/refinements > Snapshot control 'ZodNumb [Function], ], "parse": [Function], - "pattern": /\\^\\\\d\\+\\$/, + "pattern": /\\^-\\?\\\\d\\+\\$/, + "processJSONSchema": [Function], "run": [Function], "traits": Set { "ZodNumberFormat", - "$ZodNumber", + "$ZodNumberFormat", "$ZodCheckNumberFormat", "$ZodCheck", + "$ZodNumber", "$ZodType", "ZodNumber", "ZodType", @@ -114,7 +121,7 @@ exports[`Environment checks > Zod checks/refinements > Snapshot control 'ZodNumb "format": "int32", "maximum": 2147483647, "minimum": -2147483648, - "pattern": /\\^\\\\d\\+\\$/, + "pattern": /\\^-\\?\\\\d\\+\\$/, }, "check": [Function], "constr": [Function], @@ -129,13 +136,15 @@ exports[`Environment checks > Zod checks/refinements > Snapshot control 'ZodNumb [Function], ], "parse": [Function], - "pattern": /\\^\\\\d\\+\\$/, + "pattern": /\\^-\\?\\\\d\\+\\$/, + "processJSONSchema": [Function], "run": [Function], "traits": Set { "ZodNumberFormat", - "$ZodNumber", + "$ZodNumberFormat", "$ZodCheckNumberFormat", "$ZodCheck", + "$ZodNumber", "$ZodType", "ZodNumber", "ZodType", @@ -149,7 +158,7 @@ exports[`Environment checks > Zod checks/refinements > Snapshot control 'ZodNumb "format": "safeint", "maximum": 1000, "minimum": -9007199254740991, - "pattern": /\\^\\\\d\\+\\$/, + "pattern": /\\^-\\?\\\\d\\+\\$/, }, "check": [Function], "constr": [Function], @@ -166,14 +175,22 @@ 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\\+\\$/, + "pattern": /\\^-\\?\\\\d\\+\\$/, + "processJSONSchema": [Function], "run": [Function], "traits": Set { "ZodNumberFormat", - "$ZodNumber", + "$ZodNumberFormat", "$ZodCheckNumberFormat", "$ZodCheck", + "$ZodNumber", "$ZodType", "ZodNumber", "ZodType", @@ -202,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/express-zod-api/tests/__snapshots__/sse.spec.ts.snap b/express-zod-api/tests/__snapshots__/sse.spec.ts.snap index da063a7e22..6eede75bdc 100644 --- a/express-zod-api/tests/__snapshots__/sse.spec.ts.snap +++ b/express-zod-api/tests/__snapshots__/sse.spec.ts.snap @@ -37,7 +37,7 @@ exports[`SSE > makeResultHandler() > should create ResultHandler describing poss ], "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", - "anyOf": [ + "oneOf": [ { "additionalProperties": false, "properties": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fb4446eb17..82f3a3025d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -43,8 +43,8 @@ catalogs: specifier: ^6.19.8 version: 6.21.3 zod: - specifier: ^4.0.0 - version: 4.0.14 + specifier: ~4.3.4 + version: 4.3.6 overrides: '@scarf/scarf': npm:empty-npm-package@1.0.0 @@ -104,7 +104,7 @@ importers: version: link:../express-zod-api zod: specifier: catalog:dev - version: 4.0.14 + version: 4.3.6 compat-test: devDependencies: @@ -140,7 +140,7 @@ importers: version: link:../express-zod-api zod: specifier: catalog:dev - version: 4.0.14 + version: 4.3.6 example: devDependencies: @@ -167,7 +167,7 @@ importers: version: 6.21.3 zod: specifier: catalog:dev - version: 4.0.14 + version: 4.3.6 express-zod-api: dependencies: @@ -249,7 +249,7 @@ importers: version: 6.21.3 zod: specifier: catalog:dev - version: 4.0.14 + version: 4.3.6 issue952-test: dependencies: @@ -267,7 +267,7 @@ importers: version: 5.9.2 zod: specifier: catalog:dev - version: 4.0.14 + version: 4.3.6 migration: devDependencies: @@ -2380,8 +2380,8 @@ packages: zod@3.25.35: resolution: {integrity: sha512-Fe0Tz/mSbIraMd1/RR1jbtPMsrzX/SNwCmEpRqB0xB2YBnoRfQqyu4aIqWKWrx9C2XjF4SY47IVIt30+RVGSsw==} - zod@4.0.14: - resolution: {integrity: sha512-nGFJTnJN6cM2v9kXL+SOBq3AtjQby3Mv5ySGFof5UGRHrRioSJ5iG680cYNjE/yWk671nROcpPj4hAS8nyLhSw==} + zod@4.3.6: + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} snapshots: @@ -4507,4 +4507,4 @@ snapshots: zod@3.25.35: {} - zod@4.0.14: {} + zod@4.3.6: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 810845c85a..8639e1bef3 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -32,7 +32,7 @@ catalogs: "typescript": "^5.8.3" "typescript-eslint": "^8.35.1" "undici": "^6.19.8" - "zod": "^4.0.0" + "zod": "~4.3.4" overrides: "@scarf/scarf": "npm:empty-npm-package@1.0.0" "vite": "^6" # @todo remove in v25