Skip to content

Commit a8138fb

Browse files
authored
Merge branch 'master' into make-v26
2 parents da522b9 + b47ede2 commit a8138fb

10 files changed

Lines changed: 376 additions & 312 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@
2121

2222
## Version 25
2323

24+
### v25.4.1
25+
26+
- This patch fixes the issue for users facing `TypeError: .example is not a function`, but not using that method:
27+
- Some environments fail to load Zod plugin properly so that the usage of `ZodType::example()` (plugin method)
28+
internally by the framework itself could cause that error;
29+
- This version fixes the problem by replacing the usage of `.example()` with `globalRegistry.add()`;
30+
- The issue was found and reported by [@misha-z1nchuk](https://github.com/misha-z1nchuk).
31+
2432
### v25.4.0
2533

2634
- Feat: configurable query parser:

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ Therefore, many basic tasks can be accomplished faster and easier, in particular
8585

8686
These people contributed to the improvement of the framework by reporting bugs, making changes and suggesting ideas:
8787

88+
[<img src="https://github.com/misha-z1nchuk.png" alt="@misha-z1nchuk" width="50px" />](https://github.com/misha-z1nchuk)
8889
[<img src="https://github.com/GreaterTamarack.png" alt="@GreaterTamarack" width="50px" />](https://github.com/GreaterTamarack)
8990
[<img src="https://github.com/pepegc.png" alt="@pepegc" width="50px" />](https://github.com/pepegc)
9091
[<img src="https://github.com/MichaelHindley.png" alt="@MichaelHindley" width="50px" />](https://github.com/MichaelHindley)

eslint.config.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ const importConcerns = [
3030
})),
3131
];
3232

33+
const compatibilityConcerns = [
34+
{
35+
selector: "CallExpression > MemberExpression[property.name='example']",
36+
message: "avoid using example() method to operate without zod plugin",
37+
},
38+
];
39+
3340
const performanceConcerns = [
3441
{
3542
selector: "ImportDeclaration[source.value=/assert/]", // #2169
@@ -202,6 +209,7 @@ export default tsPlugin.config(
202209
"warn",
203210
...importConcerns,
204211
...performanceConcerns,
212+
...compatibilityConcerns,
205213
],
206214
},
207215
},

express-zod-api/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "express-zod-api",
3-
"version": "25.4.0",
3+
"version": "25.4.1",
44
"description": "A Typescript framework to help you get an API server up and running with I/O schema validation and custom middlewares in minutes.",
55
"license": "MIT",
66
"repository": {

express-zod-api/src/result-handler.ts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,16 @@ export class ResultHandler<
9494
}
9595
}
9696

97+
const defaultNegativeSchema = z.object({
98+
status: z.literal("error"),
99+
error: z.object({ message: z.string() }),
100+
});
101+
globalRegistry.add(defaultNegativeSchema, {
102+
examples: [
103+
{ status: "error", error: { message: "Sample error message" } },
104+
] satisfies z.output<typeof defaultNegativeSchema>[],
105+
});
106+
97107
export const defaultResultHandler = new ResultHandler({
98108
positive: (output) => {
99109
const responseSchema = z.object({
@@ -111,15 +121,7 @@ export const defaultResultHandler = new ResultHandler({
111121
}
112122
return responseSchema;
113123
},
114-
negative: z
115-
.object({
116-
status: z.literal("error"),
117-
error: z.object({ message: z.string() }),
118-
})
119-
.example({
120-
status: "error",
121-
error: { message: "Sample error message" },
122-
}),
124+
negative: defaultNegativeSchema,
123125
handler: ({ error, input, output, request, response, logger }) => {
124126
if (error) {
125127
const httpError = ensureHttpError(error);
@@ -138,6 +140,13 @@ export const defaultResultHandler = new ResultHandler({
138140
},
139141
});
140142

143+
const arrayNegativeSchema = z.string();
144+
globalRegistry.add(arrayNegativeSchema, {
145+
examples: ["Sample error message"] satisfies z.output<
146+
typeof arrayNegativeSchema
147+
>[],
148+
});
149+
141150
/**
142151
* @deprecated Resist the urge of using it: this handler is designed only to simplify the migration of legacy APIs.
143152
* @desc Responding with array is a bad practice keeping your endpoints from evolving without breaking changes.
@@ -170,10 +179,7 @@ export const arrayResultHandler = new ResultHandler({
170179
}
171180
return responseSchema;
172181
},
173-
negative: {
174-
schema: z.string().example("Sample error message"),
175-
mimeType: "text/plain",
176-
},
182+
negative: { schema: arrayNegativeSchema, mimeType: "text/plain" },
177183
handler: ({ response, output, error, logger, request, input }) => {
178184
if (error) {
179185
const httpError = ensureHttpError(error);

express-zod-api/tests/__snapshots__/env.spec.ts.snap

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,45 @@ exports[`Environment checks > Zod checks/refinements > Snapshot control 'ZodStri
215215
}
216216
`;
217217

218+
exports[`Environment checks > Zod imperfections > circular object schema has no sign of getter in its shape 1`] = `
219+
{
220+
"features": {
221+
"configurable": true,
222+
"enumerable": true,
223+
"value": {
224+
"$schema": "https://json-schema.org/draft/2020-12/schema",
225+
"items": {
226+
"additionalProperties": false,
227+
"properties": {
228+
"features": {
229+
"$ref": "#",
230+
},
231+
"name": {
232+
"type": "string",
233+
},
234+
},
235+
"required": [
236+
"name",
237+
"features",
238+
],
239+
"type": "object",
240+
},
241+
"type": "array",
242+
},
243+
"writable": true,
244+
},
245+
"name": {
246+
"configurable": true,
247+
"enumerable": true,
248+
"value": {
249+
"$schema": "https://json-schema.org/draft/2020-12/schema",
250+
"type": "string",
251+
},
252+
"writable": true,
253+
},
254+
}
255+
`;
256+
218257
exports[`Environment checks > Zod new features > input examples of transformations 1`] = `
219258
{
220259
"$schema": "https://json-schema.org/draft/2020-12/schema",

express-zod-api/tests/env.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,16 @@ describe("Environment checks", () => {
5050
expect(R.omit(["$schema"], json)).toEqual({});
5151
});
5252

53-
test("circular object schema has a getter since 4.0.15", () => {
53+
test("circular object schema has no sign of getter in its shape", () => {
5454
const schema = z.object({
5555
name: z.string(),
5656
get features() {
5757
return schema.array();
5858
},
5959
});
6060
expect(
61-
Object.getOwnPropertyDescriptors(schema._zod.def.shape).features,
62-
).toHaveProperty("get", expect.any(Function));
61+
Object.getOwnPropertyDescriptors(schema._zod.def.shape),
62+
).toMatchSnapshot();
6363
});
6464

6565
test("ZodError inequality", () => {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"eslint-plugin-prettier": "^5.4.1",
2525
"husky": "^9.0.5",
2626
"prettier": "3.6.2",
27-
"tsdown": "^0.15.0",
27+
"tsdown": "^0.15.3",
2828
"tsx": "^4.19.4",
2929
"typescript-eslint": "catalog:dev",
3030
"vitest": "^3.2.3"

0 commit comments

Comments
 (0)