express-zod-api 24.5.0 → 25.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,7 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## Version 25
4
+
5
+ ### v25.0.0
6
+
7
+ - Supported Node.js versions: `^20.19.0 || ^22.12.0 || ^24.0.0`:
8
+ - The framework distribution is now ESM-only (finally);
9
+ - All the Node.js versions listed above support `require(ESM)` syntax;
10
+ - Supported `zod` version: `^4.0.0`;
11
+ - Changes to the `Middleware` class:
12
+ - When the `input` schema is not defined, the `input` argument of the `handler` method is now `unknown`;
13
+
3
14
  ## Version 24
4
15
 
16
+ ### v24.6.0
17
+
18
+ - Supporting `zod` versions `^3.25.35 || ^4.0.0`:
19
+ - If you use `zod@^4.0.0` then `import { z } from "zod"`;
20
+ - If you use `zod@^3.25.35` then keep `import { z } from "zod/v4"`;
21
+ - For more details, see the [Explanation of the versioning strategy](https://github.com/colinhacks/zod/issues/4371).
22
+
5
23
  ### v24.5.0
6
24
 
7
25
  - `openapi3-ts` version is `^4.5.0`;
package/README.md CHANGED
@@ -206,7 +206,7 @@ Learn how to make factories for [custom response](#response-customization) and b
206
206
 
207
207
  ```typescript
208
208
  import { defaultEndpointsFactory } from "express-zod-api";
209
- import { z } from "zod/v4";
209
+ import { z } from "zod";
210
210
 
211
211
  const helloWorldEndpoint = defaultEndpointsFactory.build({
212
212
  // method: "get" (default) or array ["get", "post", ...]
@@ -318,7 +318,7 @@ Inputs of middlewares are also available to endpoint handlers within `input`.
318
318
  Here is an example of the authentication middleware, that checks a `key` from input and `token` from headers:
319
319
 
320
320
  ```typescript
321
- import { z } from "zod/v4";
321
+ import { z } from "zod";
322
322
  import createHttpError from "http-errors";
323
323
  import { Middleware } from "express-zod-api";
324
324
 
@@ -448,7 +448,7 @@ You can implement additional validations within schemas using refinements.
448
448
  Validation errors are reported in a response with a status code `400`.
449
449
 
450
450
  ```typescript
451
- import { z } from "zod/v4";
451
+ import { z } from "zod";
452
452
  import { Middleware } from "express-zod-api";
453
453
 
454
454
  const nicknameConstraintMiddleware = new Middleware({
@@ -489,7 +489,7 @@ Since parameters of GET requests come in the form of strings, there is often a n
489
489
  arrays of numbers.
490
490
 
491
491
  ```typescript
492
- import { z } from "zod/v4";
492
+ import { z } from "zod";
493
493
 
494
494
  const getUserEndpoint = endpointsFactory.build({
495
495
  input: z.object({
@@ -520,7 +520,7 @@ Here is a recommended solution: it is important to use shallow transformations o
520
520
  ```ts
521
521
  import camelize from "camelize-ts";
522
522
  import snakify from "snakify-ts";
523
- import { z } from "zod/v4";
523
+ import { z } from "zod";
524
524
 
525
525
  const endpoint = endpointsFactory.build({
526
526
  input: z
@@ -573,7 +573,7 @@ provides your endpoint handler or middleware with a `Date`. It supports the foll
573
573
  format for the response transmission. Both schemas accept metadata as an argument. Consider the following example:
574
574
 
575
575
  ```typescript
576
- import { z } from "zod/v4";
576
+ import { z } from "zod";
577
577
  import { ez, defaultEndpointsFactory } from "express-zod-api";
578
578
 
579
579
  const updateUserEndpoint = defaultEndpointsFactory.build({
@@ -748,7 +748,7 @@ In a similar way you can enable request headers as the input source. This is an
748
748
 
749
749
  ```typescript
750
750
  import { createConfig, Middleware } from "express-zod-api";
751
- import { z } from "zod/v4";
751
+ import { z } from "zod";
752
752
 
753
753
  createConfig({
754
754
  inputSources: {
@@ -783,7 +783,7 @@ type DefaultResponse<OUT> =
783
783
  You can create your own result handler by using this example as a template:
784
784
 
785
785
  ```typescript
786
- import { z } from "zod/v4";
786
+ import { z } from "zod";
787
787
  import {
788
788
  ResultHandler,
789
789
  ensureHttpError,
@@ -908,7 +908,7 @@ which is `express.urlencoded()` by default. The request content type should be `
908
908
 
909
909
  ```ts
910
910
  import { defaultEndpointsFactory, ez } from "express-zod-api";
911
- import { z } from "zod/v4";
911
+ import { z } from "zod";
912
912
 
913
913
  export const submitFeedbackEndpoint = defaultEndpointsFactory.build({
914
914
  method: "post",
@@ -948,7 +948,7 @@ const config = createConfig({
948
948
  Then use `ez.upload()` schema for a corresponding property. The request content type must be `multipart/form-data`:
949
949
 
950
950
  ```typescript
951
- import { z } from "zod/v4";
951
+ import { z } from "zod";
952
952
  import { ez, defaultEndpointsFactory } from "express-zod-api";
953
953
 
954
954
  const fileUploadEndpoint = defaultEndpointsFactory.build({
@@ -1026,7 +1026,7 @@ from outputs of previous middlewares, if the one being tested somehow depends on
1026
1026
  either by `errorHandler` configured within given `configProps` or `defaultResultHandler`.
1027
1027
 
1028
1028
  ```typescript
1029
- import { z } from "zod/v4";
1029
+ import { z } from "zod";
1030
1030
  import { Middleware, testMiddleware } from "express-zod-api";
1031
1031
 
1032
1032
  const middleware = new Middleware({
@@ -1169,7 +1169,7 @@ You can also deprecate all routes the `Endpoint` assigned to by setting `Endpoin
1169
1169
 
1170
1170
  ```ts
1171
1171
  import { Routing, DependsOnMethod } from "express-zod-api";
1172
- import { z } from "zod/v4";
1172
+ import { z } from "zod";
1173
1173
 
1174
1174
  const someEndpoint = factory.build({
1175
1175
  deprecated: true, // deprecates all routes the endpoint assigned to
@@ -1194,7 +1194,7 @@ need to reuse a handling rule for multiple brands, use the exposed types `Depict
1194
1194
 
1195
1195
  ```ts
1196
1196
  import ts from "typescript";
1197
- import { z } from "zod/v4";
1197
+ import { z } from "zod";
1198
1198
  import {
1199
1199
  Documentation,
1200
1200
  Integration,
@@ -1351,7 +1351,7 @@ Client application can subscribe to the event stream using `EventSource` class i
1351
1351
  the implementation emitting the `time` event each second.
1352
1352
 
1353
1353
  ```typescript
1354
- import { z } from "zod/v4";
1354
+ import { z } from "zod";
1355
1355
  import { EventStreamFactory } from "express-zod-api";
1356
1356
  import { setTimeout } from "node:timers/promises";
1357
1357
 
@@ -1384,7 +1384,7 @@ in this case during development. You can achieve this verification by assigning
1384
1384
  reusing it in forced type of the output:
1385
1385
 
1386
1386
  ```typescript
1387
- import { z } from "zod/v4";
1387
+ import { z } from "zod";
1388
1388
 
1389
1389
  const output = z.object({
1390
1390
  anything: z.number(),
package/SECURITY.md CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  | Version | Code name | Release | Supported |
6
6
  | ------: | :------------ | :------ | :----------------: |
7
+ | 25.x.x | Sara | 08.2025 | :white_check_mark: |
7
8
  | 24.x.x | Ashley | 06.2025 | :white_check_mark: |
8
9
  | 23.x.x | Sonia | 04.2025 | :white_check_mark: |
9
10
  | 22.x.x | Tai | 01.2025 | :white_check_mark: |
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import * as zod_v4 from 'zod/v4';
2
- import { z } from 'zod/v4';
1
+ import * as zod from 'zod';
2
+ import { z } from 'zod';
3
3
  import * as zod_v4_core from 'zod/v4/core';
4
4
  import { $ZodTypeInternals, $ZodType, SomeType, $ZodDefaultInternals, $ZodDefault, $ZodShape, $ZodLooseShape, $ZodObjectConfig, $strip, $ZodObjectInternals, $ZodObject, JSONSchema } from 'zod/v4/core';
5
5
  import compression from 'compression';
@@ -46,7 +46,7 @@ declare module "zod/v4/core" {
46
46
  default?: unknown;
47
47
  }
48
48
  }
49
- declare module "zod/v4" {
49
+ declare module "zod" {
50
50
  interface ZodType<out Output = unknown, out Input = unknown, out Internals extends $ZodTypeInternals<Output, Input> = $ZodTypeInternals<Output, Input>> extends $ZodType<Output, Input, Internals> {
51
51
  /** @desc Alias for .meta({examples}), but argument is typed to ensure the correct placement for transformations */
52
52
  example(example: z.output<this>): this;
@@ -68,10 +68,11 @@ declare module "zod/v4" {
68
68
  declare const methods: ("delete" | "get" | "post" | "put" | "patch")[];
69
69
  type Method = (typeof methods)[number];
70
70
 
71
+ /** @since zod 3.25.61 output type fixed */
72
+ declare const emptySchema: z.ZodObject<{}, z.core.$strip>;
73
+ type EmptySchema = typeof emptySchema;
71
74
  /** @desc this type does not allow props assignment, but it works for reading them when merged with another interface */
72
75
  type EmptyObject = z.output<EmptySchema>;
73
- /** Avoiding z.ZodObject<Record<string, never>, $strip>, because its z.output<> is generic "object" (external issue) */
74
- type EmptySchema = z.ZodRecord<z.ZodString, z.ZodNever>;
75
76
  type FlatObject = Record<string, unknown>;
76
77
  /** @link https://stackoverflow.com/a/65492934 */
77
78
  type NoNever<T, F> = [T] extends [never] ? F : T;
@@ -155,6 +156,16 @@ declare class BuiltinLogger implements AbstractLogger {
155
156
  profile(options: ProfilerOptions): () => void;
156
157
  }
157
158
 
159
+ type Base$1 = object & {
160
+ [Symbol.iterator]?: never;
161
+ };
162
+ /** @desc The type allowed on the top level of Middlewares and Endpoints */
163
+ type IOSchema = z.ZodType<Base$1>;
164
+ /** EndpointsFactory schema extended type when adding a Middleware */
165
+ type Extension<Current extends IOSchema | undefined, Inc extends IOSchema | undefined> = Current extends IOSchema ? Inc extends IOSchema ? z.ZodIntersection<Current, Inc> : Current : Inc;
166
+ /** The Endpoint input schema type, condition wrapped into schema to make it z.output-compatible */
167
+ type FinalInputSchema<FIN extends IOSchema | undefined, BIN extends IOSchema> = z.ZodIntersection<FIN extends IOSchema ? FIN : BIN, BIN>;
168
+
158
169
  type LogicalOr<T> = {
159
170
  or: T[];
160
171
  };
@@ -260,12 +271,12 @@ declare abstract class AbstractMiddleware {
260
271
  logger: ActualLogger;
261
272
  }): Promise<FlatObject>;
262
273
  }
263
- declare class Middleware<OPT extends FlatObject, OUT extends FlatObject, SCO extends string, IN extends IOSchema = EmptySchema> extends AbstractMiddleware {
274
+ declare class Middleware<OPT extends FlatObject, OUT extends FlatObject, SCO extends string, IN extends IOSchema | undefined = undefined> extends AbstractMiddleware {
264
275
  #private;
265
276
  constructor({ input, security, handler, }: {
266
277
  /**
267
278
  * @desc Input schema of the Middleware, combining properties from all the enabled input sources
268
- * @default z.object({})
279
+ * @default undefined
269
280
  * @see defaultInputSources
270
281
  * */
271
282
  input?: IN;
@@ -290,13 +301,6 @@ declare class ExpressMiddleware<R extends Request, S extends Response, OUT exten
290
301
  });
291
302
  }
292
303
 
293
- type Base$1 = object & {
294
- [Symbol.iterator]?: never;
295
- };
296
- /** @desc The type allowed on the top level of Middlewares and Endpoints */
297
- type IOSchema = z.ZodType<Base$1>;
298
- type ConditionalIntersection<Current extends IOSchema | undefined, Inc extends IOSchema> = z.ZodIntersection<Current extends IOSchema ? Current : Inc, Inc>;
299
-
300
304
  declare class DependsOnMethod extends Routable {
301
305
  #private;
302
306
  constructor(endpoints: Partial<Record<Method, AbstractEndpoint>>);
@@ -559,7 +563,7 @@ interface ServerConfig extends CommonConfig {
559
563
  /**
560
564
  * @desc Custom JSON parser.
561
565
  * @default express.json()
562
- * @link https://expressjs.com/en/4x/api.html#express.json
566
+ * @link https://expressjs.com/en/5x/api.html#express.json
563
567
  * */
564
568
  jsonParser?: RequestHandler;
565
569
  /**
@@ -575,13 +579,13 @@ interface ServerConfig extends CommonConfig {
575
579
  /**
576
580
  * @desc Custom raw parser (assigns Buffer to request body)
577
581
  * @default express.raw()
578
- * @link https://expressjs.com/en/4x/api.html#express.raw
582
+ * @link https://expressjs.com/en/5x/api.html#express.raw
579
583
  * */
580
584
  rawParser?: RequestHandler;
581
585
  /**
582
586
  * @desc Custom parser for URL Encoded requests used for submitting HTML forms
583
587
  * @default express.urlencoded()
584
- * @link https://expressjs.com/en/4x/api.html#express.urlencoded
588
+ * @link https://expressjs.com/en/5x/api.html#express.urlencoded
585
589
  * */
586
590
  formParser?: RequestHandler;
587
591
  /**
@@ -613,7 +617,7 @@ interface BuildProps<IN extends IOSchema, OUT extends IOSchema | z.ZodVoid, MIN
613
617
  /** @desc The schema by which the returns of the Endpoint handler is validated */
614
618
  output: OUT;
615
619
  /** @desc The Endpoint handler receiving the validated inputs, returns of added Middlewares (options) and a logger */
616
- handler: Handler<z.output<ConditionalIntersection<MIN, IN>>, z.input<OUT>, OPT>;
620
+ handler: Handler<z.output<FinalInputSchema<MIN, IN>>, z.input<OUT>, OPT>;
617
621
  /** @desc The operation description for the generated Documentation */
618
622
  description?: string;
619
623
  /** @desc The operation summary for the generated Documentation (50 symbols max) */
@@ -642,18 +646,19 @@ interface BuildProps<IN extends IOSchema, OUT extends IOSchema | z.ZodVoid, MIN
642
646
  declare class EndpointsFactory<IN extends IOSchema | undefined = undefined, OUT extends FlatObject = EmptyObject, SCO extends string = string> {
643
647
  #private;
644
648
  protected resultHandler: AbstractResultHandler;
649
+ protected schema: IN;
645
650
  protected middlewares: AbstractMiddleware[];
646
651
  constructor(resultHandler: AbstractResultHandler);
647
- addMiddleware<AOUT extends FlatObject, ASCO extends string, AIN extends IOSchema = EmptySchema>(subject: Middleware<OUT, AOUT, ASCO, AIN> | ConstructorParameters<typeof Middleware<OUT, AOUT, ASCO, AIN>>[0]): EndpointsFactory<ConditionalIntersection<IN, AIN>, OUT & AOUT, SCO & ASCO>;
652
+ addMiddleware<AOUT extends FlatObject, ASCO extends string, AIN extends IOSchema | undefined = undefined>(subject: Middleware<OUT, AOUT, ASCO, AIN> | ConstructorParameters<typeof Middleware<OUT, AOUT, ASCO, AIN>>[0]): EndpointsFactory<Extension<IN, AIN>, OUT & AOUT, SCO & ASCO>;
648
653
  use: <R extends Request, S extends Response, AOUT extends FlatObject = Record<string, never>>(nativeMw: (request: R, response: S, next: express.NextFunction) => void | Promise<void>, params_1?: {
649
654
  provider?: ((request: R, response: S) => AOUT | Promise<AOUT>) | undefined;
650
655
  transformer?: (err: Error) => Error;
651
- } | undefined) => EndpointsFactory<IN, OUT & AOUT, SCO>;
652
- addExpressMiddleware<R extends Request, S extends Response, AOUT extends FlatObject = EmptyObject>(...params: ConstructorParameters<typeof ExpressMiddleware<R, S, AOUT>>): EndpointsFactory<IN, OUT & AOUT, SCO>;
653
- addOptions<AOUT extends FlatObject>(getOptions: () => Promise<AOUT>): EndpointsFactory<IN, OUT & AOUT, SCO>;
654
- build<BOUT extends IOSchema, BIN extends IOSchema = EmptySchema>({ input, output: outputSchema, operationId, scope, tag, method, ...rest }: BuildProps<BIN, BOUT, IN, OUT, SCO>): Endpoint<ConditionalIntersection<IN, BIN>, BOUT, OUT>;
656
+ } | undefined) => EndpointsFactory<Extension<IN, undefined>, OUT & AOUT, SCO>;
657
+ addExpressMiddleware<R extends Request, S extends Response, AOUT extends FlatObject = EmptyObject>(...params: ConstructorParameters<typeof ExpressMiddleware<R, S, AOUT>>): EndpointsFactory<Extension<IN, undefined>, OUT & AOUT, SCO>;
658
+ addOptions<AOUT extends FlatObject>(getOptions: () => Promise<AOUT>): EndpointsFactory<Extension<IN, undefined>, OUT & AOUT, SCO>;
659
+ build<BOUT extends IOSchema, BIN extends IOSchema = EmptySchema>({ input, output: outputSchema, operationId, scope, tag, method, ...rest }: BuildProps<BIN, BOUT, IN, OUT, SCO>): Endpoint<FinalInputSchema<IN, BIN>, BOUT, OUT>;
655
660
  /** @desc shorthand for returning {} while having output schema z.object({}) */
656
- buildVoid<BIN extends IOSchema = EmptySchema>({ handler, ...rest }: Omit<BuildProps<BIN, z.ZodVoid, IN, OUT, SCO>, "output">): Endpoint<ConditionalIntersection<IN, BIN>, z.ZodObject<{}, z.core.$strip>, OUT>;
661
+ buildVoid<BIN extends IOSchema = EmptySchema>({ handler, ...rest }: Omit<BuildProps<BIN, z.ZodVoid, IN, OUT, SCO>, "output">): Endpoint<FinalInputSchema<IN, BIN>, z.ZodObject<{}, z.core.$strip>, OUT>;
657
662
  }
658
663
  declare const defaultEndpointsFactory: EndpointsFactory<undefined, Record<string, never>, string>;
659
664
  /**
@@ -931,12 +936,12 @@ declare function raw(): Base;
931
936
  declare function raw<S extends $ZodShape>(extra: S): ReturnType<typeof extended<S>>;
932
937
 
933
938
  declare const ez: {
934
- dateIn: ({ examples, ...rest }?: Parameters<zod_v4.ZodString["meta"]>[0]) => zod_v4_core.$ZodBranded<zod_v4.ZodPipe<zod_v4.ZodPipe<zod_v4.ZodUnion<readonly [zod_v4.ZodISODate, zod_v4.ZodISODateTime, zod_v4.ZodISODateTime]>, zod_v4.ZodTransform<Date, string>>, zod_v4.ZodDate>, symbol>;
935
- dateOut: (meta?: Parameters<zod_v4.ZodString["meta"]>[0]) => zod_v4_core.$ZodBranded<zod_v4.ZodPipe<zod_v4.ZodDate, zod_v4.ZodTransform<string, Date>>, symbol>;
936
- form: <S extends zod_v4_core.$ZodShape>(base: S | zod_v4.ZodObject<S>) => zod_v4_core.$ZodBranded<zod_v4.ZodObject<S, zod_v4_core.$strip>, symbol>;
937
- upload: () => zod_v4_core.$ZodBranded<zod_v4.ZodCustom<express_fileupload.UploadedFile, express_fileupload.UploadedFile>, symbol>;
939
+ dateIn: ({ examples, ...rest }?: Parameters<zod.ZodString["meta"]>[0]) => zod_v4_core.$ZodBranded<zod.ZodPipe<zod.ZodPipe<zod.ZodUnion<readonly [zod.ZodISODate, zod.ZodISODateTime, zod.ZodISODateTime]>, zod.ZodTransform<Date, string>>, zod.ZodDate>, symbol>;
940
+ dateOut: (meta?: Parameters<zod.ZodString["meta"]>[0]) => zod_v4_core.$ZodBranded<zod.ZodPipe<zod.ZodDate, zod.ZodTransform<string, Date>>, symbol>;
941
+ form: <S extends zod_v4_core.$ZodShape>(base: S | zod.ZodObject<S>) => zod_v4_core.$ZodBranded<zod.ZodObject<S, zod_v4_core.$strip>, symbol>;
942
+ upload: () => zod_v4_core.$ZodBranded<zod.ZodCustom<express_fileupload.UploadedFile, express_fileupload.UploadedFile>, symbol>;
938
943
  raw: typeof raw;
939
- buffer: () => zod_v4_core.$ZodBranded<zod_v4.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>, symbol>;
944
+ buffer: () => zod_v4_core.$ZodBranded<zod.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>, symbol>;
940
945
  };
941
946
 
942
947
  export { type ApiResponse, type AppConfig, type BasicSecurity, type BearerSecurity, BuiltinLogger, type CommonConfig, type CookieSecurity, DependsOnMethod, type Depicter, Documentation, DocumentationError, EndpointsFactory, EventStreamFactory, type FlatObject, type HeaderSecurity, type IOSchema, type InputSecurity, InputValidationError, Integration, type LoggerOverrides, type Method, Middleware, MissingPeerError, type OAuth2Security, type OpenIdSecurity, OutputValidationError, type Producer, ResultHandler, type Routing, RoutingError, ServeStatic, type ServerConfig, type TagOverrides, arrayEndpointsFactory, arrayResultHandler, attachRouting, createConfig, createServer, defaultEndpointsFactory, defaultResultHandler, ensureHttpError, ez, getExamples, getMessageFromError, testEndpoint, testMiddleware };