express-zod-api 27.0.0 → 27.1.0
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 +37 -2
- package/README.md +86 -59
- package/dist/index.d.ts +128 -80
- package/dist/index.js +3 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,10 +2,45 @@
|
|
|
2
2
|
|
|
3
3
|
## Version 27
|
|
4
4
|
|
|
5
|
+
### v27.1.0
|
|
6
|
+
|
|
7
|
+
- Introducing `ez.paginated()` helper for creating paginated endpoints:
|
|
8
|
+
- The configurable helper returns `input` and `output` schemas for your Endpoint;
|
|
9
|
+
- Use the `style` option to choose between `offset` and `cursor` pagination;
|
|
10
|
+
- The `itemsName` option configures the name of the property containing the items array;
|
|
11
|
+
- The `Integration` generator now equips the `Client` with a static `hasMore()` method;
|
|
12
|
+
- The `Incremental` added to the list of well-known recognizable request headers.
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
import { ez, defaultEndpointsFactory } from "express-zod-api";
|
|
17
|
+
|
|
18
|
+
const pagination = ez.paginated({
|
|
19
|
+
style: "offset", // or "cursor"
|
|
20
|
+
itemSchema: z.object({ id: z.number(), name: z.string() }),
|
|
21
|
+
itemsName: "users", // defines the output name of the items array
|
|
22
|
+
maxLimit: 100,
|
|
23
|
+
defaultLimit: 20,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const listUsers = defaultEndpointsFactory.build({
|
|
27
|
+
input: pagination.input,
|
|
28
|
+
output: pagination.output,
|
|
29
|
+
handler: async ({ input: { limit, offset } }) => {
|
|
30
|
+
const { users, total } = await db.getUsers(limit, offset);
|
|
31
|
+
return { users, total, limit, offset }; // or { users, nextCursor, limit } for cursor pagination
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### v27.0.1
|
|
37
|
+
|
|
38
|
+
- Removed debug-level comments from the declaration files in the distribution.
|
|
39
|
+
|
|
5
40
|
### v27.0.0
|
|
6
41
|
|
|
7
42
|
- Supported `zod` versions: `^4.3.4`;
|
|
8
|
-
- The new version of Zod Plugin
|
|
43
|
+
- The new version of Zod Plugin uses the inheritable metadata feature of Zod 4.3;
|
|
9
44
|
- The `typescript` dependency is now optional and only required for making `Integration`:
|
|
10
45
|
- Either import and assign the `typescript` property to its constructor argument;
|
|
11
46
|
- Or use the new static async method `create()` to delegate the import;
|
|
@@ -2182,7 +2217,7 @@ const labeledDefaultSchema = withMeta(
|
|
|
2182
2217
|
capabilities, so that the user could subscribe to subsequent updates initiated by the server;
|
|
2183
2218
|
- Check out an [example of the synergy between two frameworks](https://github.com/RobinTail/zod-sockets#subscriptions)
|
|
2184
2219
|
and the [Demo Chat application](https://github.com/RobinTail/chat);
|
|
2185
|
-
- The feature suggested by [@
|
|
2220
|
+
- The feature suggested by [@uxduck](https://github.com/uxduck).
|
|
2186
2221
|
|
|
2187
2222
|
### v18.1.0
|
|
2188
2223
|
|
package/README.md
CHANGED
|
@@ -26,14 +26,15 @@ Start your API server with I/O schema validation and custom middlewares in minut
|
|
|
26
26
|
7. [Transformations](#transformations)
|
|
27
27
|
8. [Top level transformations and mapping](#top-level-transformations-and-mapping)
|
|
28
28
|
9. [Dealing with dates](#dealing-with-dates)
|
|
29
|
-
10. [
|
|
30
|
-
11. [
|
|
31
|
-
12. [Enabling
|
|
32
|
-
13. [
|
|
33
|
-
14. [
|
|
29
|
+
10. [Pagination](#pagination)
|
|
30
|
+
11. [Cross-Origin Resource Sharing](#cross-origin-resource-sharing) (CORS)
|
|
31
|
+
12. [Enabling HTTPS](#enabling-https)
|
|
32
|
+
13. [Enabling compression](#enabling-compression)
|
|
33
|
+
14. [Customizing logger](#customizing-logger)
|
|
34
|
+
15. [Child logger](#child-logger)
|
|
34
35
|
5. [Advanced features](#advanced-features)
|
|
35
36
|
1. [Customizing input sources](#customizing-input-sources)
|
|
36
|
-
2. [Headers as input source](#headers-as-input-source)
|
|
37
|
+
2. [Headers as input source](#headers-as-an-input-source)
|
|
37
38
|
3. [Response customization](#response-customization)
|
|
38
39
|
4. [Empty response](#empty-response)
|
|
39
40
|
5. [Non-JSON response](#non-json-response) including file downloads
|
|
@@ -46,8 +47,8 @@ Start your API server with I/O schema validation and custom middlewares in minut
|
|
|
46
47
|
12. [Testing middlewares](#testing-middlewares)
|
|
47
48
|
6. [Integration and Documentation](#integration-and-documentation)
|
|
48
49
|
1. [Zod Plugin](#zod-plugin)
|
|
49
|
-
2. [
|
|
50
|
-
3. [Creating
|
|
50
|
+
2. [End-to-End Type Safety](#end-to-end-type-safety)
|
|
51
|
+
3. [Creating documentation](#creating-documentation)
|
|
51
52
|
4. [Tagging the endpoints](#tagging-the-endpoints)
|
|
52
53
|
5. [Deprecated schemas and routes](#deprecated-schemas-and-routes)
|
|
53
54
|
6. [Customizable brands handling](#customizable-brands-handling)
|
|
@@ -66,9 +67,9 @@ See also [Changelog](CHANGELOG.md) and [automated migration](https://www.npmjs.c
|
|
|
66
67
|
|
|
67
68
|
# Overview
|
|
68
69
|
|
|
69
|
-
I made this framework because of the often repetitive tasks of starting
|
|
70
|
-
data. It integrates and provides the capabilities of popular web server, logging, validation and documenting solutions.
|
|
71
|
-
Therefore, many basic tasks can be
|
|
70
|
+
I made this framework because of the often repetitive tasks of starting web server APIs with the need to validate input
|
|
71
|
+
data. It integrates and provides the capabilities of popular web server, logging, validation, and documenting solutions.
|
|
72
|
+
Therefore, many basic tasks can be achieved faster and easier, in particular:
|
|
72
73
|
|
|
73
74
|
- You can describe web server routes as a hierarchical object.
|
|
74
75
|
- You can keep the endpoint's input and output type declarations right next to its handler.
|
|
@@ -76,14 +77,14 @@ Therefore, many basic tasks can be accomplished faster and easier, in particular
|
|
|
76
77
|
you expect a number.
|
|
77
78
|
- Variables within an endpoint handler have types according to the declared schema, so your IDE and TypeScript will
|
|
78
79
|
provide you with necessary hints to focus on bringing your vision to life.
|
|
79
|
-
- All of your endpoints can respond
|
|
80
|
-
- The expected endpoint input and response types can be exported to the frontend,
|
|
81
|
-
field names when you implement the client for your API.
|
|
80
|
+
- All of your endpoints can respond consistently.
|
|
81
|
+
- The expected endpoint input and response types can be exported to the frontend, giving you end-to-end type safety
|
|
82
|
+
so you don't get confused about the field names when you implement the client for your API.
|
|
82
83
|
- You can generate your API documentation in OpenAPI 3.1 and JSON Schema compatible format.
|
|
83
84
|
|
|
84
85
|
## Contributors
|
|
85
86
|
|
|
86
|
-
These people contributed to the improvement of the framework by reporting bugs, making changes and suggesting ideas:
|
|
87
|
+
These people contributed to the improvement of the framework by reporting bugs, making changes, and suggesting ideas:
|
|
87
88
|
|
|
88
89
|
[<img src="https://github.com/pycanis.png" alt="@pycanis" width="50" />](https://github.com/pycanis)
|
|
89
90
|
[<img src="https://github.com/arlyon.png" alt="@arlyon" width="50" />](https://github.com/arlyon)
|
|
@@ -116,7 +117,7 @@ These people contributed to the improvement of the framework by reporting bugs,
|
|
|
116
117
|
[<img src="https://github.com/rottmann.png" alt="@rottmann" width="50" />](https://github.com/rottmann)
|
|
117
118
|
[<img src="https://github.com/boarush.png" alt="@boarush" width="50" />](https://github.com/boarush)
|
|
118
119
|
[<img src="https://github.com/shawncarr.png" alt="@shawncarr" width="50" />](https://github.com/shawncarr)
|
|
119
|
-
[<img src="https://github.com/
|
|
120
|
+
[<img src="https://github.com/uxduck.png" alt="@uxduck" width="50" />](https://github.com/uxduck)
|
|
120
121
|
[<img src="https://github.com/daniel-white.png" alt="@daniel-white" width="50" />](https://github.com/daniel-white)
|
|
121
122
|
[<img src="https://github.com/kotsmile.png" alt="@kotsmile" width="50" />](https://github.com/kotsmile)
|
|
122
123
|
[<img src="https://github.com/elee1766.png" alt="@elee1766" width="50" />](https://github.com/elee1766)
|
|
@@ -164,7 +165,7 @@ Much can be customized to fit your needs.
|
|
|
164
165
|
- [Typescript](https://www.typescriptlang.org/) first.
|
|
165
166
|
- Web server — [Express.js](https://expressjs.com/) v5.
|
|
166
167
|
- Schema validation — [Zod 4.x](https://github.com/colinhacks/zod) including [Zod Plugin](#zod-plugin):
|
|
167
|
-
- For using with Zod 3.x install the framework versions below 24.0.0.
|
|
168
|
+
- For using with Zod 3.x, install the framework versions below 24.0.0.
|
|
168
169
|
- Supports any logger having `info()`, `debug()`, `error()` and `warn()` methods;
|
|
169
170
|
- Built-in console logger with colorful and pretty inspections by default.
|
|
170
171
|
- Generators:
|
|
@@ -320,7 +321,7 @@ const routing: Routing = {
|
|
|
320
321
|
};
|
|
321
322
|
```
|
|
322
323
|
|
|
323
|
-
|
|
324
|
+
The same Endpoint can be reused on different routes or handle multiple methods. Path parameters (the `:id` above)
|
|
324
325
|
should be declared in the endpoint’s input schema. Properties assigned with Endpoint can explicitly declare a method.
|
|
325
326
|
If no method is specified, the methods supported by the endpoint are used (or `get` as a fallback).
|
|
326
327
|
|
|
@@ -372,7 +373,7 @@ const yourEndpoint = defaultEndpointsFactory
|
|
|
372
373
|
|
|
373
374
|
You can create a new factory by connecting as many middlewares as you want — they will be executed in the specified
|
|
374
375
|
order for all the endpoints produced on that factory. You may also use a shorter inline syntax within the
|
|
375
|
-
`.addMiddleware()` method, and have access to the output of the previously executed middlewares in chain as `ctx`:
|
|
376
|
+
`.addMiddleware()` method, and have access to the output of the previously executed middlewares in a chain as `ctx`:
|
|
376
377
|
|
|
377
378
|
```ts
|
|
378
379
|
import { defaultEndpointsFactory } from "express-zod-api";
|
|
@@ -479,7 +480,7 @@ const nicknameConstraintMiddleware = new Middleware({
|
|
|
479
480
|
});
|
|
480
481
|
```
|
|
481
482
|
|
|
482
|
-
By the way, you can also refine the whole I/O object, for example in case you need a complex validation of its props.
|
|
483
|
+
By the way, you can also refine the whole I/O object, for example, in case you need a complex validation of its props.
|
|
483
484
|
|
|
484
485
|
```ts
|
|
485
486
|
const endpoint = endpointsFactory.build({
|
|
@@ -532,7 +533,7 @@ For some APIs it may be important that public interfaces such as query parameter
|
|
|
532
533
|
implementation itself requires camel case for internal naming. In order to facilitate interoperability between the
|
|
533
534
|
different naming standards you can `.transform()` the entire `input` schema into another object using a well-typed
|
|
534
535
|
mapping library, such as [camelize-ts](https://www.npmjs.com/package/camelize-ts). However, that approach would not be
|
|
535
|
-
enough for the `output` schema if you're also aiming to [generate
|
|
536
|
+
enough for the `output` schema if you're also aiming to [generate valid documentation](#creating-documentation),
|
|
536
537
|
because the transformations themselves do not contain schemas. Addressing this case, the framework offers the `.remap()`
|
|
537
538
|
method of the object schema, a part of the [Zod plugin](#zod-plugin), which under the hood, in addition to the
|
|
538
539
|
transformation, also `.pipe()` the transformed object into a new object schema.
|
|
@@ -575,7 +576,7 @@ in actual response by calling
|
|
|
575
576
|
which in turn calls
|
|
576
577
|
[toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString).
|
|
577
578
|
It is also impossible to transmit the `Date` in its original form to your endpoints within JSON. Therefore, there is
|
|
578
|
-
confusion with original method ~~z.date()~~ that is not recommended to use without transformations.
|
|
579
|
+
confusion with the original method ~~z.date()~~ that is not recommended to use without transformations.
|
|
579
580
|
|
|
580
581
|
In order to solve this problem, the framework provides two custom methods for dealing with dates: `ez.dateIn()` and
|
|
581
582
|
`ez.dateOut()` for using within input and output schemas accordingly.
|
|
@@ -612,6 +613,34 @@ const updateUserEndpoint = defaultEndpointsFactory.build({
|
|
|
612
613
|
});
|
|
613
614
|
```
|
|
614
615
|
|
|
616
|
+
## Pagination
|
|
617
|
+
|
|
618
|
+
Consider using `ez.paginated()` to get reusable `input` and `output` schemas for offset or cursor-based pagination.
|
|
619
|
+
Attach schemas to your endpoint and compose with other params (e.g. `.and(z.object({ ... }))`).
|
|
620
|
+
To check if more pages are available, use [Client::hasMore()](#end-to-end-type-safety).
|
|
621
|
+
|
|
622
|
+
```ts
|
|
623
|
+
import { z } from "zod";
|
|
624
|
+
import { ez, defaultEndpointsFactory } from "express-zod-api";
|
|
625
|
+
|
|
626
|
+
const pagination = ez.paginated({
|
|
627
|
+
style: "offset", // or "cursor"
|
|
628
|
+
itemSchema: z.object({ id: z.number(), name: z.string() }),
|
|
629
|
+
itemsName: "users", // defines the output name of the items array
|
|
630
|
+
maxLimit: 100,
|
|
631
|
+
defaultLimit: 20,
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
const listUsers = defaultEndpointsFactory.build({
|
|
635
|
+
input: pagination.input,
|
|
636
|
+
output: pagination.output,
|
|
637
|
+
handler: async ({ input: { limit, offset } }) => {
|
|
638
|
+
const { users, total } = await db.getUsers(limit, offset);
|
|
639
|
+
return { users, total, limit, offset }; // or { users, nextCursor, limit } for cursor pagination
|
|
640
|
+
},
|
|
641
|
+
});
|
|
642
|
+
```
|
|
643
|
+
|
|
615
644
|
## Cross-Origin Resource Sharing
|
|
616
645
|
|
|
617
646
|
You can enable your API for other domains using the corresponding configuration option `cors`. The value is required to
|
|
@@ -662,7 +691,7 @@ your API at [Let's Encrypt](https://letsencrypt.org/).
|
|
|
662
691
|
|
|
663
692
|
## Enabling compression
|
|
664
693
|
|
|
665
|
-
According to [Express.js best practices guide](https://expressjs.com/en/advanced/best-practice-performance.html)
|
|
694
|
+
According to [Express.js best practices guide](https://expressjs.com/en/advanced/best-practice-performance.html),
|
|
666
695
|
it might be a good idea to enable GZIP and Brotli compression for your API responses.
|
|
667
696
|
|
|
668
697
|
Install `compression` and `@types/compression`, and enable or configure compression:
|
|
@@ -676,7 +705,7 @@ const config = createConfig({
|
|
|
676
705
|
});
|
|
677
706
|
```
|
|
678
707
|
|
|
679
|
-
|
|
708
|
+
To receive a compressed response, the client should include the following header in the request:
|
|
680
709
|
`Accept-Encoding: br, gzip, deflate`. Only responses with compressible content types are subject to compression.
|
|
681
710
|
|
|
682
711
|
## Customizing logger
|
|
@@ -695,7 +724,7 @@ const config = createConfig({
|
|
|
695
724
|
```
|
|
696
725
|
|
|
697
726
|
You can also replace it with a one having at least the following methods: `info()`, `debug()`, `error()` and `warn()`.
|
|
698
|
-
Winston and Pino support is well
|
|
727
|
+
Winston and Pino support is well-known. Here is an example configuring `pino` logger with `pino-pretty` extension:
|
|
699
728
|
|
|
700
729
|
```ts
|
|
701
730
|
import pino, { Logger } from "pino";
|
|
@@ -759,11 +788,11 @@ createConfig({
|
|
|
759
788
|
});
|
|
760
789
|
```
|
|
761
790
|
|
|
762
|
-
## Headers as input source
|
|
791
|
+
## Headers as an input source
|
|
763
792
|
|
|
764
|
-
|
|
793
|
+
Similarly, you can enable request headers as the input source. This is an opt-in feature. Please note:
|
|
765
794
|
|
|
766
|
-
- consider giving `headers` the lowest priority among other `inputSources` to avoid
|
|
795
|
+
- consider giving `headers` the lowest priority among other `inputSources` to avoid overwriting;
|
|
767
796
|
- consider handling headers in `Middleware` and declaring them within `security` property to improve `Documentation`;
|
|
768
797
|
- the request headers acquired that way are always lowercase when describing their validation schemas.
|
|
769
798
|
|
|
@@ -840,8 +869,8 @@ const endpointsFactory = new EndpointsFactory(yourResultHandler);
|
|
|
840
869
|
|
|
841
870
|
## Empty response
|
|
842
871
|
|
|
843
|
-
For some REST APIs, empty responses are typical: with status code `204` (No Content) and redirects (302).
|
|
844
|
-
|
|
872
|
+
For some REST APIs, empty responses are typical: with status code `204` (No Content) and redirects (302). To describe
|
|
873
|
+
it, set the `mimeType` to `null` and `schema` to `z.never()`:
|
|
845
874
|
|
|
846
875
|
```ts
|
|
847
876
|
const resultHandler = new ResultHandler({
|
|
@@ -852,13 +881,13 @@ const resultHandler = new ResultHandler({
|
|
|
852
881
|
|
|
853
882
|
## Non-JSON response
|
|
854
883
|
|
|
855
|
-
To configure a non-JSON
|
|
884
|
+
To configure a non-JSON response (for example, to send an image file), you should specify its MIME type.
|
|
856
885
|
|
|
857
886
|
You can find two approaches to `EndpointsFactory` and `ResultHandler` implementation
|
|
858
887
|
[in this example](https://github.com/RobinTail/express-zod-api/blob/master/example/factories.ts).
|
|
859
888
|
One of them implements file streaming, in this case the endpoint just has to provide the filename.
|
|
860
889
|
The response schema can be `z.string()`, `z.base64()` or `ez.buffer()` to reflect the data accordingly in the
|
|
861
|
-
[generated documentation](#creating-
|
|
890
|
+
[generated documentation](#creating-documentation).
|
|
862
891
|
|
|
863
892
|
```ts
|
|
864
893
|
const fileStreamingEndpointsFactory = new EndpointsFactory(
|
|
@@ -906,7 +935,7 @@ Consider enabling production mode by setting `NODE_ENV` environment variable to
|
|
|
906
935
|
- Express activates some [performance optimizations](https://expressjs.com/en/advanced/best-practice-performance.html);
|
|
907
936
|
- Self-diagnosis for potential problems is disabled to ensure faster startup;
|
|
908
937
|
- The `defaultResultHandler`, `defaultEndpointsFactory` and `LastResortHandler` generalize server-side error messages
|
|
909
|
-
in negative responses
|
|
938
|
+
in negative responses to improve the security of your API by not disclosing the exact causes of errors:
|
|
910
939
|
- Throwing errors that have or imply `5XX` status codes become just `Internal Server Error` message in response;
|
|
911
940
|
- You can control that behavior by throwing errors using `createHttpError()` and using its `expose` option:
|
|
912
941
|
|
|
@@ -947,7 +976,7 @@ _Hint: for unlisted extra fields use the following syntax: `ez.form( z.object({}
|
|
|
947
976
|
|
|
948
977
|
Install the following additional packages: `express-fileupload` and `@types/express-fileupload`, and enable or
|
|
949
978
|
configure file uploads. Refer to [documentation](https://www.npmjs.com/package/express-fileupload#available-options) on
|
|
950
|
-
available options. The `limitHandler` option is replaced by the `limitError` one. You can also connect
|
|
979
|
+
available options. The `limitHandler` option is replaced by the `limitError` one. You can also connect additional
|
|
951
980
|
middleware for restricting the ability to upload using the `beforeUpload` option. So the configuration for the limited
|
|
952
981
|
and restricted upload might look this way:
|
|
953
982
|
|
|
@@ -1017,10 +1046,10 @@ then consider using the `beforeRouting` [option in config instead](#using-native
|
|
|
1017
1046
|
## Testing endpoints
|
|
1018
1047
|
|
|
1019
1048
|
The way to test endpoints is to mock the request, response, and logger objects, invoke the `execute()` method, and
|
|
1020
|
-
assert the expectations on status, headers and payload. The framework provides a special method `testEndpoint` that
|
|
1021
|
-
makes mocking easier. Under the hood, request and response
|
|
1022
|
-
[node-mocks-http](https://www.npmjs.com/package/node-mocks-http) library
|
|
1023
|
-
settings additional properties and asserting
|
|
1049
|
+
assert the expectations on status, headers, and payload. The framework provides a special method `testEndpoint` that
|
|
1050
|
+
makes mocking easier. Under the hood, the request and response objects are mocked using the
|
|
1051
|
+
[node-mocks-http](https://www.npmjs.com/package/node-mocks-http) library; therefore, you can use its API for
|
|
1052
|
+
settings additional properties and asserting expectations using the provided getters, such as `._getStatusCode()`.
|
|
1024
1053
|
|
|
1025
1054
|
```ts
|
|
1026
1055
|
import { testEndpoint } from "express-zod-api";
|
|
@@ -1074,10 +1103,11 @@ expect(output).toEqual({ collectedContext: ["prev"], testLength: 9 });
|
|
|
1074
1103
|
Express Zod API augments Zod using [Zod Plugin](https://www.npmjs.com/package/@express-zod-api/zod-plugin),
|
|
1075
1104
|
adding the runtime helpers the framework relies on.
|
|
1076
1105
|
|
|
1077
|
-
##
|
|
1106
|
+
## End-to-End Type Safety
|
|
1078
1107
|
|
|
1079
|
-
You can generate a TypeScript file containing the IO types of your API and a client for it
|
|
1080
|
-
`typescript` installed. Consider also installing `prettier`
|
|
1108
|
+
You can generate a TypeScript file containing the IO types of your API and a client for it, giving you end-to-end type
|
|
1109
|
+
safety between your API and frontend. Make sure you have `typescript` installed. Consider also installing `prettier`
|
|
1110
|
+
and using the async `printFormatted()` method.
|
|
1081
1111
|
|
|
1082
1112
|
```ts
|
|
1083
1113
|
import typescript from "typescript";
|
|
@@ -1107,7 +1137,7 @@ client.provide("post /v1/user/:id", { id: "10" }); // it also substitutes path p
|
|
|
1107
1137
|
new Subscription("get /v1/events/stream", {}).on("time", (time) => {}); // Server-sent events (SSE)
|
|
1108
1138
|
```
|
|
1109
1139
|
|
|
1110
|
-
## Creating
|
|
1140
|
+
## Creating documentation
|
|
1111
1141
|
|
|
1112
1142
|
You can generate the specification of your API and write it to a `.yaml` file, that can be used as the documentation:
|
|
1113
1143
|
|
|
@@ -1125,8 +1155,8 @@ const yamlString = new Documentation({
|
|
|
1125
1155
|
}).getSpecAsYaml();
|
|
1126
1156
|
```
|
|
1127
1157
|
|
|
1128
|
-
You can add descriptions and examples to your endpoints, their I/O schemas and their properties.
|
|
1129
|
-
|
|
1158
|
+
You can add descriptions and examples to your endpoints, their I/O schemas, and their properties. They will be included
|
|
1159
|
+
in the generated documentation of your API. Consider the following example:
|
|
1130
1160
|
|
|
1131
1161
|
```ts
|
|
1132
1162
|
import { defaultEndpointsFactory } from "express-zod-api";
|
|
@@ -1208,8 +1238,8 @@ const routing: Routing = {
|
|
|
1208
1238
|
|
|
1209
1239
|
You can customize handling rules for your schemas in Documentation and Integration. Use the `.brand()` method on your
|
|
1210
1240
|
schema to make it special and distinguishable for the framework in runtime. Using symbols is recommended for branding.
|
|
1211
|
-
After that
|
|
1212
|
-
|
|
1241
|
+
After that use the `brandHandling` feature of both constructors to declare your custom implementation. In case you need
|
|
1242
|
+
to reuse a handling rule for multiple brands, use the exposed types `Depicter` and `Producer`.
|
|
1213
1243
|
|
|
1214
1244
|
```ts
|
|
1215
1245
|
import ts from "typescript";
|
|
@@ -1251,7 +1281,7 @@ new Integration({
|
|
|
1251
1281
|
## Different responses for different status codes
|
|
1252
1282
|
|
|
1253
1283
|
In some special cases you may want the ResultHandler to respond slightly differently depending on the status code,
|
|
1254
|
-
for example if your API strictly follows REST standards. It may also be necessary to reflect this difference in the
|
|
1284
|
+
for example, if your API strictly follows REST standards. It may also be necessary to reflect this difference in the
|
|
1255
1285
|
generated Documentation. For that purpose, the constructor of `ResultHandler` accepts flexible declaration of possible
|
|
1256
1286
|
response schemas and their corresponding status codes.
|
|
1257
1287
|
|
|
@@ -1281,13 +1311,10 @@ new ResultHandler({
|
|
|
1281
1311
|
|
|
1282
1312
|
## Array response
|
|
1283
1313
|
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
The `arrayResultHandler` expects your endpoint to have `items` property in the `output` object schema. The array
|
|
1289
|
-
assigned to that property is used as the response. This approach also supports examples, as well as documentation and
|
|
1290
|
-
client generation. Check out [the example endpoint](/example/endpoints/list-users.ts) for more details.
|
|
1314
|
+
Responding with a bare array is not recommended for new APIs (it blocks backward‑compatible changes).
|
|
1315
|
+
For new endpoints, prefer [Pagination](#pagination). For migrating legacy APIs, use `arrayResultHandler` or
|
|
1316
|
+
`arrayEndpointsFactory`: the endpoint output must have an `items` array, which is sent as the response body.
|
|
1317
|
+
See the [bad](/example/endpoints/list-users.ts) and [good](/example/endpoints/list-users-paginated.ts) examples.
|
|
1291
1318
|
|
|
1292
1319
|
## Accepting raw data
|
|
1293
1320
|
|
|
@@ -1331,7 +1358,7 @@ doExpensiveOperation();
|
|
|
1331
1358
|
done(); // debug: expensive operation '555 milliseconds'
|
|
1332
1359
|
```
|
|
1333
1360
|
|
|
1334
|
-
You can also customize the profiler with your own formatter, chosen severity or even performance assessment function:
|
|
1361
|
+
You can also customize the profiler with your own formatter, chosen severity, or even performance assessment function:
|
|
1335
1362
|
|
|
1336
1363
|
```ts
|
|
1337
1364
|
logger.profile({
|
|
@@ -1363,10 +1390,10 @@ createConfig({
|
|
|
1363
1390
|
|
|
1364
1391
|
## Subscriptions
|
|
1365
1392
|
|
|
1366
|
-
If you want the user of a client application to be able to subscribe to
|
|
1367
|
-
consider [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) (SSE) feature.
|
|
1393
|
+
If you want the user of a client application to be able to subscribe to further updates initiated by the server,
|
|
1394
|
+
consider the [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) (SSE) feature.
|
|
1368
1395
|
Client application can subscribe to the event stream using `EventSource` class instance or the
|
|
1369
|
-
[instance of the generated](#
|
|
1396
|
+
[instance of the generated](#end-to-end-type-safety) `Subscription` class. The following example demonstrates
|
|
1370
1397
|
the implementation emitting the `time` event each second.
|
|
1371
1398
|
|
|
1372
1399
|
```ts
|
|
@@ -1400,7 +1427,7 @@ should be aware of them.
|
|
|
1400
1427
|
The schema validator removes excessive properties by default. However, TypeScript
|
|
1401
1428
|
[does not yet display errors](https://www.typescriptlang.org/docs/handbook/interfaces.html#excess-property-checks)
|
|
1402
1429
|
in this case during development. You can achieve this verification by assigning the output schema to a constant and
|
|
1403
|
-
reusing it in forced type of the output:
|
|
1430
|
+
reusing it in the forced type of the output:
|
|
1404
1431
|
|
|
1405
1432
|
```ts
|
|
1406
1433
|
const output = z.object({ anything: z.number() });
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import "@express-zod-api/zod-plugin";
|
|
2
|
-
import * as
|
|
2
|
+
import * as zod from "zod";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { HttpError } from "http-errors";
|
|
5
|
-
import "
|
|
6
|
-
import * as express0 from "express";
|
|
5
|
+
import * as express$1 from "express";
|
|
7
6
|
import express, { IRouter, NextFunction, Request, RequestHandler, Response } from "express";
|
|
8
7
|
import http from "node:http";
|
|
9
8
|
import https, { ServerOptions } from "node:https";
|
|
@@ -15,10 +14,9 @@ import * as express_fileupload0 from "express-fileupload";
|
|
|
15
14
|
import fileUpload from "express-fileupload";
|
|
16
15
|
import { ListenOptions } from "node:net";
|
|
17
16
|
import * as express_serve_static_core0 from "express-serve-static-core";
|
|
18
|
-
import * as
|
|
17
|
+
import * as qs from "qs";
|
|
19
18
|
import ts from "typescript";
|
|
20
19
|
import * as zod_v4_core0 from "zod/v4/core";
|
|
21
|
-
//#region src/method.d.ts
|
|
22
20
|
declare const methods: ("get" | "post" | "put" | "delete" | "patch")[];
|
|
23
21
|
declare const clientMethods: ("get" | "post" | "put" | "delete" | "patch" | "head")[];
|
|
24
22
|
/**
|
|
@@ -33,8 +31,6 @@ type Method = (typeof methods)[number];
|
|
|
33
31
|
* @example Method | "head"
|
|
34
32
|
* */
|
|
35
33
|
type ClientMethod = (typeof clientMethods)[number];
|
|
36
|
-
//#endregion
|
|
37
|
-
//#region src/api-response.d.ts
|
|
38
34
|
/** @public this is the user facing configuration */
|
|
39
35
|
interface ApiResponse<S extends z.ZodType> {
|
|
40
36
|
schema: S;
|
|
@@ -46,8 +42,6 @@ interface ApiResponse<S extends z.ZodType> {
|
|
|
46
42
|
* */
|
|
47
43
|
mimeType?: string | [string, ...string[]] | null;
|
|
48
44
|
}
|
|
49
|
-
//#endregion
|
|
50
|
-
//#region src/common-helpers.d.ts
|
|
51
45
|
/** @since zod 3.25.61 output type fixed */
|
|
52
46
|
declare const emptySchema: z.ZodObject<{}, z.core.$strip>;
|
|
53
47
|
type EmptySchema = typeof emptySchema;
|
|
@@ -64,8 +58,6 @@ type NoNever<T, F> = [T] extends [never] ? F : T;
|
|
|
64
58
|
interface TagOverrides {}
|
|
65
59
|
type Tag = NoNever<keyof TagOverrides, string>;
|
|
66
60
|
declare const getMessageFromError: (error: Error) => string;
|
|
67
|
-
//#endregion
|
|
68
|
-
//#region src/logger-helpers.d.ts
|
|
69
61
|
declare const severity: {
|
|
70
62
|
debug: number;
|
|
71
63
|
info: number;
|
|
@@ -82,8 +74,6 @@ type AbstractLogger = Record<Severity, (message: string, meta?: any) => any>;
|
|
|
82
74
|
* */
|
|
83
75
|
interface LoggerOverrides {}
|
|
84
76
|
type ActualLogger = AbstractLogger & LoggerOverrides;
|
|
85
|
-
//#endregion
|
|
86
|
-
//#region src/builtin-logger.d.ts
|
|
87
77
|
interface Context extends FlatObject {
|
|
88
78
|
requestId?: string;
|
|
89
79
|
}
|
|
@@ -135,8 +125,6 @@ declare class BuiltinLogger implements AbstractLogger {
|
|
|
135
125
|
profile(message: string): () => void;
|
|
136
126
|
profile(options: ProfilerOptions): () => void;
|
|
137
127
|
}
|
|
138
|
-
//#endregion
|
|
139
|
-
//#region src/io-schema.d.ts
|
|
140
128
|
type Base$1 = object & {
|
|
141
129
|
[Symbol.iterator]?: never;
|
|
142
130
|
};
|
|
@@ -153,8 +141,6 @@ type FinalInputSchema<FIN extends IOSchema | undefined, BIN extends IOSchema> =
|
|
|
153
141
|
FIN extends IOSchema ? FIN : BIN,
|
|
154
142
|
BIN
|
|
155
143
|
>;
|
|
156
|
-
//#endregion
|
|
157
|
-
//#region src/logical-container.d.ts
|
|
158
144
|
type LogicalOr<T> = {
|
|
159
145
|
or: T[];
|
|
160
146
|
};
|
|
@@ -162,8 +148,6 @@ type LogicalAnd<T> = {
|
|
|
162
148
|
and: T[];
|
|
163
149
|
};
|
|
164
150
|
type LogicalContainer<T> = LogicalOr<T | LogicalAnd<T>> | LogicalAnd<T | LogicalOr<T>> | T;
|
|
165
|
-
//#endregion
|
|
166
|
-
//#region src/security.d.ts
|
|
167
151
|
interface BasicSecurity {
|
|
168
152
|
type: "basic";
|
|
169
153
|
}
|
|
@@ -243,8 +227,6 @@ type Security<K extends string = string, S extends string = string> =
|
|
|
243
227
|
| CookieSecurity
|
|
244
228
|
| OpenIdSecurity
|
|
245
229
|
| OAuth2Security<S>;
|
|
246
|
-
//#endregion
|
|
247
|
-
//#region src/middleware.d.ts
|
|
248
230
|
type Handler$2<IN, CTX, RET> = (params: {
|
|
249
231
|
/** @desc The inputs from the enabled input sources validated against the input schema of the Middleware */
|
|
250
232
|
input: IN;
|
|
@@ -320,8 +302,6 @@ declare class ExpressMiddleware<R extends Request, S extends Response, RET exten
|
|
|
320
302
|
},
|
|
321
303
|
);
|
|
322
304
|
}
|
|
323
|
-
//#endregion
|
|
324
|
-
//#region src/result-helpers.d.ts
|
|
325
305
|
type ResultSchema<R extends Result> = R extends Result<infer S> ? S : never;
|
|
326
306
|
type DiscriminatedResult =
|
|
327
307
|
| {
|
|
@@ -337,8 +317,6 @@ type DiscriminatedResult =
|
|
|
337
317
|
* @example Error —> InternalServerError(500)
|
|
338
318
|
* */
|
|
339
319
|
declare const ensureHttpError: (error: Error) => HttpError;
|
|
340
|
-
//#endregion
|
|
341
|
-
//#region src/result-handler.d.ts
|
|
342
320
|
type Handler$1<RES = unknown> = (
|
|
343
321
|
params: DiscriminatedResult & {
|
|
344
322
|
/** null in case of failure to parse or to find the matching endpoint (error: not found) */
|
|
@@ -401,19 +379,13 @@ declare const arrayResultHandler: ResultHandler<
|
|
|
401
379
|
mimeType: string;
|
|
402
380
|
}
|
|
403
381
|
>;
|
|
404
|
-
//#endregion
|
|
405
|
-
//#region src/serve-static.d.ts
|
|
406
382
|
type OriginalStatic = typeof express.static;
|
|
407
383
|
declare class ServeStatic {
|
|
408
384
|
#private;
|
|
409
385
|
constructor(...params: Parameters<OriginalStatic>);
|
|
410
386
|
}
|
|
411
|
-
//#endregion
|
|
412
|
-
//#region src/server-helpers.d.ts
|
|
413
387
|
/** @desc Returns child logger for the given request (if configured) or the configured logger otherwise */
|
|
414
388
|
type GetLogger = (request?: Request) => ActualLogger;
|
|
415
|
-
//#endregion
|
|
416
|
-
//#region src/routing.d.ts
|
|
417
389
|
/**
|
|
418
390
|
* @example { v1: { books: { ":bookId": getBookEndpoint } } }
|
|
419
391
|
* @example { "v1/books/:bookId": getBookEndpoint }
|
|
@@ -425,8 +397,6 @@ type GetLogger = (request?: Request) => ActualLogger;
|
|
|
425
397
|
interface Routing {
|
|
426
398
|
[K: string]: Routing | AbstractEndpoint | ServeStatic;
|
|
427
399
|
}
|
|
428
|
-
//#endregion
|
|
429
|
-
//#region src/endpoint.d.ts
|
|
430
400
|
type Handler<IN, OUT, CTX> = (params: {
|
|
431
401
|
/** @desc The inputs from the enabled input sources validated against the final input schema (incl. Middlewares) */
|
|
432
402
|
input: IN;
|
|
@@ -476,8 +446,6 @@ declare class Endpoint<IN extends IOSchema, OUT extends IOSchema, CTX extends Fl
|
|
|
476
446
|
config: CommonConfig;
|
|
477
447
|
}): Promise<undefined>;
|
|
478
448
|
}
|
|
479
|
-
//#endregion
|
|
480
|
-
//#region src/config-type.d.ts
|
|
481
449
|
type InputSource = keyof Pick<Request, "query" | "body" | "files" | "params" | "headers">;
|
|
482
450
|
type InputSources = Record<Method, InputSource[]>;
|
|
483
451
|
type Headers = Record<string, string>;
|
|
@@ -671,8 +639,6 @@ interface AppConfig extends CommonConfig {
|
|
|
671
639
|
}
|
|
672
640
|
declare function createConfig(config: ServerConfig): ServerConfig;
|
|
673
641
|
declare function createConfig(config: AppConfig): AppConfig;
|
|
674
|
-
//#endregion
|
|
675
|
-
//#region src/endpoints-factory.d.ts
|
|
676
642
|
interface BuildProps<
|
|
677
643
|
IN extends IOSchema,
|
|
678
644
|
OUT extends IOSchema | z.ZodVoid,
|
|
@@ -728,7 +694,7 @@ declare class EndpointsFactory<
|
|
|
728
694
|
subject: Middleware<CTX, RET, ASCO, AIN> | ConstructorParameters<typeof Middleware<CTX, RET, ASCO, AIN>>[0],
|
|
729
695
|
): EndpointsFactory<Extension<IN, AIN>, (CTX extends Record<string, never> ? RET : CTX) & RET, SCO & ASCO>;
|
|
730
696
|
use: <R extends Request, S extends Response, AOUT extends FlatObject = Record<string, never>>(
|
|
731
|
-
nativeMw: (request: R, response: S, next:
|
|
697
|
+
nativeMw: (request: R, response: S, next: express$1.NextFunction) => any,
|
|
732
698
|
params_1?:
|
|
733
699
|
| {
|
|
734
700
|
provider?: ((request: R, response: S) => AOUT | Promise<AOUT>) | undefined;
|
|
@@ -768,8 +734,6 @@ declare const defaultEndpointsFactory: EndpointsFactory<undefined, Record<string
|
|
|
768
734
|
* @desc The result handler of this factory expects your endpoint to have the property 'items' in the output schema
|
|
769
735
|
*/
|
|
770
736
|
declare const arrayEndpointsFactory: EndpointsFactory<undefined, Record<string, never>, string>;
|
|
771
|
-
//#endregion
|
|
772
|
-
//#region src/server.d.ts
|
|
773
737
|
declare const attachRouting: (
|
|
774
738
|
config: AppConfig,
|
|
775
739
|
routing: Routing,
|
|
@@ -778,7 +742,7 @@ declare const attachRouting: (
|
|
|
778
742
|
express_serve_static_core0.ParamsDictionary,
|
|
779
743
|
any,
|
|
780
744
|
any,
|
|
781
|
-
|
|
745
|
+
qs.ParsedQs,
|
|
782
746
|
Record<string, any>
|
|
783
747
|
>;
|
|
784
748
|
logger: AbstractLogger | BuiltinLogger;
|
|
@@ -794,8 +758,6 @@ declare const createServer: (
|
|
|
794
758
|
| https.Server<typeof http.IncomingMessage, typeof http.ServerResponse>
|
|
795
759
|
)[];
|
|
796
760
|
}>;
|
|
797
|
-
//#endregion
|
|
798
|
-
//#region src/documentation-helpers.d.ts
|
|
799
761
|
interface ReqResCommons {
|
|
800
762
|
makeRef: (key: object | string, value: SchemaObject | ReferenceObject, proposedName?: string) => ReferenceObject;
|
|
801
763
|
path: string;
|
|
@@ -826,8 +788,6 @@ declare const depictTags: (
|
|
|
826
788
|
>
|
|
827
789
|
>,
|
|
828
790
|
) => TagObject[];
|
|
829
|
-
//#endregion
|
|
830
|
-
//#region src/documentation.d.ts
|
|
831
791
|
type Component = "positiveResponse" | "negativeResponse" | "requestParameter" | "requestBody";
|
|
832
792
|
/** @desc user defined function that creates a component description from its properties */
|
|
833
793
|
type Descriptor = (
|
|
@@ -894,8 +854,6 @@ declare class Documentation extends OpenApiBuilder {
|
|
|
894
854
|
composition,
|
|
895
855
|
}: DocumentationParams);
|
|
896
856
|
}
|
|
897
|
-
//#endregion
|
|
898
|
-
//#region src/errors.d.ts
|
|
899
857
|
/** @desc An error related to the wrong Routing declaration */
|
|
900
858
|
declare class RoutingError extends Error {
|
|
901
859
|
name: string;
|
|
@@ -933,8 +891,6 @@ declare class MissingPeerError extends Error {
|
|
|
933
891
|
name: string;
|
|
934
892
|
constructor(module: string);
|
|
935
893
|
}
|
|
936
|
-
//#endregion
|
|
937
|
-
//#region src/testing.d.ts
|
|
938
894
|
interface TestingProps<REQ, LOG> {
|
|
939
895
|
/**
|
|
940
896
|
* @desc Additional properties to set on Request mock
|
|
@@ -965,7 +921,7 @@ declare const testEndpoint: <LOG extends FlatObject, REQ extends RequestOptions>
|
|
|
965
921
|
endpoint: AbstractEndpoint;
|
|
966
922
|
}) => Promise<{
|
|
967
923
|
requestMock: node_mocks_http0.MockRequest<
|
|
968
|
-
Request<express_serve_static_core0.ParamsDictionary, any, any,
|
|
924
|
+
Request<express_serve_static_core0.ParamsDictionary, any, any, qs.ParsedQs, Record<string, any>> & REQ
|
|
969
925
|
>;
|
|
970
926
|
responseMock: node_mocks_http0.MockResponse<Response<any, Record<string, any>>>;
|
|
971
927
|
loggerMock: AbstractLogger &
|
|
@@ -984,7 +940,7 @@ declare const testMiddleware: <LOG extends FlatObject, REQ extends RequestOption
|
|
|
984
940
|
ctx?: FlatObject;
|
|
985
941
|
}) => Promise<{
|
|
986
942
|
requestMock: node_mocks_http0.MockRequest<
|
|
987
|
-
Request<express_serve_static_core0.ParamsDictionary, any, any,
|
|
943
|
+
Request<express_serve_static_core0.ParamsDictionary, any, any, qs.ParsedQs, Record<string, any>> & REQ
|
|
988
944
|
>;
|
|
989
945
|
responseMock: node_mocks_http0.MockResponse<Response<any, Record<string, any>>>;
|
|
990
946
|
loggerMock: AbstractLogger &
|
|
@@ -993,15 +949,11 @@ declare const testMiddleware: <LOG extends FlatObject, REQ extends RequestOption
|
|
|
993
949
|
};
|
|
994
950
|
output: FlatObject;
|
|
995
951
|
}>;
|
|
996
|
-
//#endregion
|
|
997
|
-
//#region src/integration-base.d.ts
|
|
998
952
|
declare abstract class IntegrationBase {
|
|
999
953
|
#private;
|
|
1000
954
|
protected readonly serverUrl: string;
|
|
1001
955
|
protected constructor(typescript: typeof ts, serverUrl: string);
|
|
1002
956
|
}
|
|
1003
|
-
//#endregion
|
|
1004
|
-
//#region src/schema-walker.d.ts
|
|
1005
957
|
interface NextHandlerInc<U> {
|
|
1006
958
|
next: (schema: z.core.$ZodType) => U;
|
|
1007
959
|
}
|
|
@@ -1019,15 +971,11 @@ type SchemaHandler<
|
|
|
1019
971
|
type HandlingRules<U, Context extends FlatObject = EmptyObject, K extends string | symbol = string | symbol> = Partial<
|
|
1020
972
|
Record<K, SchemaHandler<U, Context>>
|
|
1021
973
|
>;
|
|
1022
|
-
//#endregion
|
|
1023
|
-
//#region src/zts-helpers.d.ts
|
|
1024
974
|
interface ZTSContext extends FlatObject {
|
|
1025
975
|
isResponse: boolean;
|
|
1026
976
|
makeAlias: (key: object, produce: () => ts.TypeNode) => ts.TypeNode;
|
|
1027
977
|
}
|
|
1028
978
|
type Producer = SchemaHandler<ts.TypeNode, ZTSContext>;
|
|
1029
|
-
//#endregion
|
|
1030
|
-
//#region src/integration.d.ts
|
|
1031
979
|
interface IntegrationParams {
|
|
1032
980
|
typescript: typeof ts;
|
|
1033
981
|
routing: Routing;
|
|
@@ -1093,8 +1041,6 @@ declare class Integration extends IntegrationBase {
|
|
|
1093
1041
|
print(printerOptions?: ts.PrinterOptions): string;
|
|
1094
1042
|
printFormatted({ printerOptions, format: userDefined }?: FormattedPrintingOptions): Promise<string>;
|
|
1095
1043
|
}
|
|
1096
|
-
//#endregion
|
|
1097
|
-
//#region src/sse.d.ts
|
|
1098
1044
|
type EventsMap = Record<string, z.ZodType>;
|
|
1099
1045
|
interface Emitter<E extends EventsMap> extends FlatObject {
|
|
1100
1046
|
/** @desc Returns true when the connection was closed or terminated */
|
|
@@ -1107,18 +1053,122 @@ interface Emitter<E extends EventsMap> extends FlatObject {
|
|
|
1107
1053
|
declare class EventStreamFactory<E extends EventsMap> extends EndpointsFactory<undefined, Emitter<E>> {
|
|
1108
1054
|
constructor(events: E);
|
|
1109
1055
|
}
|
|
1110
|
-
//#endregion
|
|
1111
|
-
//#region src/date-in-schema.d.ts
|
|
1112
1056
|
interface DateInParams extends Omit<Parameters<z.ZodString["meta"]>[0], "examples"> {
|
|
1113
1057
|
examples?: string[];
|
|
1114
1058
|
}
|
|
1115
|
-
//#endregion
|
|
1116
|
-
//#region src/date-out-schema.d.ts
|
|
1117
1059
|
interface DateOutParams extends Omit<Parameters<z.ZodString["meta"]>[0], "examples"> {
|
|
1118
1060
|
examples?: string[];
|
|
1119
1061
|
}
|
|
1120
|
-
|
|
1121
|
-
|
|
1062
|
+
declare const DEFAULT_ITEMS_NAME: "items";
|
|
1063
|
+
/** @desc Common pagination config: shared by offset and cursor styles. */
|
|
1064
|
+
interface CommonPaginationConfig<T extends z.ZodType = z.ZodType, K extends string = typeof DEFAULT_ITEMS_NAME> {
|
|
1065
|
+
/** @desc Zod schema for each item in the paginated list. */
|
|
1066
|
+
itemSchema: T;
|
|
1067
|
+
/**
|
|
1068
|
+
* @desc The name of the property containing the list of items.
|
|
1069
|
+
* @default "items"
|
|
1070
|
+
* */
|
|
1071
|
+
itemsName?: K;
|
|
1072
|
+
/**
|
|
1073
|
+
* @desc Maximum allowed page size (client request is capped to this).
|
|
1074
|
+
* @default 100
|
|
1075
|
+
*/
|
|
1076
|
+
maxLimit?: number;
|
|
1077
|
+
/**
|
|
1078
|
+
* @desc Default page size when the client omits the limit parameter.
|
|
1079
|
+
* @default 20
|
|
1080
|
+
*/
|
|
1081
|
+
defaultLimit?: number;
|
|
1082
|
+
}
|
|
1083
|
+
/**
|
|
1084
|
+
* @desc Configuration for offset-based pagination (limit and offset).
|
|
1085
|
+
* @example { style: "offset", itemSchema, maxLimit: 50, defaultLimit: 10 }
|
|
1086
|
+
*/
|
|
1087
|
+
interface OffsetPaginatedConfig<
|
|
1088
|
+
T extends z.ZodType = z.ZodType,
|
|
1089
|
+
K extends string = typeof DEFAULT_ITEMS_NAME,
|
|
1090
|
+
> extends CommonPaginationConfig<T, K> {
|
|
1091
|
+
/** @desc Discriminator for offset-style pagination. */
|
|
1092
|
+
style: "offset";
|
|
1093
|
+
}
|
|
1094
|
+
/**
|
|
1095
|
+
* @desc Configuration for cursor-based pagination (cursor and limit).
|
|
1096
|
+
* @example { style: "cursor", itemSchema, maxLimit: 50, defaultLimit: 10 }
|
|
1097
|
+
*/
|
|
1098
|
+
interface CursorPaginatedConfig<
|
|
1099
|
+
T extends z.ZodType = z.ZodType,
|
|
1100
|
+
K extends string = typeof DEFAULT_ITEMS_NAME,
|
|
1101
|
+
> extends CommonPaginationConfig<T, K> {
|
|
1102
|
+
/** @desc Discriminator for cursor-style pagination. */
|
|
1103
|
+
style: "cursor";
|
|
1104
|
+
}
|
|
1105
|
+
/** @desc Request params for offset pagination. */
|
|
1106
|
+
type OffsetInput = z.ZodObject<{
|
|
1107
|
+
/** @desc Page size (number of items per page). */
|
|
1108
|
+
limit: z.ZodDefault<z.ZodCoercedNumber>;
|
|
1109
|
+
/** @desc Number of items to skip from the start of the list. */
|
|
1110
|
+
offset: z.ZodDefault<z.ZodCoercedNumber>;
|
|
1111
|
+
}>;
|
|
1112
|
+
/** @desc Request params for cursor pagination. */
|
|
1113
|
+
type CursorInput = z.ZodObject<{
|
|
1114
|
+
/** @desc Opaque cursor for the next page; omit for the first page. */
|
|
1115
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
1116
|
+
/** @desc Page size (number of items per page). */
|
|
1117
|
+
limit: z.ZodDefault<z.ZodCoercedNumber>;
|
|
1118
|
+
}>;
|
|
1119
|
+
/** @desc Response shape for offset pagination. */
|
|
1120
|
+
type OffsetOutput<T extends z.ZodType, K extends string> = z.ZodObject<
|
|
1121
|
+
{ [ITEMS in K]: z.ZodArray<T> } & {
|
|
1122
|
+
/** @desc Total number of items across all pages. */
|
|
1123
|
+
total: z.ZodNumber;
|
|
1124
|
+
/** @desc Page size used for this response. */
|
|
1125
|
+
limit: z.ZodNumber;
|
|
1126
|
+
/** @desc Offset used for this response. */
|
|
1127
|
+
offset: z.ZodNumber;
|
|
1128
|
+
}
|
|
1129
|
+
>;
|
|
1130
|
+
/** @desc Response shape for cursor pagination. */
|
|
1131
|
+
type CursorOutput<T extends z.ZodType, K extends string> = z.ZodObject<
|
|
1132
|
+
{ [ITEMS in K]: z.ZodArray<T> } & {
|
|
1133
|
+
/** @desc Cursor for the next page, or null if there are no more pages. */
|
|
1134
|
+
nextCursor: z.ZodNullable<z.ZodString>;
|
|
1135
|
+
/** @desc Page size used for this response. */
|
|
1136
|
+
limit: z.ZodNumber;
|
|
1137
|
+
}
|
|
1138
|
+
>;
|
|
1139
|
+
/** @desc Return type of ez.paginated() for offset style. */
|
|
1140
|
+
interface OffsetPaginatedResult<T extends z.ZodType = z.ZodType, K extends string = typeof DEFAULT_ITEMS_NAME> {
|
|
1141
|
+
/** @desc Zod schema for offset pagination request params. */
|
|
1142
|
+
input: OffsetInput;
|
|
1143
|
+
/** @desc Zod schema for offset pagination response. */
|
|
1144
|
+
output: OffsetOutput<T, K>;
|
|
1145
|
+
}
|
|
1146
|
+
/** @desc Return type of ez.paginated() for cursor style. */
|
|
1147
|
+
interface CursorPaginatedResult<T extends z.ZodType = z.ZodType, K extends string = typeof DEFAULT_ITEMS_NAME> {
|
|
1148
|
+
/** @desc Zod schema for cursor pagination request params. */
|
|
1149
|
+
input: CursorInput;
|
|
1150
|
+
/** @desc Zod schema for cursor pagination response. */
|
|
1151
|
+
output: CursorOutput<T, K>;
|
|
1152
|
+
}
|
|
1153
|
+
/**
|
|
1154
|
+
* @desc Creates a pagination helper with a single config for both request params and response shape.
|
|
1155
|
+
* Use the returned `.input` as the endpoint input schema and `.output` as the response schema.
|
|
1156
|
+
* Compose with other params via `.input.and(z.object({ ... }))`.
|
|
1157
|
+
*
|
|
1158
|
+
* @param config - Pagination config; `style` discriminates offset vs cursor; `itemSchema` defines each list item.
|
|
1159
|
+
* @returns Object with `input` (Zod schema for pagination params) and `output` (Zod schema for paginated response).
|
|
1160
|
+
*
|
|
1161
|
+
* @example
|
|
1162
|
+
* const pagination = ez.paginated({ style: "offset", maxLimit: 100, defaultLimit: 20, itemSchema: userSchema });
|
|
1163
|
+
* endpoint.input = pagination.input.and(z.object({ ... }));
|
|
1164
|
+
* endpoint.output = pagination.output;
|
|
1165
|
+
*/
|
|
1166
|
+
declare function paginated<T extends z.ZodType, K extends string = typeof DEFAULT_ITEMS_NAME>(
|
|
1167
|
+
config: OffsetPaginatedConfig<T, K>,
|
|
1168
|
+
): OffsetPaginatedResult<T, K>;
|
|
1169
|
+
declare function paginated<T extends z.ZodType, K extends string = typeof DEFAULT_ITEMS_NAME>(
|
|
1170
|
+
config: CursorPaginatedConfig<T, K>,
|
|
1171
|
+
): CursorPaginatedResult<T, K>;
|
|
1122
1172
|
declare const base: z.ZodObject<
|
|
1123
1173
|
{
|
|
1124
1174
|
raw: z.core.$ZodBranded<z.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>, symbol, "out">;
|
|
@@ -1150,42 +1200,40 @@ declare const extended: <S extends z.core.$ZodShape>(
|
|
|
1150
1200
|
>;
|
|
1151
1201
|
declare function raw(): Base;
|
|
1152
1202
|
declare function raw<S extends z.core.$ZodShape>(extra: S): ReturnType<typeof extended<S>>;
|
|
1153
|
-
//#endregion
|
|
1154
|
-
//#region src/proprietary-schemas.d.ts
|
|
1155
1203
|
declare const ez: {
|
|
1156
1204
|
dateIn: ({
|
|
1157
1205
|
examples,
|
|
1158
1206
|
...rest
|
|
1159
1207
|
}?: DateInParams) => zod_v4_core0.$ZodBranded<
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1208
|
+
zod.ZodPipe<
|
|
1209
|
+
zod.ZodPipe<
|
|
1210
|
+
zod.ZodUnion<readonly [zod.ZodISODate, zod.ZodISODateTime, zod.ZodISODateTime]>,
|
|
1211
|
+
zod.ZodTransform<Date, string>
|
|
1164
1212
|
>,
|
|
1165
|
-
|
|
1213
|
+
zod.ZodDate
|
|
1166
1214
|
>,
|
|
1167
1215
|
symbol,
|
|
1168
1216
|
"out"
|
|
1169
1217
|
>;
|
|
1170
1218
|
dateOut: (
|
|
1171
1219
|
meta?: DateOutParams,
|
|
1172
|
-
) => zod_v4_core0.$ZodBranded<
|
|
1220
|
+
) => zod_v4_core0.$ZodBranded<zod.ZodPipe<zod.ZodDate, zod.ZodTransform<string, Date>>, symbol, "out">;
|
|
1173
1221
|
form: <S extends zod_v4_core0.$ZodShape>(
|
|
1174
|
-
base: S |
|
|
1175
|
-
) => zod_v4_core0.$ZodBranded<
|
|
1222
|
+
base: S | zod.ZodObject<S>,
|
|
1223
|
+
) => zod_v4_core0.$ZodBranded<zod.ZodObject<S, zod_v4_core0.$strip>, symbol, "out">;
|
|
1176
1224
|
upload: () => zod_v4_core0.$ZodBranded<
|
|
1177
|
-
|
|
1225
|
+
zod.ZodCustom<express_fileupload0.UploadedFile, express_fileupload0.UploadedFile>,
|
|
1178
1226
|
symbol,
|
|
1179
1227
|
"out"
|
|
1180
1228
|
>;
|
|
1181
1229
|
raw: typeof raw;
|
|
1182
1230
|
buffer: () => zod_v4_core0.$ZodBranded<
|
|
1183
|
-
|
|
1231
|
+
zod.ZodCustom<Buffer<ArrayBufferLike>, Buffer<ArrayBufferLike>>,
|
|
1184
1232
|
symbol,
|
|
1185
1233
|
"out"
|
|
1186
1234
|
>;
|
|
1235
|
+
paginated: typeof paginated;
|
|
1187
1236
|
};
|
|
1188
|
-
//#endregion
|
|
1189
1237
|
export {
|
|
1190
1238
|
type ApiResponse,
|
|
1191
1239
|
type AppConfig,
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
import{getBrand as e}from"@express-zod-api/zod-plugin";import*as t from"ramda";import{globalRegistry as n,z as r}from"zod";import i,{isHttpError as a}from"http-errors";import o,{blue as s,cyanBright as c,gray as l,green as u,hex as d,italic as f,red as p,whiteBright as m}from"ansis";import{inspect as h}from"node:util";import{performance as g}from"node:perf_hooks";import _ from"express";import ee from"node:http";import v from"node:https";import{setInterval as te}from"node:timers/promises";import{OpenApiBuilder as ne,isReferenceObject as re,isSchemaObject as y}from"openapi3-ts/oas31";import{createRequest as ie,createResponse as ae}from"node-mocks-http";function oe(e){return e}const b={json:`application/json`,upload:`multipart/form-data`,raw:`application/octet-stream`,sse:`text/event-stream`,form:`application/x-www-form-urlencoded`},se=[`get`,`post`,`put`,`delete`,`patch`],ce=[...se,`head`],x=e=>se.includes(e),le=r.object({}),ue=/:([A-Za-z0-9_]+)/g,de=e=>e.match(ue)?.map(e=>e.slice(1))||[],fe=e=>{let t=(e.header(`content-type`)||``).toLowerCase().startsWith(b.upload);return`files`in e&&t},pe={get:[`query`,`params`],post:[`body`,`params`,`files`],put:[`body`,`params`],patch:[`body`,`params`],delete:[`query`,`params`]},me=[`body`,`query`,`params`],he=e=>e.method.toLowerCase(),ge=(e,t={})=>{if(e===`options`)return[];let n=e===`head`?`get`:x(e)?e:void 0;return(n?t[n]||pe[n]:void 0)||me},_e=(e,t={})=>ge(he(e),t).filter(t=>t===`files`?fe(e):!0).reduce((t,n)=>Object.assign(t,e[n]),{}),S=e=>e instanceof Error?e:e instanceof r.ZodError?new r.ZodRealError(e.issues):Error(String(e)),C=e=>e instanceof r.ZodError?e.issues.map(({path:e,message:t})=>`${e.length?`${r.core.toDotPath(e)}: `:``}${t}`).join(`; `):e.message,w=(e,n)=>D(e)&&`_zod`in e&&(n?t.path([`_zod`,`def`,`type`],e)===n:!0),T=(e,n,r)=>e.length&&n.length?t.xprod(e,n).map(r):e.concat(n),ve=e=>e.charAt(0).toUpperCase()+e.slice(1).toLowerCase(),E=(...e)=>{let n=t.chain(e=>e.split(/[^A-Z0-9]/gi),e);return t.chain(e=>e.replaceAll(/[A-Z]+/g,e=>`/${e}`).split(`/`),n).map(ve).join(``)},ye=t.tryCatch((e,t)=>typeof r.parse(e,t),t.always(void 0)),D=e=>typeof e==`object`&&!!e,be=t.memoizeWith(()=>`static`,()=>process.env.NODE_ENV===`production`),xe=(e,t)=>!!t&&e!==`head`,O=Symbol(`Buffer`),Se=()=>r.custom(e=>Buffer.isBuffer(e),{error:`Expected Buffer`}).brand(O),k=Symbol(`DateIn`),Ce=({examples:e,...t}={})=>r.union([r.iso.date(),r.iso.datetime(),r.iso.datetime({local:!0})]).meta({examples:e}).transform(e=>new Date(e)).pipe(r.date()).brand(k).meta(t),A=Symbol(`DateOut`),we=(e={})=>r.date().transform(e=>e.toISOString()).brand(A).meta(e);var j=class extends Error{name=`RoutingError`;cause;constructor(e,t,n){super(e),this.cause={method:t,path:n}}},M=class extends Error{name=`DocumentationError`;cause;constructor(e,{method:t,path:n,isResponse:r}){super(e),this.cause=`${r?`Response`:`Input`} schema of an Endpoint assigned to ${t.toUpperCase()} method of ${n} path.`}},Te=class extends Error{name=`IOSchemaError`},Ee=class extends Te{name=`DeepCheckError`;constructor(e){super(`Found`,{cause:e}),this.cause=e}},De=class extends Te{name=`OutputValidationError`;constructor(e){let t=new r.ZodError(e.issues.map(({path:e,...t})=>({...t,path:[`output`,...e]})));super(C(t),{cause:e}),this.cause=e}},N=class extends Te{name=`InputValidationError`;constructor(e){super(C(e),{cause:e}),this.cause=e}},Oe=class extends Error{name=`ResultHandlerError`;constructor(e,t){super(C(e),{cause:e}),this.cause=e,this.handled=t}},ke=class extends Error{name=`MissingPeerError`;constructor(e){super(`Missing peer dependency: ${e}. Please install it to use the feature.`)}};const Ae=Symbol(`Form`),je=e=>(e instanceof r.ZodObject?e:r.object(e)).brand(Ae),P=Symbol(`Upload`),Me=()=>r.custom(e=>typeof e==`object`&&!!e&&`name`in e&&`encoding`in e&&`mimetype`in e&&`data`in e&&`tempFilePath`in e&&`truncated`in e&&`size`in e&&`md5`in e&&`mv`in e&&typeof e.name==`string`&&typeof e.encoding==`string`&&typeof e.mimetype==`string`&&Buffer.isBuffer(e.data)&&typeof e.tempFilePath==`string`&&typeof e.truncated==`boolean`&&typeof e.size==`number`&&typeof e.md5==`string`&&typeof e.mv==`function`,{error:({input:e})=>({message:`Expected file upload, received ${typeof e}`})}).brand(P),F=Symbol(`Raw`),Ne=r.object({raw:Se()}),Pe=e=>Ne.extend(e).brand(F);function Fe(e){return e?Pe(e):Ne.brand(F)}const Ie=(e,{io:n,condition:i})=>t.tryCatch(()=>void r.toJSONSchema(e,{io:n,unrepresentable:`any`,override:({zodSchema:e})=>{if(i(e))throw new Ee(e)}}),e=>e.cause)(),Le=(e,{io:n})=>{let i=[r.toJSONSchema(e,{io:n,unrepresentable:`any`})];for(;i.length;){let e=i.shift();if(t.is(Object,e)){if(e.$ref===`#`)return!0;i.push(...t.values(e))}t.is(Array,e)&&i.push(...t.values(e))}return!1},Re=t=>Ie(t,{condition:t=>{let n=e(t);return typeof n==`symbol`&&[P,F,Ae].includes(n)},io:`input`}),ze=[`nan`,`symbol`,`map`,`set`,`bigint`,`void`,`promise`,`never`,`function`],Be=(t,n)=>Ie(t,{io:n,condition:t=>{let r=e(t),{type:i}=t._zod.def;return!!(ze.includes(i)||r===O||n===`input`&&(i===`date`||r===A)||n===`output`&&(r===k||r===F||r===P))}}),Ve=(e,{variant:t,args:n,...i})=>{if(typeof e==`function`&&(e=e(...n)),e instanceof r.ZodType)return[{schema:e,...i}];if(Array.isArray(e)&&!e.length)throw new Oe(Error(`At least one ${t} response schema required.`));return(Array.isArray(e)?e:[e]).map(({schema:e,statusCode:t,mimeType:n})=>({schema:e,statusCodes:typeof t==`number`?[t]:t||i.statusCodes,mimeTypes:typeof n==`string`?[n]:n===void 0?i.mimeTypes:n}))},He=(e,t,{url:n},r)=>!e.expose&&t.error(`Server side error`,{error:e,url:n,payload:r}),I=e=>a(e)?e:i(e instanceof N?400:500,C(e),{cause:e.cause||e}),L=e=>be()&&!e.expose?i(e.statusCode).message:e.message,Ue=e=>Object.entries(e._zod.def.shape).reduce((e,[r,i])=>{let{examples:a=[]}=n.get(i)||{};return T(e,a.map(t.objOf(r)),([e,t])=>({...e,...t}))},[]),We=({error:e,logger:t,response:n})=>{t.error(`Result handler failure`,e);let r=L(i(500,`An error occurred while serving the result: ${e.message}.`+(e.handled?`\nOriginal error: ${e.handled.message}.`:``),{expose:a(e.cause)?e.cause.expose:!1}));n.status(500).type(`text/plain`).end(r)};var Ge=class{},R=class extends Ge{#e;#t;#n;constructor({input:e,security:t,handler:n}){super(),this.#e=e,this.#t=t,this.#n=n}get security(){return this.#t}get schema(){return this.#e}async execute({input:e,...t}){try{let n=await(this.#e||le).parseAsync(e);return this.#n({...t,input:n})}catch(e){throw e instanceof r.ZodError?new N(e):e}}},Ke=class extends R{constructor(e,{provider:t=()=>({}),transformer:n=e=>e}={}){super({handler:async({request:r,response:i})=>new Promise((a,o)=>{let s=e=>{if(e&&e instanceof Error)return o(n(e));a(t(r,i))};e(r,i,s)?.catch(s)})})}},z=class{nest(e){return{...e,"":this}}},qe=class i extends z{#e;#t=t.once(()=>{if(n.get(this.#e.outputSchema)?.examples?.length||!w(this.#e.outputSchema,`object`))return;let e=Ue(this.#e.outputSchema);if(!e.length)return;let t=this.#e.outputSchema.meta();n.remove(this.#e.outputSchema).add(this.#e.outputSchema,{...t,examples:e})});constructor(e){super(),this.#e=e}#n(e){return new i({...this.#e,...e})}deprecated(){return this.#n({deprecated:!0})}get isDeprecated(){return this.#e.deprecated||!1}get description(){return this.#e.description}get shortDescription(){return this.#e.shortDescription}get methods(){return Object.freeze(this.#e.methods)}get inputSchema(){return this.#e.inputSchema}get outputSchema(){return this.#t(),this.#e.outputSchema}get requestType(){let t=Re(this.#e.inputSchema);if(t){let n=e(t);if(n===P)return`upload`;if(n===F)return`raw`;if(n===Ae)return`form`}return`json`}getResponses(e){return e===`positive`&&this.#t(),Object.freeze(e===`negative`?this.#e.resultHandler.getNegativeResponse():this.#e.resultHandler.getPositiveResponse(this.#e.outputSchema))}get security(){let e=t.pluck(`security`,this.#e.middlewares||[]);return t.reject(t.isNil,e)}get scopes(){return Object.freeze(this.#e.scopes||[])}get tags(){return Object.freeze(this.#e.tags||[])}getOperationId(e){return this.#e.getOperationId?.(e)}async#r(e){try{return await this.#e.outputSchema.parseAsync(e)}catch(e){throw e instanceof r.ZodError?new De(e):e}}async#i({method:e,logger:t,ctx:n,response:r,...i}){for(let a of this.#e.middlewares||[])if(!(e===`options`&&!(a instanceof Ke))&&(Object.assign(n,await a.execute({...i,ctx:n,response:r,logger:t})),r.writableEnded)){t.warn(`A middleware has closed the stream. Accumulated context:`,n);break}}async#a({input:e,...t}){let n;try{n=await this.#e.inputSchema.parseAsync(e)}catch(e){throw e instanceof r.ZodError?new N(e):e}return this.#e.handler({...t,input:n})}async#o(e){try{await this.#e.resultHandler.execute(e)}catch(t){We({...e,error:new Oe(S(t),e.error||void 0)})}}async execute({request:e,response:t,logger:n,config:r}){let i=he(e),a={},o={output:{},error:null},s=_e(e,r.inputSources);try{if(await this.#i({method:i,input:s,request:e,response:t,logger:n,ctx:a}),t.writableEnded)return;if(i===`options`)return void t.status(200).end();o={output:await this.#r(await this.#a({input:s,logger:n,ctx:a})),error:null}}catch(e){o={output:null,error:S(e)}}await this.#o({...o,input:s,request:e,response:t,logger:n,ctx:a})}};const Je=(e,t)=>e&&t?e.and(t):e||t,Ye=(e,t)=>e?e.and(t):t,B={positive:200,negative:400},V=Object.keys(B);var Xe=class{#e;constructor(e){this.#e=e}execute(...e){return this.#e(...e)}},H=class extends Xe{#e;#t;constructor(e){super(e.handler),this.#e=e.positive,this.#t=e.negative}getPositiveResponse(e){return Ve(this.#e,{variant:`positive`,args:[e],statusCodes:[B.positive],mimeTypes:[b.json]})}getNegativeResponse(){return Ve(this.#t,{variant:`negative`,args:[],statusCodes:[B.negative],mimeTypes:[b.json]})}};const Ze=r.object({status:r.literal(`error`),error:r.object({message:r.string()})});n.add(Ze,{examples:[{status:`error`,error:{message:`Sample error message`}}]});const U=new H({positive:e=>{let t=r.object({status:r.literal(`success`),data:e}),{examples:i}=n.get(e)||{};return i?.length&&n.add(t,{examples:i.map(e=>({status:`success`,data:e}))}),t},negative:Ze,handler:({error:e,input:t,output:n,request:r,response:i,logger:a})=>{if(e){let n=I(e);He(n,a,r,t),i.status(n.statusCode).set(n.headers).json({status:`error`,error:{message:L(n)}});return}i.status(B.positive).json({status:`success`,data:n})}}),Qe=r.string();n.add(Qe,{examples:[`Sample error message`]});const $e=new H({positive:e=>{let t=e instanceof r.ZodObject&&`items`in e.shape&&e.shape.items instanceof r.ZodArray?e.shape.items:r.array(r.any());if(n.get(t)?.examples?.length)return t;let i=n.get(e)?.examples?.filter(e=>D(e)&&`items`in e&&Array.isArray(e.items)).map(e=>e.items);if(i?.length){let e=t.meta();n.remove(t).add(t,{...e,examples:i})}return t},negative:{schema:Qe,mimeType:`text/plain`},handler:({response:e,output:t,error:n,logger:r,request:i,input:a})=>{if(n){let t=I(n);He(t,r,i,a),e.status(t.statusCode).type(`text/plain`).send(L(t));return}if(`items`in t&&Array.isArray(t.items)){e.status(B.positive).json(t.items);return}throw Error(`Property 'items' is missing in the endpoint output`)}});var W=class e{schema=void 0;middlewares=[];constructor(e){this.resultHandler=e}#e(t){let n=new e(this.resultHandler);return n.middlewares=this.middlewares.concat(t),n.schema=Je(this.schema,t.schema),n}addMiddleware(e){return this.#e(e instanceof R?e:new R(e))}use=this.addExpressMiddleware;addExpressMiddleware(...e){return this.#e(new Ke(...e))}addContext(e){return this.#e(new R({handler:e}))}build({input:e=le,output:t,operationId:n,scope:r,tag:i,method:a,...o}){let{middlewares:s,resultHandler:c}=this,l=typeof a==`string`?[a]:a,u=typeof n==`function`?n:e=>n&&`${n}${e===`head`?`__HEAD`:``}`,d=typeof r==`string`?[r]:r||[],f=typeof i==`string`?[i]:i||[];return new qe({...o,middlewares:s,outputSchema:t,resultHandler:c,scopes:d,tags:f,methods:l,getOperationId:u,inputSchema:Ye(this.schema,e)})}buildVoid({handler:e,...t}){return this.build({...t,output:le,handler:async t=>(await e(t),{})})}};const et=new W(U),tt=new W($e),nt={debug:s,info:u,warn:d(`#FFA500`),error:p,ctx:c},G={debug:10,info:20,warn:30,error:40},rt=e=>D(e)&&Object.keys(G).some(t=>t in e),it=e=>e in G,at=(e,t)=>G[e]<G[t],K=t.memoizeWith((e,t)=>`${e}${t}`,(e,t=0)=>Intl.NumberFormat(void 0,{useGrouping:!1,minimumFractionDigits:0,maximumFractionDigits:t,style:`unit`,unitDisplay:`long`,unit:e})),ot=e=>e<1e-6?K(`nanosecond`,3).format(e/1e-6):e<.001?K(`nanosecond`).format(e/1e-6):e<1?K(`microsecond`).format(e/.001):e<1e3?K(`millisecond`).format(e):e<6e4?K(`second`,2).format(e/1e3):K(`minute`,2).format(e/6e4);var st=class e{config;constructor({color:e=o.isSupported(),level:t=be()?`warn`:`debug`,depth:n=2,ctx:r={}}={}){this.config={color:e,level:t,depth:n,ctx:r}}format(e){let{depth:t,color:n,level:r}=this.config;return h(e,{depth:t,colors:n,breakLength:r===`debug`?80:1/0,compact:r===`debug`?3:!0})}print(e,t,n){let{level:r,ctx:{requestId:i,...a},color:o}=this.config;if(r===`silent`||at(e,r))return;let s=[new Date().toISOString()];i&&s.push(o?nt.ctx(i):i),s.push(o?`${nt[e](e)}:`:`${e}:`,t),n!==void 0&&s.push(this.format(n)),Object.keys(a).length>0&&s.push(this.format(a)),console.log(s.join(` `))}debug(e,t){this.print(`debug`,e,t)}info(e,t){this.print(`info`,e,t)}warn(e,t){this.print(`warn`,e,t)}error(e,t){this.print(`error`,e,t)}child(t){return new e({...this.config,ctx:t})}get ctx(){return this.config.ctx}profile(e){let t=g.now();return()=>{let n=g.now()-t,{message:r,severity:i=`debug`,formatter:a=ot}=typeof e==`object`?e:{message:e};this.print(typeof i==`function`?i(n):i,r,a(n))}}},ct=class{#e;constructor(...e){this.#e=e}apply(e,t){return t(e,_.static(...this.#e))}};const q=async(e,t=`default`)=>{try{return(await import(e))[t]}catch{}throw new ke(e)},lt=e=>e.type===`object`,ut=t.mergeDeepWith((e,n)=>{if(Array.isArray(e)&&Array.isArray(n))return t.concat(e,n);if(e===n)return n;throw Error(`Can not flatten properties`,{cause:{a:e,b:n}})}),dt=t.pipe(Object.keys,t.without([`type`,`properties`,`required`,`examples`,`description`,`additionalProperties`]),t.isEmpty),ft=t.pair(!0),J=(e,n=`coerce`)=>{let r=[t.pair(!1,e)],i={type:`object`,properties:{}},a=[];for(;r.length;){let[e,o]=r.shift();if(o.description&&(i.description??=o.description),o.allOf&&r.push(...o.allOf.map(r=>{if(n===`throw`&&!(r.type===`object`&&dt(r)))throw Error(`Can not merge`);return t.pair(e,r)})),o.anyOf&&r.push(...t.map(ft,o.anyOf)),o.oneOf&&r.push(...t.map(ft,o.oneOf)),o.examples?.length&&(e?i.examples=t.concat(i.examples||[],o.examples):i.examples=T(i.examples?.filter(D)||[],o.examples.filter(D),([e,n])=>t.mergeDeepRight(e,n))),lt(o)&&(r.push([e,{examples:pt(o)}]),o.properties&&(i.properties=(n===`throw`?ut:t.mergeDeepRight)(i.properties,o.properties),!e&&o.required&&a.push(...o.required)),D(o.propertyNames))){let t=[];typeof o.propertyNames.const==`string`&&t.push(o.propertyNames.const),o.propertyNames.enum&&t.push(...o.propertyNames.enum.filter(e=>typeof e==`string`));let n={...Object(o.additionalProperties)};for(let e of t)i.properties[e]??=n;e||a.push(...t)}}return a.length&&(i.required=[...new Set(a)]),i},pt=e=>Object.entries(e.properties||{}).reduce((e,[n,r])=>{let{examples:i=[]}=D(r)?r:{};return T(e,i.map(t.objOf(n)),([e,t])=>({...e,...t}))},[]);var mt=class{#e=new WeakMap;constructor(e){this.logger=e}#t(e,t,n){if(!e.isSchemaChecked){for(let e of[`input`,`output`]){let i=[r.toJSONSchema(t[`${e}Schema`],{unrepresentable:`any`})];for(;i.length>0;){let t=i.shift();t.type&&t.type!==`object`&&this.logger.warn(`Endpoint ${e} schema is not object-based`,n);for(let e of[`allOf`,`oneOf`,`anyOf`])t[e]&&i.push(...t[e])}}if(t.requestType===`json`){let e=Be(t.inputSchema,`input`);e&&this.logger.warn(`The final input schema of the endpoint contains an unsupported JSON payload type.`,{...n,reason:e})}for(let e of V)for(let{mimeTypes:r,schema:i}of t.getResponses(e)){if(!r?.includes(b.json))continue;let t=Be(i,`output`);t&&this.logger.warn(`The final ${e} response schema of the endpoint contains an unsupported JSON payload type.`,{...n,reason:t})}e.isSchemaChecked=!0}}#n(e,t,n,i){if(e.paths.has(n))return;let a=de(n);if(a.length!==0){e.flat??=J(r.toJSONSchema(t.inputSchema,{unrepresentable:`any`,io:`input`}));for(let t of a)t in e.flat.properties||this.logger.warn(`The input schema of the endpoint is most likely missing the parameter of the path it's assigned to.`,{...i,path:n,param:t});e.paths.add(n)}}check=(e,t,n)=>{let r=this.#e.get(n);r||(r={isSchemaChecked:!1,paths:new Set},this.#e.set(n,r)),this.#t(r,n,{method:e,path:t}),this.#n(r,n,t,{method:e})}};const ht=e=>(t,...n)=>{e(t,...n),t===`get`&&e(`head`,...n)},gt=e=>{let[t,n]=e.trim().split(/ (.+)/,2);return n&&x(t)?[n,t]:[e]},_t=e=>e.trim().split(`/`).filter(Boolean).join(`/`),vt=({methodLikeRouteBehavior:e=`method`},t,n)=>{let r=e===`method`;return Object.entries(t).map(([e,t])=>{let[i,a]=r&&x(e)&&t instanceof z?[`/`,e]:gt(e);return[[n||``].concat(_t(i)||[]).join(`/`),t,a]})},yt=(e,t)=>{throw new j(`Route with explicit method can only be assigned with Endpoint`,e,t)},bt=(e,t,n)=>{if(!(!n||n.includes(e)))throw new j(`Method ${e} is not supported by the assigned Endpoint.`,e,t)},xt=(e,t,n)=>{let r=`${e} ${t}`;if(n.has(r))throw new j(`Route has a duplicate`,e,t);n.add(r)},St=({routing:e,config:t,onEndpoint:n,onStatic:r})=>{let i=vt(t,e),a=new Set;for(;i.length;){let[e,o,s]=i.shift();if(o instanceof z)if(s)xt(s,e,a),bt(s,e,o.methods),n(s,e,o);else{let{methods:t=[`get`]}=o;for(let r of t)xt(r,e,a),n(r,e,o)}else s&&yt(s,e),o instanceof ct?r&&o.apply(e,r):i.unshift(...vt(t,o,e))}},Ct=e=>e.sort((e,t)=>x(t)-+x(e)||e.localeCompare(t)).join(`, `).toUpperCase(),wt=e=>({method:t},n,r)=>{let a=Ct(e);n.set({Allow:a}),r(i(405,`${t} is not allowed`,{headers:{Allow:a}}))},Tt=e=>({"Access-Control-Allow-Origin":`*`,"Access-Control-Allow-Methods":Ct(e),"Access-Control-Allow-Headers":`content-type`}),Et=({app:e,getLogger:n,config:r,routing:i,parsers:a})=>{let o=be()?void 0:new mt(n()),s=new Map;return St({routing:i,config:r,onEndpoint:(e,n,i)=>{o?.check(e,n,i);let c=a?.[i.requestType]||[],l=t.pair(c,i);s.has(n)||s.set(n,new Map(r.cors?[[`options`,l]]:[])),s.get(n)?.set(e,l)},onStatic:e.use.bind(e)}),s},Dt=({app:e,config:t,getLogger:n,...r})=>{let i=Et({app:e,getLogger:n,config:t,...r}),a=new Map;for(let[r,o]of i){let i=Array.from(o.keys());i.includes(`get`)&&i.push(`head`);for(let[a,[s,c]]of o){let o=s.slice().concat(async(e,r)=>{let i=n(e);return c.execute({request:e,response:r,logger:i,config:t})});t.cors&&o.unshift(async(e,r,a)=>{let o=n(e),s=Tt(i),l=typeof t.cors==`function`?await t.cors({request:e,endpoint:c,logger:o,defaultHeaders:s}):s;r.set(l),a()}),e[a](r,...o)}t.wrongMethodBehavior!==404&&a.set(r,wt(i))}for(let[t,n]of a)e.all(t,n)},Ot=e=>`_httpMessage`in e&&typeof e._httpMessage==`object`&&e._httpMessage!==null&&`headersSent`in e._httpMessage&&typeof e._httpMessage.headersSent==`boolean`&&`setHeader`in e._httpMessage&&typeof e._httpMessage.setHeader==`function`,kt=e=>`server`in e&&typeof e.server==`object`&&e.server!==null&&`close`in e.server&&typeof e.server.close==`function`,At=e=>`encrypted`in e&&typeof e.encrypted==`boolean`&&e.encrypted,jt=({},e)=>void(!e.headersSent&&e.setHeader(`connection`,`close`)),Mt=e=>new Promise((t,n)=>void e.close(e=>e?n(e):t())),Nt=(e,{timeout:t=1e3,logger:n}={})=>{let r,i=new Set,a=e=>void i.delete(e.destroy()),o=e=>void(Ot(e)?!e._httpMessage.headersSent&&e._httpMessage.setHeader(`connection`,`close`):a(e)),s=e=>void(r?e.destroy():i.add(e.once(`close`,()=>void i.delete(e))));for(let t of e)for(let e of[`connection`,`secureConnection`])t.on(e,s);let c=async()=>{for(let t of e)t.on(`request`,jt);n?.info(`Graceful shutdown`,{sockets:i.size,timeout:t});for(let e of i)(At(e)||kt(e))&&o(e);for await(let e of te(10,Date.now()))if(i.size===0||Date.now()-e>=t)break;for(let e of i)a(e);return Promise.allSettled(e.map(Mt))};return{sockets:i,shutdown:()=>r??=c()}},Pt=Symbol.for(`express-zod-api`),Ft=({errorHandler:e,getLogger:t})=>async(n,r,i,a)=>n?e.execute({error:S(n),request:r,response:i,input:null,output:null,ctx:{},logger:t(r)}):a(),It=({errorHandler:e,getLogger:t})=>async(n,r)=>{let a=i(404,`Can not ${n.method} ${n.path}`),o=t(n);try{await e.execute({request:n,response:r,logger:o,error:a,input:null,output:null,ctx:{}})}catch(e){We({response:r,logger:o,error:new Oe(S(e),a)})}},Lt=e=>(t,{},n)=>{if(Object.values(t?.files||[]).flat().find(({truncated:e})=>e))return n(e);n()},Rt=e=>({log:e.debug.bind(e)}),zt=async({getLogger:e,config:t})=>{let n=await q(`express-fileupload`),{limitError:r,beforeUpload:i,...a}={...typeof t.upload==`object`&&t.upload},o=[];return o.push(async(t,r,o)=>{let s=e(t);return await i?.({request:t,logger:s}),n({debug:!0,...a,abortOnLimit:!1,parseNested:!0,logger:Rt(s)})(t,r,o)}),r&&o.push(Lt(r)),o},Bt=(e,{},t)=>{Buffer.isBuffer(e.body)&&(e.body={raw:e.body}),t()},Vt=({logger:e,config:{childLoggerProvider:t,accessLogger:n=({method:e,path:t},n)=>n.debug(`${e}: ${t}`)}})=>async(r,i,a)=>{let o=await t?.({request:r,parent:e})||e;n?.(r,o),r.res&&(r.res.locals[Pt]={logger:o}),a()},Ht=e=>t=>t?.res?.locals[Pt]?.logger||e,Ut=e=>process.on(`deprecation`,({message:t,namespace:n,name:r,stack:i})=>e.warn(`${r} (${n}): ${t}`,i.split(`
|
|
2
3
|
`).slice(1))),Wt=({servers:e,logger:t,options:{timeout:n,beforeExit:r,events:i=[`SIGINT`,`SIGTERM`]}})=>{let a=Nt(e,{logger:t,timeout:n}),o=async()=>{await a.shutdown(),await r?.(),process.exit()};for(let e of i)process.on(e,o)},Gt=e=>{if(e.columns<132)return;let t=f(`Proudly supports transgender community.`.padStart(109)),n=f(`Start your API server with I/O schema validation and custom middlewares in minutes.`.padStart(109)),r=f(`Thank you for choosing Express Zod API for your project.`.padStart(132)),i=f(`for Nikki`.padEnd(20)),a=d(`#F5A9B8`),o=d(`#5BCEFA`),s=Array(14).fill(o,1,3).fill(a,3,5).fill(m,5,7).fill(a,7,9).fill(o,9,12).fill(l,12,13),c=`
|
|
3
4
|
8888888888 8888888888P 888 d8888 8888888b. 8888888
|
|
@@ -14,8 +15,8 @@ ${i}888${n}
|
|
|
14
15
|
${r}
|
|
15
16
|
`;e.write(c.split(`
|
|
16
17
|
`).map((e,t)=>s[t]?s[t](e):e).join(`
|
|
17
|
-
`))},Kt=e=>{e.startupLogo!==!1&&Gt(process.stdout);let t=e.errorHandler||U,n=rt(e.logger)?e.logger:new st(e.logger);n.debug(`Running`,{build:`v27.0.0`,env:process.env.NODE_ENV||`development`}),Ut(n);let r=Vt({logger:n,config:e}),i={getLogger:Ht(n),errorHandler:t},a=It(i),o=Ft(i);return{...i,logger:n,notFoundHandler:a,catcher:o,loggingMiddleware:r}},qt=(e,t)=>{let{logger:n,getLogger:r,notFoundHandler:i,loggingMiddleware:a}=Kt(e);return Dt({app:e.app.use(a),routing:t,getLogger:r,config:e}),{notFoundHandler:i,logger:n}},Jt=async(e,t)=>{let{logger:n,getLogger:r,notFoundHandler:i,catcher:a,loggingMiddleware:o}=Kt(e),s=_().disable(`x-powered-by`).set(`query parser`,e.queryParser??`simple`).use(o);if(e.compression){let t=await q(`compression`);s.use(t(typeof e.compression==`object`?e.compression:void 0))}await e.beforeRouting?.({app:s,getLogger:r}),Dt({app:s,routing:t,getLogger:r,config:e,parsers:{json:[e.jsonParser||_.json()],raw:[e.rawParser||_.raw(),Bt],form:[e.formParser||_.urlencoded()],upload:e.upload?await zt({config:e,getLogger:r}):[]}}),await e.afterRouting?.({app:s,getLogger:r}),s.use(a,i);let c=[],l=(e,t)=>()=>e.listen(t,()=>n.info(`Listening`,t)),u=[];if(e.http){let t=ee.createServer(s);c.push(t),u.push(l(t,e.http.listen))}if(e.https){let t=v.createServer(e.https.options,s);c.push(t),u.push(l(t,e.https.listen))}return c.length||n.warn(`No servers configured.`),e.gracefulShutdown&&Wt({logger:n,servers:c,options:e.gracefulShutdown===!0?{}:e.gracefulShutdown}),{app:s,logger:n,servers:u.map(e=>e())}},Yt=e=>D(e)&&`or`in e,Xt=e=>D(e)&&`and`in e,Zt=e=>!Xt(e)&&!Yt(e),Qt=e=>{let n=t.filter(Zt,e),r=t.chain(t.prop(`and`),t.filter(Xt,e)),[i,a]=t.partition(Zt,r),o=t.concat(n,i),s=t.filter(Yt,e);return t.map(t.prop(`or`),t.concat(s,a)).reduce((e,n)=>T(e,t.map(e=>Zt(e)?[e]:e.and,n),([e,n])=>t.concat(e,n)),t.reject(t.isEmpty,[o]))};var $t=`a-im.accept.accept-additions.accept-ch.accept-charset.accept-datetime.accept-encoding.accept-features.accept-language.accept-signature.access-control.access-control-request-headers.access-control-request-method.alpn.alt-used.alternates.amp-cache-transform.apply-to-redirect-ref.authentication-control.authentication-info.authorization.available-dictionary.c-ext.c-man.c-opt.c-pep.c-pep-info.cache-control.cal-managed-id.caldav-timezones.capsule-protocol.cert-not-after.cert-not-before.client-cert.client-cert-chain.close.cmcd-object.cmcd-request.cmcd-session.cmcd-status.cmsd-dynamic.cmsd-static.concealed-auth-export.configuration-context.connection.content-digest.content-disposition.content-encoding.content-id.content-language.content-length.content-location.content-md5.content-range.content-script-type.content-type.cookie.cookie2.cross-origin-embedder-policy.cross-origin-embedder-policy-report-only.cross-origin-opener-policy.cross-origin-opener-policy-report-only.cross-origin-resource-policy.cta-common-access-token.dasl.date.dav.default-style.delta-base.deprecation.depth.derived-from.destination.detached-jws.differential-id.dictionary-id.digest.dpop.dpop-nonce.early-data.ediint-features.expect.expect-ct.ext.forwarded.from.getprofile.hobareg.host.http2-settings.if.if-match.if-modified-since.if-none-match.if-range.if-schedule-tag-match.if-unmodified-since.im.include-referred-token-binding-id.isolation.keep-alive.label.last-event-id.link.link-template.lock-token.man.max-forwards.memento-datetime.meter.method-check.method-check-expires.mime-version.negotiate.nel.odata-entityid.odata-isolation.odata-maxversion.odata-version.opt.ordering-type.origin.origin-agent-cluster.oscore.oslc-core-version.overwrite.p3p.pep.pep-info.permissions-policy.pics-label.ping-from.ping-to.position.pragma.prefer.preference-applied.priority.profileobject.protocol.protocol-info.protocol-query.protocol-request.proxy-authorization.proxy-features.proxy-instruction.public.public-key-pins.public-key-pins-report-only.range.redirect-ref.referer.referer-root.referrer-policy.repeatability-client-id.repeatability-first-sent.repeatability-request-id.repeatability-result.replay-nonce.reporting-endpoints.repr-digest.safe.schedule-reply.schedule-tag.sec-fetch-storage-access.sec-gpc.sec-purpose.sec-token-binding.sec-websocket-extensions.sec-websocket-key.sec-websocket-protocol.sec-websocket-version.security-scheme.setprofile.signature.signature-input.slug.soapaction.status-uri.sunset.surrogate-capability.tcn.te.timeout.topic.traceparent.tracestate.trailer.transfer-encoding.ttl.upgrade.urgency.uri.use-as-dictionary.user-agent.variant-vary.via.want-content-digest.want-digest.want-repr-digest.warning.x-content-type-options.x-frame-options`.split(`.`);const en=`https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString`,tn={integer:0,number:0,string:``,boolean:!1,object:{},null:null,array:[]},nn=e=>e.replace(ue,e=>`{${e.slice(1)}}`),rn=({},e)=>{if(e.isResponse)throw new M(`Please use ez.upload() only for input.`,e);return{type:`string`,format:`binary`}},an=({jsonSchema:e})=>({...e,externalDocs:{description:`raw binary data`,url:`https://swagger.io/specification/#working-with-binary-data`}}),on=({zodSchema:e,jsonSchema:t})=>{if(!w(e,`union`)||!(`discriminator`in e._zod.def))return t;let n=e._zod.def.discriminator;return{...t,discriminator:t.discriminator??{propertyName:n}}},sn=t.tryCatch(({jsonSchema:e})=>{if(!e.allOf)throw`no allOf`;return J(e,`throw`)},(e,{jsonSchema:t})=>t),cn=({jsonSchema:e})=>{if(!e.anyOf)return e;let t=e.anyOf[0];return Object.assign(t,{type:mn(t.type)})},Y=e=>e,ln=({jsonSchema:{examples:e,description:t}},n)=>{if(n.isResponse)throw new M(`Please use ez.dateOut() for output.`,n);let r={description:t||`YYYY-MM-DDTHH:mm:ss.sssZ`,type:`string`,format:`date-time`,pattern:`^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?)?Z?$`,externalDocs:{url:en}};return e?.length&&(r.examples=e),r},un=({jsonSchema:{examples:e,description:t}},n)=>{if(!n.isResponse)throw new M(`Please use ez.dateIn() for input.`,n);let r={description:t||`YYYY-MM-DDTHH:mm:ss.sssZ`,type:`string`,format:`date-time`,externalDocs:{url:en}};return e?.length&&(r.examples=e),r},dn=()=>({type:`string`,format:`bigint`,pattern:`^-?\\d+$`}),fn=({zodSchema:e,jsonSchema:t})=>e._zod.def.rest===null?{...t,items:{not:{}}}:t,pn=e=>{let t=Array.isArray(e.type)?e.type[0]:e.type;return tn?.[t]},mn=e=>e===`null`?e:typeof e==`string`?[e,`null`]:e&&[...new Set(e).add(`null`)],hn=({zodSchema:e,jsonSchema:t},n)=>{let r=e._zod.def[n.isResponse?`out`:`in`],i=e._zod.def[n.isResponse?`in`:`out`];if(!w(r,`transform`))return t;let a=Y(Sn(i,{ctx:n}));if(y(a))if(n.isResponse){let e=ye(r,pn(a));if(e&&[`number`,`string`,`boolean`].includes(e))return{...t,type:e}}else{let{type:e,...t}=a;return{...t,format:`${t.format||e} (preprocessed)`}}return t},gn=({jsonSchema:e})=>{if(e.type!==`object`)return e;let t=e;return!t.properties||!(`raw`in t.properties)||!D(t.properties.raw)?e:t.properties.raw},_n=e=>e.length?t.fromPairs(t.zip(t.times(e=>`example${e+1}`,e.length),t.map(t.objOf(`value`),e))):void 0,vn=(e,t)=>t?.includes(e)||e.startsWith(`x-`)||$t.includes(e),yn=({path:e,method:n,request:r,inputSources:i,makeRef:a,composition:o,isHeader:s,security:c,description:l=`${n.toUpperCase()} ${e} Parameter`})=>{let u=J(r),d=de(e),f=i.includes(`query`),p=i.includes(`params`),m=i.includes(`headers`),h=e=>p&&d.includes(e),g=t.chain(t.filter(e=>e.type===`header`),c??[]).map(({name:e})=>e),_=t=>m&&(s?.(t,n,e)??vn(t,g));return Object.entries(u.properties).reduce((e,[n,r])=>{if(!D(r))return e;let i=h(n)?`path`:_(n)?`header`:f?`query`:void 0;if(!i)return e;let s=Y(r),c=o===`components`?a(r.id||JSON.stringify(r),s,r.id||E(l,n)):s;return e.concat({name:n,in:i,deprecated:r.deprecated,required:u.required?.includes(n)||!1,description:s.description||l,schema:c,examples:_n(y(s)&&s.examples?.length?s.examples:t.pluck(n,u.examples?.filter(t.both(D,t.has(n)))||[]))})},[])},bn={nullable:cn,union:on,bigint:dn,intersection:sn,tuple:fn,pipe:hn,[k]:ln,[A]:un,[P]:rn,[F]:gn,[O]:an},xn=(e,n,r)=>{let i=[e,n];for(;i.length;){let e=i.shift();if(t.is(Object,e)){if(re(e)&&!e.$ref.startsWith(`#/components`)){let t=n[e.$ref.split(`/`).pop()];t&&(e.$ref=r.makeRef(t.id||t,Y(t),t.id).$ref);continue}i.push(...t.values(e))}t.is(Array,e)&&i.push(...t.values(e))}return e},Sn=(t,{ctx:n,rules:i=bn})=>{let{$defs:a={},properties:o={}}=r.toJSONSchema(r.object({subject:t}),{unrepresentable:`any`,io:n.isResponse?`output`:`input`,override:t=>{let r=e(t.zodSchema),a=i[r&&r in i?r:t.zodSchema._zod.def.type];if(a){let e={...a(t,n)};for(let e in t.jsonSchema)delete t.jsonSchema[e];Object.assign(t.jsonSchema,e)}}});return xn(D(o.subject)?o.subject:{},a,n)},Cn=(e,n)=>{if(re(e))return[e,!1];let r=!1,i=t.map(e=>{let[t,i]=Cn(e,n);return r||=i,t}),a=t.omit(n),o={properties:a,examples:t.map(a),required:t.without(n),allOf:i,oneOf:i,anyOf:i},s=t.evolve(o,e);return[s,r||!!s.required?.length]},wn=({method:e,path:n,schema:r,mimeTypes:i,variant:a,makeRef:o,composition:s,hasMultipleStatusCodes:c,statusCode:l,brandHandling:u,description:d=`${e.toUpperCase()} ${n} ${ve(a)} response ${c?l:``}`.trim()})=>{if(!xe(e,i))return{description:d};let f=Y(Sn(r,{rules:{...u,...bn},ctx:{isResponse:!0,makeRef:o,path:n,method:e}})),p=[];y(f)&&f.examples&&(p.push(...f.examples),delete f.examples);let m={schema:s===`components`?o(r,f,E(d)):f,examples:_n(p)};return{description:d,content:t.fromPairs(t.xprod(i,[m]))}},Tn=({format:e})=>{let t={type:`http`,scheme:`bearer`};return e&&(t.bearerFormat=e),t},En=({name:e},t)=>{let n={type:`apiKey`,in:`query`,name:e};return t?.includes(`body`)&&(t?.includes(`query`)?(n[`x-in-alternative`]=`body`,n.description=`${e} CAN also be supplied within the request body`):(n[`x-in-actual`]=`body`,n.description=`${e} MUST be supplied within the request body instead of query`)),n},Dn=({name:e})=>({type:`apiKey`,in:`header`,name:e}),On=({name:e})=>({type:`apiKey`,in:`cookie`,name:e}),kn=({url:e})=>({type:`openIdConnect`,openIdConnectUrl:e}),An=({flows:e={}})=>({type:`oauth2`,flows:t.map(e=>({...e,scopes:e.scopes||{}}),t.reject(t.isNil,e))}),jn=(e,t=[])=>{let n=e=>e.type===`basic`?{type:`http`,scheme:`basic`}:e.type===`bearer`?Tn(e):e.type===`input`?En(e,t):e.type===`header`?Dn(e):e.type===`cookie`?On(e):e.type===`openid`?kn(e):An(e);return e.map(e=>e.map(n))},Mn=(e,t,n)=>e.map(e=>e.reduce((e,r)=>{let i=n(r),a=[`oauth2`,`openIdConnect`].includes(r.type);return Object.assign(e,{[i]:a?t:[]})},{})),Nn=({schema:e,brandHandling:t,makeRef:n,path:r,method:i})=>Sn(e,{rules:{...t,...bn},ctx:{isResponse:!1,makeRef:n,path:r,method:i}}),Pn=({method:e,path:n,schema:r,request:i,mimeType:a,makeRef:o,composition:s,paramNames:c,description:l=`${e.toUpperCase()} ${n} Request body`})=>{let[u,d]=Cn(Y(i),c),f=[];y(u)&&u.examples&&(f.push(...u.examples),delete u.examples);let p={schema:s===`components`?o(r,u,E(l)):u,examples:_n(f.length?f:J(i).examples?.filter(e=>D(e)&&!Array.isArray(e)).map(t.omit(c))||[])},m={description:l,content:{[a]:p}};return(d||a===b.raw)&&(m.required=!0),m},Fn=e=>Object.entries(e).reduce((e,[t,n])=>{if(!n)return e;let r={name:t,description:typeof n==`string`?n:n.description};return typeof n==`object`&&n.url&&(r.externalDocs={url:n.url}),e.concat(r)},[]),In=e=>e.length<=50?e:e.slice(0,49)+`…`,X=e=>e.length?e.slice():void 0;var Ln=class extends ne{#e=new Map;#t=new Map;#n=new Map;#r(e,t,n){let r=this.#n.get(e);if(!r){let t=n?0:1;do r=`${n??`Schema`}${t?this.#n.size+t:``}`,t++;while(this.rootDoc.components?.schemas?.[r]);this.#n.set(e,r)}return this.addSchema(r,t),{$ref:`#/components/schemas/${r}`}}#i(e,t,n){let r=n||E(t,e),i=this.#t.get(r);if(i===void 0)return this.#t.set(r,1),r;if(n)throw new M(`Duplicated operationId: "${n}"`,{method:t,isResponse:!1,path:e});return i++,this.#t.set(r,i),`${r}${i}`}#a(e){let t=JSON.stringify(e);for(let e in this.rootDoc.components?.securitySchemes||{})if(t===JSON.stringify(this.rootDoc.components?.securitySchemes?.[e]))return e;let n=(this.#e.get(e.type)||0)+1;return this.#e.set(e.type,n),`${e.type.toUpperCase()}_${n}`}constructor({routing:e,config:n,title:r,version:i,serverUrl:a,descriptions:o,brandHandling:s,tags:c,isHeader:l,hasSummaryFromDescription:u=!0,hasHeadMethod:d=!0,composition:f=`inline`}){super(),this.addInfo({title:r,version:i});for(let e of typeof a==`string`?[a]:a)this.addServer({url:e});let p=(e,r,i)=>{let a={path:r,method:e,endpoint:i,composition:f,brandHandling:s,makeRef:this.#r.bind(this)},{description:c,shortDescription:d,scopes:p,inputSchema:m}=i,h=d?In(d):u&&c?In(c):void 0,g=ge(e,n.inputSources),_=this.#i(r,e,i.getOperationId(e)),ee=Nn({...a,schema:m}),v=Qt(i.security),te=yn({...a,inputSources:g,isHeader:l,security:v,request:ee,description:o?.requestParameter?.call(null,{method:e,path:r,operationId:_})}),ne={};for(let t of V){let n=i.getResponses(t);for(let{mimeTypes:i,schema:s,statusCodes:c}of n)for(let l of c)ne[l]=wn({...a,variant:t,schema:s,mimeTypes:i,statusCode:l,hasMultipleStatusCodes:n.length>1||c.length>1,description:o?.[`${t}Response`]?.call(null,{method:e,path:r,operationId:_,statusCode:l})})}let re=g.includes(`body`)?Pn({...a,request:ee,paramNames:t.pluck(`name`,te),schema:m,mimeType:b[i.requestType],description:o?.requestBody?.call(null,{method:e,path:r,operationId:_})}):void 0,y=Mn(jn(v,g),p,e=>{let t=this.#a(e);return this.addSecurityScheme(t,e),t}),ie={operationId:_,summary:h,description:c,deprecated:i.isDeprecated||void 0,tags:X(i.tags),parameters:X(te),requestBody:re,security:X(y),responses:ne};this.addPath(nn(r),{[e]:ie})};St({routing:e,config:n,onEndpoint:d?ht(p):p}),c&&(this.rootDoc.tags=Fn(c))}};const Rn=e=>ie({...e,headers:{"content-type":b.json,...e?.headers}}),zn=e=>ae(e),Bn=e=>{let t={warn:[],error:[],info:[],debug:[]};return new Proxy(e||{},{get(e,n,r){return n===`_getLogs`?()=>t:it(n)?(...e)=>t[n].push(e):Reflect.get(e,n,r)}})},Vn=({requestProps:e,responseOptions:t,configProps:n,loggerProps:r})=>{let i=Rn(e),a=zn({req:i,...t});a.req=t?.req||i,i.res=a;let o=Bn(r);return{requestMock:i,responseMock:a,loggerMock:o,configMock:{cors:!1,logger:o,...n}}},Hn=async({endpoint:e,...t})=>{let{requestMock:n,responseMock:r,loggerMock:i,configMock:a}=Vn(t);return await e.execute({request:n,response:r,config:a,logger:i}),{requestMock:n,responseMock:r,loggerMock:i}},Un=async({middleware:e,ctx:t={},...n})=>{let{requestMock:r,responseMock:i,loggerMock:a,configMock:{inputSources:o,errorHandler:s=U}}=Vn(n),c={request:r,response:i,logger:a,input:_e(r,o),ctx:t};try{return{requestMock:r,responseMock:i,loggerMock:a,output:await e.execute(c)}}catch(e){return await s.execute({...c,error:S(e),output:null}),{requestMock:r,responseMock:i,loggerMock:a,output:{}}}};var Wn=class e{ts;f;exportModifier;asyncModifier;accessModifiers;#e;static#t=/^[A-Za-z_$][A-Za-z0-9_$]*$/;constructor(e){this.ts=e,this.f=this.ts.factory,this.exportModifier=[this.f.createModifier(this.ts.SyntaxKind.ExportKeyword)],this.asyncModifier=[this.f.createModifier(this.ts.SyntaxKind.AsyncKeyword)],this.accessModifiers={public:[this.f.createModifier(this.ts.SyntaxKind.PublicKeyword)],protectedReadonly:[this.f.createModifier(this.ts.SyntaxKind.ProtectedKeyword),this.f.createModifier(this.ts.SyntaxKind.ReadonlyKeyword)]},this.#e=[this.ts.SyntaxKind.AnyKeyword,this.ts.SyntaxKind.BigIntKeyword,this.ts.SyntaxKind.BooleanKeyword,this.ts.SyntaxKind.NeverKeyword,this.ts.SyntaxKind.NumberKeyword,this.ts.SyntaxKind.ObjectKeyword,this.ts.SyntaxKind.StringKeyword,this.ts.SyntaxKind.SymbolKeyword,this.ts.SyntaxKind.UndefinedKeyword,this.ts.SyntaxKind.UnknownKeyword,this.ts.SyntaxKind.VoidKeyword]}addJsDoc=(e,t)=>this.ts.addSyntheticLeadingComment(e,this.ts.SyntaxKind.MultiLineCommentTrivia,`* ${t} `,!0);printNode=(e,t)=>{let n=this.ts.createSourceFile(`print.ts`,``,this.ts.ScriptTarget.Latest,!1,this.ts.ScriptKind.TS);return this.ts.createPrinter(t).printNode(this.ts.EmitHint.Unspecified,e,n)};makeId=e=>this.f.createIdentifier(e);makePropertyIdentifier=t=>typeof t==`string`&&e.#t.test(t)?this.makeId(t):this.literally(t);makeTemplate=(e,...t)=>this.f.createTemplateExpression(this.f.createTemplateHead(e),t.map(([e,n=``],r)=>this.f.createTemplateSpan(typeof e==`string`?this.makeId(e):e,r===t.length-1?this.f.createTemplateTail(n):this.f.createTemplateMiddle(n))));makeParam=(e,{type:t,mod:n,initId:r,optional:i}={})=>this.f.createParameterDeclaration(n,void 0,e,i?this.f.createToken(this.ts.SyntaxKind.QuestionToken):void 0,t?this.ensureTypeNode(t):void 0,r?this.makeId(r):void 0);makeParams=e=>Object.entries(e).map(([e,t])=>this.makeParam(e,typeof t==`string`||typeof t==`number`||typeof t==`object`&&`kind`in t?{type:t}:t));makePublicConstructor=(e,t=[])=>this.f.createConstructorDeclaration(this.accessModifiers.public,e,this.f.createBlock(t));ensureTypeNode=(e,n)=>typeof e==`number`?this.f.createKeywordTypeNode(e):typeof e==`string`||this.ts.isIdentifier(e)?this.f.createTypeReferenceNode(e,n&&t.map(this.ensureTypeNode,n)):e;makeRecordStringAny=()=>this.ensureTypeNode(`Record`,[this.ts.SyntaxKind.StringKeyword,this.ts.SyntaxKind.AnyKeyword]);makeUnion=e=>{let t=new Map;for(let n of e)t.set(this.isPrimitive(n)?n.kind:n,n);return this.f.createUnionTypeNode(Array.from(t.values()))};makeInterfaceProp=(e,n,{isOptional:r,hasUndefined:i=r,isDeprecated:a,comment:o}={})=>{let s=this.ensureTypeNode(n),c=this.f.createPropertySignature(void 0,this.makePropertyIdentifier(e),r?this.f.createToken(this.ts.SyntaxKind.QuestionToken):void 0,i?this.makeUnion([s,this.ensureTypeNode(this.ts.SyntaxKind.UndefinedKeyword)]):s),l=t.reject(t.isNil,[a?`@deprecated`:void 0,o]);return l.length?this.addJsDoc(c,l.join(` `)):c};makeOneLine=e=>this.ts.setEmitFlags(e,this.ts.EmitFlags.SingleLine);makeDeconstruction=(...e)=>this.f.createArrayBindingPattern(e.map(e=>this.f.createBindingElement(void 0,void 0,e)));makeConst=(e,t,{type:n,expose:r}={})=>this.f.createVariableStatement(r&&this.exportModifier,this.f.createVariableDeclarationList([this.f.createVariableDeclaration(e,void 0,n?this.ensureTypeNode(n):void 0,t)],this.ts.NodeFlags.Const));makePublicLiteralType=(e,n)=>this.makeType(e,this.makeUnion(t.map(this.makeLiteralType,n)),{expose:!0});makeType=(e,t,{expose:n,comment:r,params:i}={})=>{let a=this.f.createTypeAliasDeclaration(n?this.exportModifier:void 0,e,i&&this.makeTypeParams(i),t);return r?this.addJsDoc(a,r):a};makePublicProperty=(e,t)=>this.f.createPropertyDeclaration(this.accessModifiers.public,e,void 0,this.ensureTypeNode(t),void 0);makePublicMethod=(e,t,n,{typeParams:r,returns:i}={})=>this.f.createMethodDeclaration(this.accessModifiers.public,void 0,e,void 0,r&&this.makeTypeParams(r),t,i,this.f.createBlock(n));makePublicClass=(e,t,{typeParams:n}={})=>this.f.createClassDeclaration(this.exportModifier,e,n&&this.makeTypeParams(n),void 0,t);makeKeyOf=e=>this.f.createTypeOperatorNode(this.ts.SyntaxKind.KeyOfKeyword,this.ensureTypeNode(e));makePromise=e=>this.ensureTypeNode(Promise.name,[e]);makeInterface=(e,t,{expose:n,comment:r}={})=>{let i=this.f.createInterfaceDeclaration(n?this.exportModifier:void 0,e,void 0,void 0,t);return r?this.addJsDoc(i,r):i};makeTypeParams=e=>(Array.isArray(e)?e.map(e=>t.pair(e,void 0)):Object.entries(e)).map(([e,t])=>{let{type:n,init:r}=typeof t==`object`&&`init`in t?t:{type:t};return this.f.createTypeParameterDeclaration([],e,n?this.ensureTypeNode(n):void 0,r?this.ensureTypeNode(r):void 0)});makeArrowFn=(e,n,{isAsync:r}={})=>this.f.createArrowFunction(r?this.asyncModifier:void 0,void 0,Array.isArray(e)?t.map(this.makeParam,e):this.makeParams(e),void 0,void 0,n);makeTernary=(...e)=>{let[t,n,r]=e.map(e=>typeof e==`string`?this.makeId(e):e);return this.f.createConditionalExpression(t,this.f.createToken(this.ts.SyntaxKind.QuestionToken),n,this.f.createToken(this.ts.SyntaxKind.ColonToken),r)};makeCall=(e,...t)=>(...n)=>this.f.createCallExpression(t.reduce((e,t)=>typeof t==`string`||this.ts.isIdentifier(t)?this.f.createPropertyAccessExpression(e,t):this.f.createElementAccessExpression(e,t),typeof e==`string`?this.makeId(e):e),void 0,n.map(e=>typeof e==`string`?this.makeId(e):e));makeNew=(e,...t)=>this.f.createNewExpression(this.makeId(e),void 0,t);makeExtract=(e,t)=>this.ensureTypeNode(`Extract`,[e,t]);makeAssignment=(e,t)=>this.f.createExpressionStatement(this.f.createBinaryExpression(typeof e==`string`?this.makeId(e):e,this.f.createToken(this.ts.SyntaxKind.EqualsToken),t));makeIndexed=(e,t)=>this.f.createIndexedAccessTypeNode(this.ensureTypeNode(e),this.ensureTypeNode(t));makeMaybeAsync=e=>this.makeUnion([this.ensureTypeNode(e),this.makePromise(e)]);makeFnType=(e,t)=>this.f.createFunctionTypeNode(void 0,this.makeParams(e),this.ensureTypeNode(t));literally=e=>typeof e==`number`?this.f.createNumericLiteral(e):typeof e==`bigint`?this.f.createBigIntLiteral(e.toString()):typeof e==`boolean`?e?this.f.createTrue():this.f.createFalse():e===null?this.f.createNull():this.f.createStringLiteral(e);makeLiteralType=e=>this.f.createLiteralTypeNode(this.literally(e));isPrimitive=e=>this.#e.includes(e.kind)};const Z=e=>e;var Gn=class{api;paths=new Set;tags=new Map;registry=new Map;constructor(e,t){this.serverUrl=t,this.api=new Wn(e)}#e={pathType:`Path`,implementationType:`Implementation`,keyParameter:`key`,pathParameter:`path`,paramsArgument:`params`,ctxArgument:`ctx`,methodParameter:`method`,requestParameter:`request`,eventParameter:`event`,dataParameter:`data`,handlerParameter:`handler`,msgParameter:`msg`,parseRequestFn:`parseRequest`,substituteFn:`substitute`,provideMethod:`provide`,onMethod:`on`,implementationArgument:`implementation`,hasBodyConst:`hasBody`,undefinedValue:`undefined`,responseConst:`response`,restConst:`rest`,searchParamsConst:`searchParams`,defaultImplementationConst:`defaultImplementation`,clientConst:`client`,contentTypeConst:`contentType`,isJsonConst:`isJSON`,sourceProp:`source`,methodType:`Method`,someOfType:`SomeOf`,requestType:`Request`};interfaces={input:`Input`,positive:`PositiveResponse`,negative:`NegativeResponse`,encoded:`EncodedResponse`,response:`Response`};makeMethodType=()=>this.api.makePublicLiteralType(this.#e.methodType,ce);makeSomeOfType=()=>this.api.makeType(this.#e.someOfType,this.api.makeIndexed(`T`,this.api.makeKeyOf(`T`)),{params:[`T`]});makeRequestType=()=>this.api.makeType(this.#e.requestType,this.api.makeKeyOf(this.interfaces.input),{expose:!0});someOf=({name:e})=>this.api.ensureTypeNode(this.#e.someOfType,[e]);makePathType=()=>this.api.makePublicLiteralType(this.#e.pathType,Array.from(this.paths));makePublicInterfaces=()=>Object.keys(this.interfaces).map(e=>this.api.makeInterface(this.interfaces[e],Array.from(this.registry).map(([t,{store:n,isDeprecated:r}])=>this.api.makeInterfaceProp(t,n[e],{isDeprecated:r})),{expose:!0}));makeEndpointTags=()=>this.api.makeConst(`endpointTags`,this.api.f.createObjectLiteralExpression(Array.from(this.tags).map(([e,n])=>this.api.f.createPropertyAssignment(this.api.makePropertyIdentifier(e),this.api.f.createArrayLiteralExpression(t.map(this.api.literally,n))))),{expose:!0});makeImplementationType=()=>this.api.makeType(this.#e.implementationType,this.api.makeFnType({[this.#e.methodParameter]:this.#e.methodType,[this.#e.pathParameter]:this.api.ts.SyntaxKind.StringKeyword,[this.#e.paramsArgument]:this.api.makeRecordStringAny(),[this.#e.ctxArgument]:{optional:!0,type:`T`}},this.api.makePromise(this.api.ts.SyntaxKind.AnyKeyword)),{expose:!0,params:{T:{init:this.api.ts.SyntaxKind.UnknownKeyword}}});makeParseRequestFn=()=>this.api.makeConst(this.#e.parseRequestFn,this.api.makeArrowFn({[this.#e.requestParameter]:this.api.ts.SyntaxKind.StringKeyword},this.api.f.createAsExpression(this.api.makeCall(this.#e.requestParameter,Z(`split`))(this.api.f.createRegularExpressionLiteral(`/ (.+)/`),this.api.literally(2)),this.api.f.createTupleTypeNode([this.api.ensureTypeNode(this.#e.methodType),this.api.ensureTypeNode(this.#e.pathType)]))));makeSubstituteFn=()=>this.api.makeConst(this.#e.substituteFn,this.api.makeArrowFn({[this.#e.pathParameter]:this.api.ts.SyntaxKind.StringKeyword,[this.#e.paramsArgument]:this.api.makeRecordStringAny()},this.api.f.createBlock([this.api.makeConst(this.#e.restConst,this.api.f.createObjectLiteralExpression([this.api.f.createSpreadAssignment(this.api.makeId(this.#e.paramsArgument))])),this.api.f.createForInStatement(this.api.f.createVariableDeclarationList([this.api.f.createVariableDeclaration(this.#e.keyParameter)],this.api.ts.NodeFlags.Const),this.api.makeId(this.#e.paramsArgument),this.api.f.createBlock([this.api.makeAssignment(this.#e.pathParameter,this.api.makeCall(this.#e.pathParameter,Z(`replace`))(this.api.makeTemplate(`:`,[this.#e.keyParameter]),this.api.makeArrowFn([],this.api.f.createBlock([this.api.f.createExpressionStatement(this.api.f.createDeleteExpression(this.api.f.createElementAccessExpression(this.api.makeId(this.#e.restConst),this.api.makeId(this.#e.keyParameter)))),this.api.f.createReturnStatement(this.api.f.createElementAccessExpression(this.api.makeId(this.#e.paramsArgument),this.api.makeId(this.#e.keyParameter)))]))))])),this.api.f.createReturnStatement(this.api.f.createAsExpression(this.api.f.createArrayLiteralExpression([this.api.makeId(this.#e.pathParameter),this.api.makeId(this.#e.restConst)]),this.api.ensureTypeNode(`const`)))])));#t=()=>this.api.makePublicMethod(this.#e.provideMethod,this.api.makeParams({[this.#e.requestParameter]:`K`,[this.#e.paramsArgument]:this.api.makeIndexed(this.interfaces.input,`K`),[this.#e.ctxArgument]:{optional:!0,type:`T`}}),[this.api.makeConst(this.api.makeDeconstruction(this.#e.methodParameter,this.#e.pathParameter),this.api.makeCall(this.#e.parseRequestFn)(this.#e.requestParameter)),this.api.f.createReturnStatement(this.api.makeCall(this.api.f.createThis(),this.#e.implementationArgument)(this.#e.methodParameter,this.api.f.createSpreadElement(this.api.makeCall(this.#e.substituteFn)(this.#e.pathParameter,this.#e.paramsArgument)),this.#e.ctxArgument))],{typeParams:{K:this.#e.requestType},returns:this.api.makePromise(this.api.makeIndexed(this.interfaces.response,`K`))});makeClientClass=e=>this.api.makePublicClass(e,[this.api.makePublicConstructor([this.api.makeParam(this.#e.implementationArgument,{type:this.api.ensureTypeNode(this.#e.implementationType,[`T`]),mod:this.api.accessModifiers.protectedReadonly,initId:this.#e.defaultImplementationConst})]),this.#t()],{typeParams:[`T`]});#n=e=>this.api.makeTemplate(`?`,[this.api.makeNew(URLSearchParams.name,this.api.makeId(e))]);#r=()=>this.api.makeNew(URL.name,this.api.makeTemplate(``,[this.#e.pathParameter],[this.#e.searchParamsConst]),this.api.literally(this.serverUrl));makeDefaultImplementation=()=>{let e=this.api.f.createPropertyAssignment(Z(`method`),this.api.makeCall(this.#e.methodParameter,Z(`toUpperCase`))()),t=this.api.f.createPropertyAssignment(Z(`headers`),this.api.makeTernary(this.#e.hasBodyConst,this.api.f.createObjectLiteralExpression([this.api.f.createPropertyAssignment(this.api.literally(`Content-Type`),this.api.literally(b.json))]),this.#e.undefinedValue)),n=this.api.f.createPropertyAssignment(Z(`body`),this.api.makeTernary(this.#e.hasBodyConst,this.api.makeCall(JSON[Symbol.toStringTag],Z(`stringify`))(this.#e.paramsArgument),this.#e.undefinedValue)),r=this.api.makeConst(this.#e.responseConst,this.api.f.createAwaitExpression(this.api.makeCall(fetch.name)(this.#r(),this.api.f.createObjectLiteralExpression([e,t,n])))),i=this.api.makeConst(this.#e.hasBodyConst,this.api.f.createLogicalNot(this.api.makeCall(this.api.f.createArrayLiteralExpression([this.api.literally(`get`),this.api.literally(`head`),this.api.literally(`delete`)]),Z(`includes`))(this.#e.methodParameter))),a=this.api.makeConst(this.#e.searchParamsConst,this.api.makeTernary(this.#e.hasBodyConst,this.api.literally(``),this.#n(this.#e.paramsArgument))),o=this.api.makeConst(this.#e.contentTypeConst,this.api.makeCall(this.#e.responseConst,Z(`headers`),Z(`get`))(this.api.literally(`content-type`))),s=this.api.f.createIfStatement(this.api.f.createPrefixUnaryExpression(this.api.ts.SyntaxKind.ExclamationToken,this.api.makeId(this.#e.contentTypeConst)),this.api.f.createReturnStatement()),c=this.api.makeConst(this.#e.isJsonConst,this.api.makeCall(this.#e.contentTypeConst,Z(`startsWith`))(this.api.literally(b.json))),l=this.api.f.createReturnStatement(this.api.makeCall(this.#e.responseConst,this.api.makeTernary(this.#e.isJsonConst,this.api.literally(Z(`json`)),this.api.literally(Z(`text`))))());return this.api.makeConst(this.#e.defaultImplementationConst,this.api.makeArrowFn([this.#e.methodParameter,this.#e.pathParameter,this.#e.paramsArgument],this.api.f.createBlock([i,a,r,o,s,c,l]),{isAsync:!0}),{type:this.#e.implementationType})};#i=()=>this.api.makePublicConstructor(this.api.makeParams({request:`K`,params:this.api.makeIndexed(this.interfaces.input,`K`)}),[this.api.makeConst(this.api.makeDeconstruction(this.#e.pathParameter,this.#e.restConst),this.api.makeCall(this.#e.substituteFn)(this.api.f.createElementAccessExpression(this.api.makeCall(this.#e.parseRequestFn)(this.#e.requestParameter),this.api.literally(1)),this.#e.paramsArgument)),this.api.makeConst(this.#e.searchParamsConst,this.#n(this.#e.restConst)),this.api.makeAssignment(this.api.f.createPropertyAccessExpression(this.api.f.createThis(),this.#e.sourceProp),this.api.makeNew(`EventSource`,this.#r()))]);#a=e=>this.api.f.createTypeLiteralNode([this.api.makeInterfaceProp(Z(`event`),e)]);#o=()=>this.api.makePublicMethod(this.#e.onMethod,this.api.makeParams({[this.#e.eventParameter]:`E`,[this.#e.handlerParameter]:this.api.makeFnType({[this.#e.dataParameter]:this.api.makeIndexed(this.api.makeExtract(`R`,this.api.makeOneLine(this.#a(`E`))),this.api.makeLiteralType(Z(`data`)))},this.api.makeMaybeAsync(this.api.ts.SyntaxKind.VoidKeyword))}),[this.api.f.createExpressionStatement(this.api.makeCall(this.api.f.createThis(),this.#e.sourceProp,Z(`addEventListener`))(this.#e.eventParameter,this.api.makeArrowFn([this.#e.msgParameter],this.api.makeCall(this.#e.handlerParameter)(this.api.makeCall(JSON[Symbol.toStringTag],Z(`parse`))(this.api.f.createPropertyAccessExpression(this.api.f.createParenthesizedExpression(this.api.f.createAsExpression(this.api.makeId(this.#e.msgParameter),this.api.ensureTypeNode(MessageEvent.name))),Z(`data`))))))),this.api.f.createReturnStatement(this.api.f.createThis())],{typeParams:{E:this.api.makeIndexed(`R`,this.api.makeLiteralType(Z(`event`)))}});makeSubscriptionClass=e=>this.api.makePublicClass(e,[this.api.makePublicProperty(this.#e.sourceProp,`EventSource`),this.#i(),this.#o()],{typeParams:{K:this.api.makeExtract(this.#e.requestType,this.api.f.createTemplateLiteralType(this.api.f.createTemplateHead(`get `),[this.api.f.createTemplateLiteralTypeSpan(this.api.ensureTypeNode(this.api.ts.SyntaxKind.StringKeyword),this.api.f.createTemplateTail(``))])),R:this.api.makeExtract(this.api.makeIndexed(this.interfaces.positive,`K`),this.api.makeOneLine(this.#a(this.api.ts.SyntaxKind.StringKeyword)))}});makeUsageStatements=(e,t)=>[this.api.makeConst(this.#e.clientConst,this.api.makeNew(e)),this.api.makeCall(this.#e.clientConst,this.#e.provideMethod)(this.api.literally(`get /v1/user/retrieve`),this.api.f.createObjectLiteralExpression([this.api.f.createPropertyAssignment(`id`,this.api.literally(`10`))])),this.api.makeCall(this.api.makeNew(t,this.api.literally(`get /v1/events/stream`),this.api.f.createObjectLiteralExpression()),this.#e.onMethod)(this.api.literally(`time`),this.api.makeArrowFn([`time`],this.api.f.createBlock([])))]};const Kn=(t,{onEach:n,rules:r,onMissing:i,ctx:a={}})=>{let o=e(t),s=o&&o in r?r[o]:r[t._zod.def.type],c=e=>Kn(e,{ctx:a,onEach:n,rules:r,onMissing:i}),l=s?s(t,{...a,next:c}):i(t,a),u=n&&n(t,{prev:l,...a});return u?{...l,...u}:l},qn={name:t.path([`name`,`text`]),type:t.path([`type`]),optional:t.path([`questionToken`])},Jn=({_zod:{def:e}},{api:t})=>{let n=e.values.map(e=>e===void 0?t.ensureTypeNode(t.ts.SyntaxKind.UndefinedKeyword):t.makeLiteralType(e));return n.length===1?n[0]:t.makeUnion(n)},Yn=({_zod:{def:e}},{next:t,api:n})=>{let r=[...e.parts],i=()=>{let e=``;for(;r.length;){let t=r.shift();if(w(t)){r.unshift(t);break}e+=t??``}return e},a=n.f.createTemplateHead(i()),o=[];for(;r.length;){let e=t(r.shift()),a=i(),s=r.length?n.f.createTemplateMiddle:n.f.createTemplateTail;o.push(n.f.createTemplateLiteralTypeSpan(e,s(a)))}return o.length?n.f.createTemplateLiteralType(a,o):n.makeLiteralType(a.text)},Xn=(e,{isResponse:t,next:i,makeAlias:a,api:o})=>{let s=()=>{let a=Object.entries(e._zod.def.shape).map(([e,a])=>{let{description:s,deprecated:c}=n.get(a)||{},l=(t?a._zod.optout:a._zod.optin)===`optional`,u=l&&!(a instanceof r.core.$ZodExactOptional);return o.makeInterfaceProp(e,i(a),{comment:s,isDeprecated:c,isOptional:l,hasUndefined:u})});return o.f.createTypeLiteralNode(a)};return Le(e,{io:t?`output`:`input`})?a(e,s):s()},Zn=({_zod:{def:e}},{next:t,api:n})=>n.f.createArrayTypeNode(t(e.element)),Qn=({_zod:{def:e}},{api:n})=>n.makeUnion(t.map(n.makeLiteralType,Object.values(e.entries))),$n=({_zod:{def:e}},{next:t,api:n})=>n.makeUnion(e.options.map(t)),er=({_zod:{def:e}},{next:t,api:n})=>n.makeUnion([t(e.innerType),n.makeLiteralType(null)]),tr=({_zod:{def:e}},{next:t,api:n})=>n.f.createTupleTypeNode(e.items.map(t).concat(e.rest===null?[]:n.f.createRestTypeNode(t(e.rest)))),nr=({_zod:{def:e}},{next:t,api:n})=>{let[r,i]=[e.keyType,e.valueType].map(t),a=n.ensureTypeNode(`Record`,[r,i]);return e.mode===`loose`?n.f.createIntersectionTypeNode([a,n.ensureTypeNode(`Record`,[`PropertyKey`,i])]):a},rr=t.tryCatch((e,n)=>{if(!n.every(e.ts.isTypeLiteralNode))throw Error(`Not objects`);let r=t.chain(t.prop(`members`),n),i=t.uniqWith((...e)=>{if(!t.eqBy(qn.name,...e))return!1;if(t.both(t.eqBy(qn.type),t.eqBy(qn.optional))(...e))return!0;throw Error(`Has conflicting prop`)},r);return e.f.createTypeLiteralNode(i)},(e,t,n)=>t.f.createIntersectionTypeNode(n)),ir=({_zod:{def:e}},{next:t,api:n})=>rr(n,[e.left,e.right].map(t)),Q=e=>({},{api:t})=>t.ensureTypeNode(t.ts.SyntaxKind[e]),$=({_zod:{def:e}},{next:t})=>t(e.innerType),ar=(e,t)=>e.ensureTypeNode(t?e.ts.SyntaxKind.UnknownKeyword:e.ts.SyntaxKind.AnyKeyword),or=({_zod:{def:e}},{next:t,isResponse:n,api:r})=>{let i=e[n?`out`:`in`],a=e[n?`in`:`out`];if(!w(i,`transform`))return t(i);let o=t(a),s={[r.ts.SyntaxKind.AnyKeyword]:``,[r.ts.SyntaxKind.BigIntKeyword]:BigInt(0),[r.ts.SyntaxKind.BooleanKeyword]:!1,[r.ts.SyntaxKind.NumberKeyword]:0,[r.ts.SyntaxKind.ObjectKeyword]:{},[r.ts.SyntaxKind.StringKeyword]:``,[r.ts.SyntaxKind.UndefinedKeyword]:void 0}[o.kind],c=ye(i,s),l={number:r.ts.SyntaxKind.NumberKeyword,bigint:r.ts.SyntaxKind.BigIntKeyword,boolean:r.ts.SyntaxKind.BooleanKeyword,string:r.ts.SyntaxKind.StringKeyword,undefined:r.ts.SyntaxKind.UndefinedKeyword,object:r.ts.SyntaxKind.ObjectKeyword};return r.ensureTypeNode(c&&l[c]||ar(r,n))},sr=({},{api:e})=>e.makeLiteralType(null),cr=({_zod:{def:e}},{makeAlias:t,next:n})=>t(e.getter,()=>n(e.getter())),lr=({},{api:e})=>e.ensureTypeNode(`Buffer`),ur=(e,{next:t})=>t(e._zod.def.shape.raw),dr={string:Q(`StringKeyword`),number:Q(`NumberKeyword`),bigint:Q(`BigIntKeyword`),boolean:Q(`BooleanKeyword`),any:Q(`AnyKeyword`),undefined:Q(`UndefinedKeyword`),[k]:Q(`StringKeyword`),[A]:Q(`StringKeyword`),never:Q(`NeverKeyword`),void:Q(`UndefinedKeyword`),unknown:Q(`UnknownKeyword`),null:sr,array:Zn,tuple:tr,record:nr,object:Xn,literal:Jn,template_literal:Yn,intersection:ir,union:$n,default:$,enum:Qn,optional:$,nonoptional:$,nullable:er,catch:$,pipe:or,lazy:cr,readonly:$,[O]:lr,[F]:ur},fr=(e,{brandHandling:t,ctx:n})=>Kn(e,{rules:{...t,...dr},onMissing:({},{isResponse:e,api:t})=>ar(t,e),ctx:n});var pr=class e extends Gn{#e=[this.makeSomeOfType()];#t=new Map;#n=[];#r(e,t){let n=this.#t.get(e)?.name?.text;if(!n){n=`Type${this.#t.size+1}`;let r=this.api.makeLiteralType(null);this.#t.set(e,this.api.makeType(n,r)),this.#t.set(e,this.api.makeType(n,t()))}return this.api.ensureTypeNode(n)}constructor({typescript:e,routing:n,config:i,brandHandling:a,variant:o=`client`,clientClassName:s=`Client`,subscriptionClassName:c=`Subscription`,serverUrl:l=`https://example.com`,noContent:u=r.undefined(),hasHeadMethod:d=!0}){super(e,l);let f={makeAlias:this.#r.bind(this),api:this.api},p={brandHandling:a,ctx:{...f,isResponse:!1}},m={brandHandling:a,ctx:{...f,isResponse:!0}},h=(e,n,r)=>{let i=E.bind(null,e,n),{isDeprecated:a,inputSchema:o,tags:s}=r,c=`${e} ${n}`,l=this.api.makeType(i(`input`),fr(o,p),{comment:c});this.#e.push(l);let d=V.reduce((n,a)=>{let o=r.getResponses(a),s=t.chain(([t,{schema:n,mimeTypes:r,statusCodes:o}])=>{let s=xe(e,r),l=this.api.makeType(i(a,`variant`,`${t+1}`),fr(s?n:u,m),{comment:c});return this.#e.push(l),o.map(e=>this.api.makeInterfaceProp(e,l.name))},Array.from(o.entries())),l=this.api.makeInterface(i(a,`response`,`variants`),s,{comment:c});return this.#e.push(l),Object.assign(n,{[a]:l})},{});this.paths.add(n);let f=this.api.makeLiteralType(c),h={input:this.api.ensureTypeNode(l.name),positive:this.someOf(d.positive),negative:this.someOf(d.negative),response:this.api.makeUnion([this.api.makeIndexed(this.interfaces.positive,f),this.api.makeIndexed(this.interfaces.negative,f)]),encoded:this.api.f.createIntersectionTypeNode([this.api.ensureTypeNode(d.positive.name),this.api.ensureTypeNode(d.negative.name)])};this.registry.set(c,{isDeprecated:a,store:h}),this.tags.set(c,s)};St({routing:n,config:i,onEndpoint:d?ht(h):h}),this.#e.unshift(...this.#t.values()),this.#e.push(this.makePathType(),this.makeMethodType(),...this.makePublicInterfaces(),this.makeRequestType()),o!==`types`&&(this.#e.push(this.makeEndpointTags(),this.makeParseRequestFn(),this.makeSubstituteFn(),this.makeImplementationType(),this.makeDefaultImplementation(),this.makeClientClass(s),this.makeSubscriptionClass(c)),this.#n.push(...this.makeUsageStatements(s,c)))}static async create(t){return new e({...t,typescript:await q(`typescript`)})}#i(e){return this.#n.length?this.#n.map(t=>typeof t==`string`?t:this.api.printNode(t,e)).join(`
|
|
18
|
+
`))},Kt=e=>{e.startupLogo!==!1&&Gt(process.stdout);let t=e.errorHandler||U,n=rt(e.logger)?e.logger:new st(e.logger);n.debug(`Running`,{build:`v27.1.0`,env:process.env.NODE_ENV||`development`}),Ut(n);let r=Vt({logger:n,config:e}),i={getLogger:Ht(n),errorHandler:t},a=It(i),o=Ft(i);return{...i,logger:n,notFoundHandler:a,catcher:o,loggingMiddleware:r}},qt=(e,t)=>{let{logger:n,getLogger:r,notFoundHandler:i,loggingMiddleware:a}=Kt(e);return Dt({app:e.app.use(a),routing:t,getLogger:r,config:e}),{notFoundHandler:i,logger:n}},Jt=async(e,t)=>{let{logger:n,getLogger:r,notFoundHandler:i,catcher:a,loggingMiddleware:o}=Kt(e),s=_().disable(`x-powered-by`).set(`query parser`,e.queryParser??`simple`).use(o);if(e.compression){let t=await q(`compression`);s.use(t(typeof e.compression==`object`?e.compression:void 0))}await e.beforeRouting?.({app:s,getLogger:r}),Dt({app:s,routing:t,getLogger:r,config:e,parsers:{json:[e.jsonParser||_.json()],raw:[e.rawParser||_.raw(),Bt],form:[e.formParser||_.urlencoded()],upload:e.upload?await zt({config:e,getLogger:r}):[]}}),await e.afterRouting?.({app:s,getLogger:r}),s.use(a,i);let c=[],l=(e,t)=>()=>e.listen(t,()=>n.info(`Listening`,t)),u=[];if(e.http){let t=ee.createServer(s);c.push(t),u.push(l(t,e.http.listen))}if(e.https){let t=v.createServer(e.https.options,s);c.push(t),u.push(l(t,e.https.listen))}return c.length||n.warn(`No servers configured.`),e.gracefulShutdown&&Wt({logger:n,servers:c,options:e.gracefulShutdown===!0?{}:e.gracefulShutdown}),{app:s,logger:n,servers:u.map(e=>e())}},Yt=e=>D(e)&&`or`in e,Xt=e=>D(e)&&`and`in e,Zt=e=>!Xt(e)&&!Yt(e),Qt=e=>{let n=t.filter(Zt,e),r=t.chain(t.prop(`and`),t.filter(Xt,e)),[i,a]=t.partition(Zt,r),o=t.concat(n,i),s=t.filter(Yt,e);return t.map(t.prop(`or`),t.concat(s,a)).reduce((e,n)=>T(e,t.map(e=>Zt(e)?[e]:e.and,n),([e,n])=>t.concat(e,n)),t.reject(t.isEmpty,[o]))};var $t=`a-im.accept.accept-additions.accept-ch.accept-charset.accept-datetime.accept-encoding.accept-features.accept-language.accept-signature.access-control.access-control-request-headers.access-control-request-method.alpn.alt-used.alternates.amp-cache-transform.apply-to-redirect-ref.authentication-control.authentication-info.authorization.available-dictionary.c-ext.c-man.c-opt.c-pep.c-pep-info.cache-control.cal-managed-id.caldav-timezones.capsule-protocol.cert-not-after.cert-not-before.client-cert.client-cert-chain.close.cmcd-object.cmcd-request.cmcd-session.cmcd-status.cmsd-dynamic.cmsd-static.concealed-auth-export.configuration-context.connection.content-digest.content-disposition.content-encoding.content-id.content-language.content-length.content-location.content-md5.content-range.content-script-type.content-type.cookie.cookie2.cross-origin-embedder-policy.cross-origin-embedder-policy-report-only.cross-origin-opener-policy.cross-origin-opener-policy-report-only.cross-origin-resource-policy.cta-common-access-token.dasl.date.dav.default-style.delta-base.deprecation.depth.derived-from.destination.detached-jws.differential-id.dictionary-id.digest.dpop.dpop-nonce.early-data.ediint-features.expect.expect-ct.ext.forwarded.from.getprofile.hobareg.host.http2-settings.if.if-match.if-modified-since.if-none-match.if-range.if-schedule-tag-match.if-unmodified-since.im.include-referred-token-binding-id.incremental.isolation.keep-alive.label.last-event-id.link.link-template.lock-token.man.max-forwards.memento-datetime.meter.method-check.method-check-expires.mime-version.negotiate.nel.odata-entityid.odata-isolation.odata-maxversion.odata-version.opt.ordering-type.origin.origin-agent-cluster.oscore.oslc-core-version.overwrite.p3p.pep.pep-info.permissions-policy.pics-label.ping-from.ping-to.position.pragma.prefer.preference-applied.priority.profileobject.protocol.protocol-info.protocol-query.protocol-request.proxy-authorization.proxy-features.proxy-instruction.public.public-key-pins.public-key-pins-report-only.range.redirect-ref.referer.referer-root.referrer-policy.repeatability-client-id.repeatability-first-sent.repeatability-request-id.repeatability-result.replay-nonce.reporting-endpoints.repr-digest.safe.schedule-reply.schedule-tag.sec-fetch-storage-access.sec-gpc.sec-purpose.sec-token-binding.sec-websocket-extensions.sec-websocket-key.sec-websocket-protocol.sec-websocket-version.security-scheme.setprofile.signature.signature-input.slug.soapaction.status-uri.sunset.surrogate-capability.tcn.te.timeout.topic.traceparent.tracestate.trailer.transfer-encoding.ttl.upgrade.urgency.uri.use-as-dictionary.user-agent.variant-vary.via.want-content-digest.want-digest.want-repr-digest.warning.x-content-type-options.x-frame-options`.split(`.`);const en=`https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString`,tn={integer:0,number:0,string:``,boolean:!1,object:{},null:null,array:[]},nn=e=>e.replace(ue,e=>`{${e.slice(1)}}`),rn=({},e)=>{if(e.isResponse)throw new M(`Please use ez.upload() only for input.`,e);return{type:`string`,format:`binary`}},an=({jsonSchema:e})=>({...e,externalDocs:{description:`raw binary data`,url:`https://swagger.io/specification/#working-with-binary-data`}}),on=({zodSchema:e,jsonSchema:t})=>{if(!w(e,`union`)||!(`discriminator`in e._zod.def))return t;let n=e._zod.def.discriminator;return{...t,discriminator:t.discriminator??{propertyName:n}}},sn=t.tryCatch(({jsonSchema:e})=>{if(!e.allOf)throw`no allOf`;return J(e,`throw`)},(e,{jsonSchema:t})=>t),cn=({jsonSchema:e})=>{if(!e.anyOf)return e;let t=e.anyOf[0];return Object.assign(t,{type:mn(t.type)})},Y=e=>e,ln=({jsonSchema:{examples:e,description:t}},n)=>{if(n.isResponse)throw new M(`Please use ez.dateOut() for output.`,n);let r={description:t||`YYYY-MM-DDTHH:mm:ss.sssZ`,type:`string`,format:`date-time`,pattern:`^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?)?Z?$`,externalDocs:{url:en}};return e?.length&&(r.examples=e),r},un=({jsonSchema:{examples:e,description:t}},n)=>{if(!n.isResponse)throw new M(`Please use ez.dateIn() for input.`,n);let r={description:t||`YYYY-MM-DDTHH:mm:ss.sssZ`,type:`string`,format:`date-time`,externalDocs:{url:en}};return e?.length&&(r.examples=e),r},dn=()=>({type:`string`,format:`bigint`,pattern:`^-?\\d+$`}),fn=({zodSchema:e,jsonSchema:t})=>e._zod.def.rest===null?{...t,items:{not:{}}}:t,pn=e=>{let t=Array.isArray(e.type)?e.type[0]:e.type;return tn?.[t]},mn=e=>e===`null`?e:typeof e==`string`?[e,`null`]:e&&[...new Set(e).add(`null`)],hn=({zodSchema:e,jsonSchema:t},n)=>{let r=e._zod.def[n.isResponse?`out`:`in`],i=e._zod.def[n.isResponse?`in`:`out`];if(!w(r,`transform`))return t;let a=Y(Sn(i,{ctx:n}));if(y(a))if(n.isResponse){let e=ye(r,pn(a));if(e&&[`number`,`string`,`boolean`].includes(e))return{...t,type:e}}else{let{type:e,...t}=a;return{...t,format:`${t.format||e} (preprocessed)`}}return t},gn=({jsonSchema:e})=>{if(e.type!==`object`)return e;let t=e;return!t.properties||!(`raw`in t.properties)||!D(t.properties.raw)?e:t.properties.raw},_n=e=>e.length?t.fromPairs(t.zip(t.times(e=>`example${e+1}`,e.length),t.map(t.objOf(`value`),e))):void 0,vn=(e,t)=>t?.includes(e)||e.startsWith(`x-`)||$t.includes(e),yn=({path:e,method:n,request:r,inputSources:i,makeRef:a,composition:o,isHeader:s,security:c,description:l=`${n.toUpperCase()} ${e} Parameter`})=>{let u=J(r),d=de(e),f=i.includes(`query`),p=i.includes(`params`),m=i.includes(`headers`),h=e=>p&&d.includes(e),g=t.chain(t.filter(e=>e.type===`header`),c??[]).map(({name:e})=>e),_=t=>m&&(s?.(t,n,e)??vn(t,g));return Object.entries(u.properties).reduce((e,[n,r])=>{if(!D(r))return e;let i=h(n)?`path`:_(n)?`header`:f?`query`:void 0;if(!i)return e;let s=Y(r),c=o===`components`?a(r.id||JSON.stringify(r),s,r.id||E(l,n)):s;return e.concat({name:n,in:i,deprecated:r.deprecated,required:u.required?.includes(n)||!1,description:s.description||l,schema:c,examples:_n(y(s)&&s.examples?.length?s.examples:t.pluck(n,u.examples?.filter(t.both(D,t.has(n)))||[]))})},[])},bn={nullable:cn,union:on,bigint:dn,intersection:sn,tuple:fn,pipe:hn,[k]:ln,[A]:un,[P]:rn,[F]:gn,[O]:an},xn=(e,n,r)=>{let i=[e,n];for(;i.length;){let e=i.shift();if(t.is(Object,e)){if(re(e)&&!e.$ref.startsWith(`#/components`)){let t=n[e.$ref.split(`/`).pop()];t&&(e.$ref=r.makeRef(t.id||t,Y(t),t.id).$ref);continue}i.push(...t.values(e))}t.is(Array,e)&&i.push(...t.values(e))}return e},Sn=(t,{ctx:n,rules:i=bn})=>{let{$defs:a={},properties:o={}}=r.toJSONSchema(r.object({subject:t}),{unrepresentable:`any`,io:n.isResponse?`output`:`input`,override:t=>{let r=e(t.zodSchema),a=i[r&&r in i?r:t.zodSchema._zod.def.type];if(a){let e={...a(t,n)};for(let e in t.jsonSchema)delete t.jsonSchema[e];Object.assign(t.jsonSchema,e)}}});return xn(D(o.subject)?o.subject:{},a,n)},Cn=(e,n)=>{if(re(e))return[e,!1];let r=!1,i=t.map(e=>{let[t,i]=Cn(e,n);return r||=i,t}),a=t.omit(n),o={properties:a,examples:t.map(a),required:t.without(n),allOf:i,oneOf:i,anyOf:i},s=t.evolve(o,e);return[s,r||!!s.required?.length]},wn=({method:e,path:n,schema:r,mimeTypes:i,variant:a,makeRef:o,composition:s,hasMultipleStatusCodes:c,statusCode:l,brandHandling:u,description:d=`${e.toUpperCase()} ${n} ${ve(a)} response ${c?l:``}`.trim()})=>{if(!xe(e,i))return{description:d};let f=Y(Sn(r,{rules:{...u,...bn},ctx:{isResponse:!0,makeRef:o,path:n,method:e}})),p=[];y(f)&&f.examples&&(p.push(...f.examples),delete f.examples);let m={schema:s===`components`?o(r,f,E(d)):f,examples:_n(p)};return{description:d,content:t.fromPairs(t.xprod(i,[m]))}},Tn=({format:e})=>{let t={type:`http`,scheme:`bearer`};return e&&(t.bearerFormat=e),t},En=({name:e},t)=>{let n={type:`apiKey`,in:`query`,name:e};return t?.includes(`body`)&&(t?.includes(`query`)?(n[`x-in-alternative`]=`body`,n.description=`${e} CAN also be supplied within the request body`):(n[`x-in-actual`]=`body`,n.description=`${e} MUST be supplied within the request body instead of query`)),n},Dn=({name:e})=>({type:`apiKey`,in:`header`,name:e}),On=({name:e})=>({type:`apiKey`,in:`cookie`,name:e}),kn=({url:e})=>({type:`openIdConnect`,openIdConnectUrl:e}),An=({flows:e={}})=>({type:`oauth2`,flows:t.map(e=>({...e,scopes:e.scopes||{}}),t.reject(t.isNil,e))}),jn=(e,t=[])=>{let n=e=>e.type===`basic`?{type:`http`,scheme:`basic`}:e.type===`bearer`?Tn(e):e.type===`input`?En(e,t):e.type===`header`?Dn(e):e.type===`cookie`?On(e):e.type===`openid`?kn(e):An(e);return e.map(e=>e.map(n))},Mn=(e,t,n)=>e.map(e=>e.reduce((e,r)=>{let i=n(r),a=[`oauth2`,`openIdConnect`].includes(r.type);return Object.assign(e,{[i]:a?t:[]})},{})),Nn=({schema:e,brandHandling:t,makeRef:n,path:r,method:i})=>Sn(e,{rules:{...t,...bn},ctx:{isResponse:!1,makeRef:n,path:r,method:i}}),Pn=({method:e,path:n,schema:r,request:i,mimeType:a,makeRef:o,composition:s,paramNames:c,description:l=`${e.toUpperCase()} ${n} Request body`})=>{let[u,d]=Cn(Y(i),c),f=[];y(u)&&u.examples&&(f.push(...u.examples),delete u.examples);let p={schema:s===`components`?o(r,u,E(l)):u,examples:_n(f.length?f:J(i).examples?.filter(e=>D(e)&&!Array.isArray(e)).map(t.omit(c))||[])},m={description:l,content:{[a]:p}};return(d||a===b.raw)&&(m.required=!0),m},Fn=e=>Object.entries(e).reduce((e,[t,n])=>{if(!n)return e;let r={name:t,description:typeof n==`string`?n:n.description};return typeof n==`object`&&n.url&&(r.externalDocs={url:n.url}),e.concat(r)},[]),In=e=>e.length<=50?e:e.slice(0,49)+`…`,X=e=>e.length?e.slice():void 0;var Ln=class extends ne{#e=new Map;#t=new Map;#n=new Map;#r(e,t,n){let r=this.#n.get(e);if(!r){let t=n?0:1;do r=`${n??`Schema`}${t?this.#n.size+t:``}`,t++;while(this.rootDoc.components?.schemas?.[r]);this.#n.set(e,r)}return this.addSchema(r,t),{$ref:`#/components/schemas/${r}`}}#i(e,t,n){let r=n||E(t,e),i=this.#t.get(r);if(i===void 0)return this.#t.set(r,1),r;if(n)throw new M(`Duplicated operationId: "${n}"`,{method:t,isResponse:!1,path:e});return i++,this.#t.set(r,i),`${r}${i}`}#a(e){let t=JSON.stringify(e);for(let e in this.rootDoc.components?.securitySchemes||{})if(t===JSON.stringify(this.rootDoc.components?.securitySchemes?.[e]))return e;let n=(this.#e.get(e.type)||0)+1;return this.#e.set(e.type,n),`${e.type.toUpperCase()}_${n}`}constructor({routing:e,config:n,title:r,version:i,serverUrl:a,descriptions:o,brandHandling:s,tags:c,isHeader:l,hasSummaryFromDescription:u=!0,hasHeadMethod:d=!0,composition:f=`inline`}){super(),this.addInfo({title:r,version:i});for(let e of typeof a==`string`?[a]:a)this.addServer({url:e});let p=(e,r,i)=>{let a={path:r,method:e,endpoint:i,composition:f,brandHandling:s,makeRef:this.#r.bind(this)},{description:c,shortDescription:d,scopes:p,inputSchema:m}=i,h=d?In(d):u&&c?In(c):void 0,g=ge(e,n.inputSources),_=this.#i(r,e,i.getOperationId(e)),ee=Nn({...a,schema:m}),v=Qt(i.security),te=yn({...a,inputSources:g,isHeader:l,security:v,request:ee,description:o?.requestParameter?.call(null,{method:e,path:r,operationId:_})}),ne={};for(let t of V){let n=i.getResponses(t);for(let{mimeTypes:i,schema:s,statusCodes:c}of n)for(let l of c)ne[l]=wn({...a,variant:t,schema:s,mimeTypes:i,statusCode:l,hasMultipleStatusCodes:n.length>1||c.length>1,description:o?.[`${t}Response`]?.call(null,{method:e,path:r,operationId:_,statusCode:l})})}let re=g.includes(`body`)?Pn({...a,request:ee,paramNames:t.pluck(`name`,te),schema:m,mimeType:b[i.requestType],description:o?.requestBody?.call(null,{method:e,path:r,operationId:_})}):void 0,y=Mn(jn(v,g),p,e=>{let t=this.#a(e);return this.addSecurityScheme(t,e),t}),ie={operationId:_,summary:h,description:c,deprecated:i.isDeprecated||void 0,tags:X(i.tags),parameters:X(te),requestBody:re,security:X(y),responses:ne};this.addPath(nn(r),{[e]:ie})};St({routing:e,config:n,onEndpoint:d?ht(p):p}),c&&(this.rootDoc.tags=Fn(c))}};const Rn=e=>ie({...e,headers:{"content-type":b.json,...e?.headers}}),zn=e=>ae(e),Bn=e=>{let t={warn:[],error:[],info:[],debug:[]};return new Proxy(e||{},{get(e,n,r){return n===`_getLogs`?()=>t:it(n)?(...e)=>t[n].push(e):Reflect.get(e,n,r)}})},Vn=({requestProps:e,responseOptions:t,configProps:n,loggerProps:r})=>{let i=Rn(e),a=zn({req:i,...t});a.req=t?.req||i,i.res=a;let o=Bn(r);return{requestMock:i,responseMock:a,loggerMock:o,configMock:{cors:!1,logger:o,...n}}},Hn=async({endpoint:e,...t})=>{let{requestMock:n,responseMock:r,loggerMock:i,configMock:a}=Vn(t);return await e.execute({request:n,response:r,config:a,logger:i}),{requestMock:n,responseMock:r,loggerMock:i}},Un=async({middleware:e,ctx:t={},...n})=>{let{requestMock:r,responseMock:i,loggerMock:a,configMock:{inputSources:o,errorHandler:s=U}}=Vn(n),c={request:r,response:i,logger:a,input:_e(r,o),ctx:t};try{return{requestMock:r,responseMock:i,loggerMock:a,output:await e.execute(c)}}catch(e){return await s.execute({...c,error:S(e),output:null}),{requestMock:r,responseMock:i,loggerMock:a,output:{}}}};var Wn=class e{ts;f;exportModifier;asyncModifier;accessModifiers;#e;static#t=/^[A-Za-z_$][A-Za-z0-9_$]*$/;constructor(e){this.ts=e,this.f=this.ts.factory,this.exportModifier=[this.f.createModifier(this.ts.SyntaxKind.ExportKeyword)],this.asyncModifier=[this.f.createModifier(this.ts.SyntaxKind.AsyncKeyword)],this.accessModifiers={public:[this.f.createModifier(this.ts.SyntaxKind.PublicKeyword)],publicStatic:[this.f.createModifier(this.ts.SyntaxKind.PublicKeyword),this.f.createModifier(this.ts.SyntaxKind.StaticKeyword)],protectedReadonly:[this.f.createModifier(this.ts.SyntaxKind.ProtectedKeyword),this.f.createModifier(this.ts.SyntaxKind.ReadonlyKeyword)]},this.#e=[this.ts.SyntaxKind.AnyKeyword,this.ts.SyntaxKind.BigIntKeyword,this.ts.SyntaxKind.BooleanKeyword,this.ts.SyntaxKind.NeverKeyword,this.ts.SyntaxKind.NumberKeyword,this.ts.SyntaxKind.ObjectKeyword,this.ts.SyntaxKind.StringKeyword,this.ts.SyntaxKind.SymbolKeyword,this.ts.SyntaxKind.UndefinedKeyword,this.ts.SyntaxKind.UnknownKeyword,this.ts.SyntaxKind.VoidKeyword]}addJsDoc=(e,t)=>this.ts.addSyntheticLeadingComment(e,this.ts.SyntaxKind.MultiLineCommentTrivia,`* ${t} `,!0);printNode=(e,t)=>{let n=this.ts.createSourceFile(`print.ts`,``,this.ts.ScriptTarget.Latest,!1,this.ts.ScriptKind.TS);return this.ts.createPrinter(t).printNode(this.ts.EmitHint.Unspecified,e,n)};makeId=e=>this.f.createIdentifier(e);makePropertyIdentifier=t=>typeof t==`string`&&e.#t.test(t)?this.makeId(t):this.literally(t);makeTemplate=(e,...t)=>this.f.createTemplateExpression(this.f.createTemplateHead(e),t.map(([e,n=``],r)=>this.f.createTemplateSpan(typeof e==`string`?this.makeId(e):e,r===t.length-1?this.f.createTemplateTail(n):this.f.createTemplateMiddle(n))));makeParam=(e,{type:t,mod:n,initId:r,optional:i}={})=>this.f.createParameterDeclaration(n,void 0,e,i?this.f.createToken(this.ts.SyntaxKind.QuestionToken):void 0,t?this.ensureTypeNode(t):void 0,r?this.makeId(r):void 0);makeParams=e=>Object.entries(e).map(([e,t])=>this.makeParam(e,typeof t==`string`||typeof t==`number`||typeof t==`object`&&`kind`in t?{type:t}:t));makePublicConstructor=(e,t=[])=>this.f.createConstructorDeclaration(this.accessModifiers.public,e,this.f.createBlock(t));ensureTypeNode=(e,n)=>typeof e==`number`?this.f.createKeywordTypeNode(e):typeof e==`string`||this.ts.isIdentifier(e)?this.f.createTypeReferenceNode(e,n&&t.map(this.ensureTypeNode,n)):e;makeRecordStringAny=()=>this.ensureTypeNode(`Record`,[this.ts.SyntaxKind.StringKeyword,this.ts.SyntaxKind.AnyKeyword]);makeUnion=e=>{let t=new Map;for(let n of e)t.set(this.isPrimitive(n)?n.kind:n,n);return this.f.createUnionTypeNode(Array.from(t.values()))};makeInterfaceProp=(e,n,{isOptional:r,hasUndefined:i=r,isDeprecated:a,comment:o}={})=>{let s=this.ensureTypeNode(n),c=this.f.createPropertySignature(void 0,this.makePropertyIdentifier(e),r?this.f.createToken(this.ts.SyntaxKind.QuestionToken):void 0,i?this.makeUnion([s,this.ensureTypeNode(this.ts.SyntaxKind.UndefinedKeyword)]):s),l=t.reject(t.isNil,[a?`@deprecated`:void 0,o]);return l.length?this.addJsDoc(c,l.join(` `)):c};makeOneLine=e=>this.ts.setEmitFlags(e,this.ts.EmitFlags.SingleLine);makeDeconstruction=(...e)=>this.f.createArrayBindingPattern(e.map(e=>this.f.createBindingElement(void 0,void 0,e)));makeConst=(e,t,{type:n,expose:r}={})=>this.f.createVariableStatement(r&&this.exportModifier,this.f.createVariableDeclarationList([this.f.createVariableDeclaration(e,void 0,n?this.ensureTypeNode(n):void 0,t)],this.ts.NodeFlags.Const));makePublicLiteralType=(e,n)=>this.makeType(e,this.makeUnion(t.map(this.makeLiteralType,n)),{expose:!0});makeType=(e,t,{expose:n,comment:r,params:i}={})=>{let a=this.f.createTypeAliasDeclaration(n?this.exportModifier:void 0,e,i&&this.makeTypeParams(i),t);return r?this.addJsDoc(a,r):a};makePublicProperty=(e,t)=>this.f.createPropertyDeclaration(this.accessModifiers.public,e,void 0,this.ensureTypeNode(t),void 0);makePublicMethod=(e,t,n,{typeParams:r,returns:i,isStatic:a}={})=>this.f.createMethodDeclaration(a?this.accessModifiers.publicStatic:this.accessModifiers.public,void 0,e,void 0,r&&this.makeTypeParams(r),t,i,this.f.createBlock(n));makePublicClass=(e,t,{typeParams:n}={})=>this.f.createClassDeclaration(this.exportModifier,e,n&&this.makeTypeParams(n),void 0,t);makeKeyOf=e=>this.f.createTypeOperatorNode(this.ts.SyntaxKind.KeyOfKeyword,this.ensureTypeNode(e));makePromise=e=>this.ensureTypeNode(Promise.name,[e]);makeInterface=(e,t,{expose:n,comment:r}={})=>{let i=this.f.createInterfaceDeclaration(n?this.exportModifier:void 0,e,void 0,void 0,t);return r?this.addJsDoc(i,r):i};makeTypeParams=e=>(Array.isArray(e)?e.map(e=>t.pair(e,void 0)):Object.entries(e)).map(([e,t])=>{let{type:n,init:r}=typeof t==`object`&&`init`in t?t:{type:t};return this.f.createTypeParameterDeclaration([],e,n?this.ensureTypeNode(n):void 0,r?this.ensureTypeNode(r):void 0)});makeArrowFn=(e,n,{isAsync:r}={})=>this.f.createArrowFunction(r?this.asyncModifier:void 0,void 0,Array.isArray(e)?t.map(this.makeParam,e):this.makeParams(e),void 0,void 0,n);makeTernary=(...e)=>{let[t,n,r]=e.map(e=>typeof e==`string`?this.makeId(e):e);return this.f.createConditionalExpression(t,this.f.createToken(this.ts.SyntaxKind.QuestionToken),n,this.f.createToken(this.ts.SyntaxKind.ColonToken),r)};makeCall=(e,...t)=>(...n)=>this.f.createCallExpression(t.reduce((e,t)=>typeof t==`string`||this.ts.isIdentifier(t)?this.f.createPropertyAccessExpression(e,t):this.f.createElementAccessExpression(e,t),typeof e==`string`?this.makeId(e):e),void 0,n.map(e=>typeof e==`string`?this.makeId(e):e));makeNew=(e,...t)=>this.f.createNewExpression(this.makeId(e),void 0,t);makeExtract=(e,t)=>this.ensureTypeNode(`Extract`,[e,t]);makeAssignment=(e,t)=>this.f.createExpressionStatement(this.f.createBinaryExpression(typeof e==`string`?this.makeId(e):e,this.f.createToken(this.ts.SyntaxKind.EqualsToken),t));makeIndexed=(e,t)=>this.f.createIndexedAccessTypeNode(this.ensureTypeNode(e),this.ensureTypeNode(t));makeMaybeAsync=e=>this.makeUnion([this.ensureTypeNode(e),this.makePromise(e)]);makeFnType=(e,t)=>this.f.createFunctionTypeNode(void 0,this.makeParams(e),this.ensureTypeNode(t));literally=e=>typeof e==`number`?this.f.createNumericLiteral(e):typeof e==`bigint`?this.f.createBigIntLiteral(e.toString()):typeof e==`boolean`?e?this.f.createTrue():this.f.createFalse():e===null?this.f.createNull():this.f.createStringLiteral(e);makeLiteralType=e=>this.f.createLiteralTypeNode(this.literally(e));isPrimitive=e=>this.#e.includes(e.kind)};const Z=e=>e;var Gn=class{api;paths=new Set;tags=new Map;registry=new Map;constructor(e,t){this.serverUrl=t,this.api=new Wn(e)}#e={pathType:`Path`,implementationType:`Implementation`,keyParameter:`key`,pathParameter:`path`,paramsArgument:`params`,ctxArgument:`ctx`,methodParameter:`method`,requestParameter:`request`,eventParameter:`event`,dataParameter:`data`,handlerParameter:`handler`,msgParameter:`msg`,parseRequestFn:`parseRequest`,substituteFn:`substitute`,provideMethod:`provide`,onMethod:`on`,implementationArgument:`implementation`,hasBodyConst:`hasBody`,undefinedValue:`undefined`,responseConst:`response`,restConst:`rest`,searchParamsConst:`searchParams`,defaultImplementationConst:`defaultImplementation`,clientConst:`client`,contentTypeConst:`contentType`,isJsonConst:`isJSON`,sourceProp:`source`,methodType:`Method`,someOfType:`SomeOf`,requestType:`Request`,paginationType:`Pagination`};interfaces={input:`Input`,positive:`PositiveResponse`,negative:`NegativeResponse`,encoded:`EncodedResponse`,response:`Response`};makeMethodType=()=>this.api.makePublicLiteralType(this.#e.methodType,ce);makeSomeOfType=()=>this.api.makeType(this.#e.someOfType,this.api.makeIndexed(`T`,this.api.makeKeyOf(`T`)),{params:[`T`]});makeRequestType=()=>this.api.makeType(this.#e.requestType,this.api.makeKeyOf(this.interfaces.input),{expose:!0});someOf=({name:e})=>this.api.ensureTypeNode(this.#e.someOfType,[e]);makePathType=()=>this.api.makePublicLiteralType(this.#e.pathType,Array.from(this.paths));makePublicInterfaces=()=>Object.keys(this.interfaces).map(e=>this.api.makeInterface(this.interfaces[e],Array.from(this.registry).map(([t,{store:n,isDeprecated:r}])=>this.api.makeInterfaceProp(t,n[e],{isDeprecated:r})),{expose:!0}));makeEndpointTags=()=>this.api.makeConst(`endpointTags`,this.api.f.createObjectLiteralExpression(Array.from(this.tags).map(([e,n])=>this.api.f.createPropertyAssignment(this.api.makePropertyIdentifier(e),this.api.f.createArrayLiteralExpression(t.map(this.api.literally,n))))),{expose:!0});makeImplementationType=()=>this.api.makeType(this.#e.implementationType,this.api.makeFnType({[this.#e.methodParameter]:this.#e.methodType,[this.#e.pathParameter]:this.api.ts.SyntaxKind.StringKeyword,[this.#e.paramsArgument]:this.api.makeRecordStringAny(),[this.#e.ctxArgument]:{optional:!0,type:`T`}},this.api.makePromise(this.api.ts.SyntaxKind.AnyKeyword)),{expose:!0,params:{T:{init:this.api.ts.SyntaxKind.UnknownKeyword}}});makeParseRequestFn=()=>this.api.makeConst(this.#e.parseRequestFn,this.api.makeArrowFn({[this.#e.requestParameter]:this.api.ts.SyntaxKind.StringKeyword},this.api.f.createAsExpression(this.api.makeCall(this.#e.requestParameter,Z(`split`))(this.api.f.createRegularExpressionLiteral(`/ (.+)/`),this.api.literally(2)),this.api.f.createTupleTypeNode([this.api.ensureTypeNode(this.#e.methodType),this.api.ensureTypeNode(this.#e.pathType)]))));makeSubstituteFn=()=>this.api.makeConst(this.#e.substituteFn,this.api.makeArrowFn({[this.#e.pathParameter]:this.api.ts.SyntaxKind.StringKeyword,[this.#e.paramsArgument]:this.api.makeRecordStringAny()},this.api.f.createBlock([this.api.makeConst(this.#e.restConst,this.api.f.createObjectLiteralExpression([this.api.f.createSpreadAssignment(this.api.makeId(this.#e.paramsArgument))])),this.api.f.createForInStatement(this.api.f.createVariableDeclarationList([this.api.f.createVariableDeclaration(this.#e.keyParameter)],this.api.ts.NodeFlags.Const),this.api.makeId(this.#e.paramsArgument),this.api.f.createBlock([this.api.makeAssignment(this.#e.pathParameter,this.api.makeCall(this.#e.pathParameter,Z(`replace`))(this.api.makeTemplate(`:`,[this.#e.keyParameter]),this.api.makeArrowFn([],this.api.f.createBlock([this.api.f.createExpressionStatement(this.api.f.createDeleteExpression(this.api.f.createElementAccessExpression(this.api.makeId(this.#e.restConst),this.api.makeId(this.#e.keyParameter)))),this.api.f.createReturnStatement(this.api.f.createElementAccessExpression(this.api.makeId(this.#e.paramsArgument),this.api.makeId(this.#e.keyParameter)))]))))])),this.api.f.createReturnStatement(this.api.f.createAsExpression(this.api.f.createArrayLiteralExpression([this.api.makeId(this.#e.pathParameter),this.api.makeId(this.#e.restConst)]),this.api.ensureTypeNode(`const`)))])));makePaginationType=()=>{let e=Z(`nextCursor`),t=Z(`total`),n=Z(`limit`),r=Z(`offset`),i=this.api.f.createTypeLiteralNode([this.api.makeInterfaceProp(e,this.api.makeUnion([this.api.ensureTypeNode(this.api.ts.SyntaxKind.StringKeyword),this.api.makeLiteralType(null)]))]),a=this.api.f.createTypeLiteralNode([t,n,r].map(e=>this.api.makeInterfaceProp(e,this.api.ts.SyntaxKind.NumberKeyword)));return this.api.makeType(this.#e.paginationType,this.api.makeUnion([i,a]))};#t=()=>{let e=this.api.makeId(this.#e.responseConst),t=Z(`nextCursor`),n=Z(`total`),r=Z(`limit`),i=Z(`offset`),a=this.api.f.createBinaryExpression(this.api.literally(t),this.api.ts.SyntaxKind.InKeyword,e),o=this.api.f.createReturnStatement(this.api.f.createBinaryExpression(this.api.f.createPropertyAccessExpression(e,t),this.api.ts.SyntaxKind.ExclamationEqualsEqualsToken,this.api.literally(null))),s=this.api.f.createBinaryExpression(this.api.f.createPropertyAccessExpression(e,i),this.api.ts.SyntaxKind.PlusToken,this.api.f.createPropertyAccessExpression(e,r)),c=this.api.f.createReturnStatement(this.api.f.createBinaryExpression(s,this.api.ts.SyntaxKind.LessThanToken,this.api.f.createPropertyAccessExpression(e,n)));return this.api.makePublicMethod(`hasMore`,[this.api.makeParam(e,{type:this.#e.paginationType})],[this.api.f.createIfStatement(a,o),c],{returns:this.api.ensureTypeNode(this.api.ts.SyntaxKind.BooleanKeyword),isStatic:!0})};#n=()=>this.api.makePublicMethod(this.#e.provideMethod,this.api.makeParams({[this.#e.requestParameter]:`K`,[this.#e.paramsArgument]:this.api.makeIndexed(this.interfaces.input,`K`),[this.#e.ctxArgument]:{optional:!0,type:`T`}}),[this.api.makeConst(this.api.makeDeconstruction(this.#e.methodParameter,this.#e.pathParameter),this.api.makeCall(this.#e.parseRequestFn)(this.#e.requestParameter)),this.api.f.createReturnStatement(this.api.makeCall(this.api.f.createThis(),this.#e.implementationArgument)(this.#e.methodParameter,this.api.f.createSpreadElement(this.api.makeCall(this.#e.substituteFn)(this.#e.pathParameter,this.#e.paramsArgument)),this.#e.ctxArgument))],{typeParams:{K:this.#e.requestType},returns:this.api.makePromise(this.api.makeIndexed(this.interfaces.response,`K`))});makeClientClass=e=>this.api.makePublicClass(e,[this.api.makePublicConstructor([this.api.makeParam(this.#e.implementationArgument,{type:this.api.ensureTypeNode(this.#e.implementationType,[`T`]),mod:this.api.accessModifiers.protectedReadonly,initId:this.#e.defaultImplementationConst})]),this.#n(),this.#t()],{typeParams:[`T`]});#r=e=>this.api.makeTemplate(`?`,[this.api.makeNew(URLSearchParams.name,this.api.makeId(e))]);#i=()=>this.api.makeNew(URL.name,this.api.makeTemplate(``,[this.#e.pathParameter],[this.#e.searchParamsConst]),this.api.literally(this.serverUrl));makeDefaultImplementation=()=>{let e=this.api.f.createPropertyAssignment(Z(`method`),this.api.makeCall(this.#e.methodParameter,Z(`toUpperCase`))()),t=this.api.f.createPropertyAssignment(Z(`headers`),this.api.makeTernary(this.#e.hasBodyConst,this.api.f.createObjectLiteralExpression([this.api.f.createPropertyAssignment(this.api.literally(`Content-Type`),this.api.literally(b.json))]),this.#e.undefinedValue)),n=this.api.f.createPropertyAssignment(Z(`body`),this.api.makeTernary(this.#e.hasBodyConst,this.api.makeCall(JSON[Symbol.toStringTag],Z(`stringify`))(this.#e.paramsArgument),this.#e.undefinedValue)),r=this.api.makeConst(this.#e.responseConst,this.api.f.createAwaitExpression(this.api.makeCall(fetch.name)(this.#i(),this.api.f.createObjectLiteralExpression([e,t,n])))),i=this.api.makeConst(this.#e.hasBodyConst,this.api.f.createLogicalNot(this.api.makeCall(this.api.f.createArrayLiteralExpression([this.api.literally(`get`),this.api.literally(`head`),this.api.literally(`delete`)]),Z(`includes`))(this.#e.methodParameter))),a=this.api.makeConst(this.#e.searchParamsConst,this.api.makeTernary(this.#e.hasBodyConst,this.api.literally(``),this.#r(this.#e.paramsArgument))),o=this.api.makeConst(this.#e.contentTypeConst,this.api.makeCall(this.#e.responseConst,Z(`headers`),Z(`get`))(this.api.literally(`content-type`))),s=this.api.f.createIfStatement(this.api.f.createPrefixUnaryExpression(this.api.ts.SyntaxKind.ExclamationToken,this.api.makeId(this.#e.contentTypeConst)),this.api.f.createReturnStatement()),c=this.api.makeConst(this.#e.isJsonConst,this.api.makeCall(this.#e.contentTypeConst,Z(`startsWith`))(this.api.literally(b.json))),l=this.api.f.createReturnStatement(this.api.makeCall(this.#e.responseConst,this.api.makeTernary(this.#e.isJsonConst,this.api.literally(Z(`json`)),this.api.literally(Z(`text`))))());return this.api.makeConst(this.#e.defaultImplementationConst,this.api.makeArrowFn([this.#e.methodParameter,this.#e.pathParameter,this.#e.paramsArgument],this.api.f.createBlock([i,a,r,o,s,c,l]),{isAsync:!0}),{type:this.#e.implementationType})};#a=()=>this.api.makePublicConstructor(this.api.makeParams({request:`K`,params:this.api.makeIndexed(this.interfaces.input,`K`)}),[this.api.makeConst(this.api.makeDeconstruction(this.#e.pathParameter,this.#e.restConst),this.api.makeCall(this.#e.substituteFn)(this.api.f.createElementAccessExpression(this.api.makeCall(this.#e.parseRequestFn)(this.#e.requestParameter),this.api.literally(1)),this.#e.paramsArgument)),this.api.makeConst(this.#e.searchParamsConst,this.#r(this.#e.restConst)),this.api.makeAssignment(this.api.f.createPropertyAccessExpression(this.api.f.createThis(),this.#e.sourceProp),this.api.makeNew(`EventSource`,this.#i()))]);#o=e=>this.api.f.createTypeLiteralNode([this.api.makeInterfaceProp(Z(`event`),e)]);#s=()=>this.api.makePublicMethod(this.#e.onMethod,this.api.makeParams({[this.#e.eventParameter]:`E`,[this.#e.handlerParameter]:this.api.makeFnType({[this.#e.dataParameter]:this.api.makeIndexed(this.api.makeExtract(`R`,this.api.makeOneLine(this.#o(`E`))),this.api.makeLiteralType(Z(`data`)))},this.api.makeMaybeAsync(this.api.ts.SyntaxKind.VoidKeyword))}),[this.api.f.createExpressionStatement(this.api.makeCall(this.api.f.createThis(),this.#e.sourceProp,Z(`addEventListener`))(this.#e.eventParameter,this.api.makeArrowFn([this.#e.msgParameter],this.api.makeCall(this.#e.handlerParameter)(this.api.makeCall(JSON[Symbol.toStringTag],Z(`parse`))(this.api.f.createPropertyAccessExpression(this.api.f.createParenthesizedExpression(this.api.f.createAsExpression(this.api.makeId(this.#e.msgParameter),this.api.ensureTypeNode(MessageEvent.name))),Z(`data`))))))),this.api.f.createReturnStatement(this.api.f.createThis())],{typeParams:{E:this.api.makeIndexed(`R`,this.api.makeLiteralType(Z(`event`)))}});makeSubscriptionClass=e=>this.api.makePublicClass(e,[this.api.makePublicProperty(this.#e.sourceProp,`EventSource`),this.#a(),this.#s()],{typeParams:{K:this.api.makeExtract(this.#e.requestType,this.api.f.createTemplateLiteralType(this.api.f.createTemplateHead(`get `),[this.api.f.createTemplateLiteralTypeSpan(this.api.ensureTypeNode(this.api.ts.SyntaxKind.StringKeyword),this.api.f.createTemplateTail(``))])),R:this.api.makeExtract(this.api.makeIndexed(this.interfaces.positive,`K`),this.api.makeOneLine(this.#o(this.api.ts.SyntaxKind.StringKeyword)))}});makeUsageStatements=(e,t)=>[this.api.makeConst(this.#e.clientConst,this.api.makeNew(e)),this.api.makeCall(this.#e.clientConst,this.#e.provideMethod)(this.api.literally(`get /v1/user/retrieve`),this.api.f.createObjectLiteralExpression([this.api.f.createPropertyAssignment(`id`,this.api.literally(`10`))])),this.api.makeCall(this.api.makeNew(t,this.api.literally(`get /v1/events/stream`),this.api.f.createObjectLiteralExpression()),this.#e.onMethod)(this.api.literally(`time`),this.api.makeArrowFn([`time`],this.api.f.createBlock([])))]};const Kn=(t,{onEach:n,rules:r,onMissing:i,ctx:a={}})=>{let o=e(t),s=o&&o in r?r[o]:r[t._zod.def.type],c=e=>Kn(e,{ctx:a,onEach:n,rules:r,onMissing:i}),l=s?s(t,{...a,next:c}):i(t,a),u=n&&n(t,{prev:l,...a});return u?{...l,...u}:l},qn={name:t.path([`name`,`text`]),type:t.path([`type`]),optional:t.path([`questionToken`])},Jn=({_zod:{def:e}},{api:t})=>{let n=e.values.map(e=>e===void 0?t.ensureTypeNode(t.ts.SyntaxKind.UndefinedKeyword):t.makeLiteralType(e));return n.length===1?n[0]:t.makeUnion(n)},Yn=({_zod:{def:e}},{next:t,api:n})=>{let r=[...e.parts],i=()=>{let e=``;for(;r.length;){let t=r.shift();if(w(t)){r.unshift(t);break}e+=t??``}return e},a=n.f.createTemplateHead(i()),o=[];for(;r.length;){let e=t(r.shift()),a=i(),s=r.length?n.f.createTemplateMiddle:n.f.createTemplateTail;o.push(n.f.createTemplateLiteralTypeSpan(e,s(a)))}return o.length?n.f.createTemplateLiteralType(a,o):n.makeLiteralType(a.text)},Xn=(e,{isResponse:t,next:i,makeAlias:a,api:o})=>{let s=()=>{let a=Object.entries(e._zod.def.shape).map(([e,a])=>{let{description:s,deprecated:c}=n.get(a)||{},l=(t?a._zod.optout:a._zod.optin)===`optional`,u=l&&!(a instanceof r.core.$ZodExactOptional);return o.makeInterfaceProp(e,i(a),{comment:s,isDeprecated:c,isOptional:l,hasUndefined:u})});return o.f.createTypeLiteralNode(a)};return Le(e,{io:t?`output`:`input`})?a(e,s):s()},Zn=({_zod:{def:e}},{next:t,api:n})=>n.f.createArrayTypeNode(t(e.element)),Qn=({_zod:{def:e}},{api:n})=>n.makeUnion(t.map(n.makeLiteralType,Object.values(e.entries))),$n=({_zod:{def:e}},{next:t,api:n})=>n.makeUnion(e.options.map(t)),er=({_zod:{def:e}},{next:t,api:n})=>n.makeUnion([t(e.innerType),n.makeLiteralType(null)]),tr=({_zod:{def:e}},{next:t,api:n})=>n.f.createTupleTypeNode(e.items.map(t).concat(e.rest===null?[]:n.f.createRestTypeNode(t(e.rest)))),nr=({_zod:{def:e}},{next:t,api:n})=>{let[r,i]=[e.keyType,e.valueType].map(t),a=n.ensureTypeNode(`Record`,[r,i]);return e.mode===`loose`?n.f.createIntersectionTypeNode([a,n.ensureTypeNode(`Record`,[`PropertyKey`,i])]):a},rr=t.tryCatch((e,n)=>{if(!n.every(e.ts.isTypeLiteralNode))throw Error(`Not objects`);let r=t.chain(t.prop(`members`),n),i=t.uniqWith((...e)=>{if(!t.eqBy(qn.name,...e))return!1;if(t.both(t.eqBy(qn.type),t.eqBy(qn.optional))(...e))return!0;throw Error(`Has conflicting prop`)},r);return e.f.createTypeLiteralNode(i)},(e,t,n)=>t.f.createIntersectionTypeNode(n)),ir=({_zod:{def:e}},{next:t,api:n})=>rr(n,[e.left,e.right].map(t)),Q=e=>({},{api:t})=>t.ensureTypeNode(t.ts.SyntaxKind[e]),$=({_zod:{def:e}},{next:t})=>t(e.innerType),ar=(e,t)=>e.ensureTypeNode(t?e.ts.SyntaxKind.UnknownKeyword:e.ts.SyntaxKind.AnyKeyword),or=({_zod:{def:e}},{next:t,isResponse:n,api:r})=>{let i=e[n?`out`:`in`],a=e[n?`in`:`out`];if(!w(i,`transform`))return t(i);let o=t(a),s={[r.ts.SyntaxKind.AnyKeyword]:``,[r.ts.SyntaxKind.BigIntKeyword]:BigInt(0),[r.ts.SyntaxKind.BooleanKeyword]:!1,[r.ts.SyntaxKind.NumberKeyword]:0,[r.ts.SyntaxKind.ObjectKeyword]:{},[r.ts.SyntaxKind.StringKeyword]:``,[r.ts.SyntaxKind.UndefinedKeyword]:void 0}[o.kind],c=ye(i,s),l={number:r.ts.SyntaxKind.NumberKeyword,bigint:r.ts.SyntaxKind.BigIntKeyword,boolean:r.ts.SyntaxKind.BooleanKeyword,string:r.ts.SyntaxKind.StringKeyword,undefined:r.ts.SyntaxKind.UndefinedKeyword,object:r.ts.SyntaxKind.ObjectKeyword};return r.ensureTypeNode(c&&l[c]||ar(r,n))},sr=({},{api:e})=>e.makeLiteralType(null),cr=({_zod:{def:e}},{makeAlias:t,next:n})=>t(e.getter,()=>n(e.getter())),lr=({},{api:e})=>e.ensureTypeNode(`Buffer`),ur=(e,{next:t})=>t(e._zod.def.shape.raw),dr={string:Q(`StringKeyword`),number:Q(`NumberKeyword`),bigint:Q(`BigIntKeyword`),boolean:Q(`BooleanKeyword`),any:Q(`AnyKeyword`),undefined:Q(`UndefinedKeyword`),[k]:Q(`StringKeyword`),[A]:Q(`StringKeyword`),never:Q(`NeverKeyword`),void:Q(`UndefinedKeyword`),unknown:Q(`UnknownKeyword`),null:sr,array:Zn,tuple:tr,record:nr,object:Xn,literal:Jn,template_literal:Yn,intersection:ir,union:$n,default:$,enum:Qn,optional:$,nonoptional:$,nullable:er,catch:$,pipe:or,lazy:cr,readonly:$,[O]:lr,[F]:ur},fr=(e,{brandHandling:t,ctx:n})=>Kn(e,{rules:{...t,...dr},onMissing:({},{isResponse:e,api:t})=>ar(t,e),ctx:n});var pr=class e extends Gn{#e=[this.makeSomeOfType()];#t=new Map;#n=[];#r(e,t){let n=this.#t.get(e)?.name?.text;if(!n){n=`Type${this.#t.size+1}`;let r=this.api.makeLiteralType(null);this.#t.set(e,this.api.makeType(n,r)),this.#t.set(e,this.api.makeType(n,t()))}return this.api.ensureTypeNode(n)}constructor({typescript:e,routing:n,config:i,brandHandling:a,variant:o=`client`,clientClassName:s=`Client`,subscriptionClassName:c=`Subscription`,serverUrl:l=`https://example.com`,noContent:u=r.undefined(),hasHeadMethod:d=!0}){super(e,l);let f={makeAlias:this.#r.bind(this),api:this.api},p={brandHandling:a,ctx:{...f,isResponse:!1}},m={brandHandling:a,ctx:{...f,isResponse:!0}},h=(e,n,r)=>{let i=E.bind(null,e,n),{isDeprecated:a,inputSchema:o,tags:s}=r,c=`${e} ${n}`,l=this.api.makeType(i(`input`),fr(o,p),{comment:c});this.#e.push(l);let d=V.reduce((n,a)=>{let o=r.getResponses(a),s=t.chain(([t,{schema:n,mimeTypes:r,statusCodes:o}])=>{let s=xe(e,r),l=this.api.makeType(i(a,`variant`,`${t+1}`),fr(s?n:u,m),{comment:c});return this.#e.push(l),o.map(e=>this.api.makeInterfaceProp(e,l.name))},Array.from(o.entries())),l=this.api.makeInterface(i(a,`response`,`variants`),s,{comment:c});return this.#e.push(l),Object.assign(n,{[a]:l})},{});this.paths.add(n);let f=this.api.makeLiteralType(c),h={input:this.api.ensureTypeNode(l.name),positive:this.someOf(d.positive),negative:this.someOf(d.negative),response:this.api.makeUnion([this.api.makeIndexed(this.interfaces.positive,f),this.api.makeIndexed(this.interfaces.negative,f)]),encoded:this.api.f.createIntersectionTypeNode([this.api.ensureTypeNode(d.positive.name),this.api.ensureTypeNode(d.negative.name)])};this.registry.set(c,{isDeprecated:a,store:h}),this.tags.set(c,s)};St({routing:n,config:i,onEndpoint:d?ht(h):h}),this.#e.unshift(...this.#t.values()),this.#e.push(this.makePathType(),this.makeMethodType(),...this.makePublicInterfaces(),this.makeRequestType()),o!==`types`&&(this.#e.push(this.makeEndpointTags(),this.makeParseRequestFn(),this.makeSubstituteFn(),this.makeImplementationType(),this.makePaginationType(),this.makeDefaultImplementation(),this.makeClientClass(s),this.makeSubscriptionClass(c)),this.#n.push(...this.makeUsageStatements(s,c)))}static async create(t){return new e({...t,typescript:await q(`typescript`)})}#i(e){return this.#n.length?this.#n.map(t=>typeof t==`string`?t:this.api.printNode(t,e)).join(`
|
|
18
19
|
`):void 0}print(e){let t=this.#i(e),n=t&&this.api.ts.addSyntheticLeadingComment(this.api.ts.addSyntheticLeadingComment(this.api.f.createEmptyStatement(),this.api.ts.SyntaxKind.SingleLineCommentTrivia,` Usage example:`),this.api.ts.SyntaxKind.MultiLineCommentTrivia,`\n${t}`);return this.#e.concat(n||[]).map((t,n)=>this.api.printNode(t,n<this.#e.length?e:{...e,omitTrailingSemicolon:!0})).join(`
|
|
19
20
|
|
|
20
21
|
`)}async printFormatted({printerOptions:e,format:t}={}){let n=t;if(!n)try{let e=(await q(`prettier`)).format;n=t=>e(t,{filepath:`client.ts`})}catch{}let r=this.#i(e);this.#n=r&&n?[await n(r)]:this.#n;let i=this.print(e);return n?n(i):i}};const mr=(e,t)=>r.object({data:t,event:r.literal(e),id:r.string().optional(),retry:r.int().positive().optional()}),hr=(e,t,n)=>mr(String(t),e[t]).transform(e=>[`event: ${e.event}`,`data: ${JSON.stringify(e.data)}`,``,``].join(`
|
|
21
|
-
`)).parse({event:t,data:n}),gr=e=>e.headersSent||e.writeHead(200,{connection:`keep-alive`,"content-type":b.sse,"cache-control":`no-cache`}),_r=e=>new R({handler:async({request:t,response:n})=>{let r=new AbortController;return t.once(`close`,()=>{r.abort()}),setTimeout(()=>gr(n),1e4),{isClosed:()=>n.writableEnded||n.closed,signal:r.signal,emit:(t,r)=>{gr(n),n.write(hr(e,t,r),`utf-8`),n.flush?.()}}}}),vr=e=>new H({positive:()=>{let[t,...n]=Object.entries(e).map(([e,t])=>mr(e,t));return{mimeType:b.sse,schema:n.length?r.discriminatedUnion(`event`,[t,...n]):t}},negative:{mimeType:`text/plain`,schema:r.string()},handler:async({response:e,error:t,logger:n,request:r,input:i})=>{if(t){let a=I(t);He(a,n,r,i),e.headersSent||e.status(a.statusCode).type(`text/plain`).write(L(a),`utf-8`)}e.end()}});var yr=class extends W{constructor(e){super(vr(e)),this.middlewares=[_r(e)]}};const br={dateIn:Ce,dateOut:we,form:je,upload:Me,raw:Fe,buffer:Se};export{st as BuiltinLogger,Ln as Documentation,M as DocumentationError,W as EndpointsFactory,yr as EventStreamFactory,N as InputValidationError,pr as Integration,R as Middleware,ke as MissingPeerError,De as OutputValidationError,H as ResultHandler,j as RoutingError,ct as ServeStatic,tt as arrayEndpointsFactory,$e as arrayResultHandler,qt as attachRouting,oe as createConfig,Jt as createServer,et as defaultEndpointsFactory,U as defaultResultHandler,I as ensureHttpError,
|
|
22
|
+
`)).parse({event:t,data:n}),gr=e=>e.headersSent||e.writeHead(200,{connection:`keep-alive`,"content-type":b.sse,"cache-control":`no-cache`}),_r=e=>new R({handler:async({request:t,response:n})=>{let r=new AbortController;return t.once(`close`,()=>{r.abort()}),setTimeout(()=>gr(n),1e4),{isClosed:()=>n.writableEnded||n.closed,signal:r.signal,emit:(t,r)=>{gr(n),n.write(hr(e,t,r),`utf-8`),n.flush?.()}}}}),vr=e=>new H({positive:()=>{let[t,...n]=Object.entries(e).map(([e,t])=>mr(e,t));return{mimeType:b.sse,schema:n.length?r.discriminatedUnion(`event`,[t,...n]):t}},negative:{mimeType:`text/plain`,schema:r.string()},handler:async({response:e,error:t,logger:n,request:r,input:i})=>{if(t){let a=I(t);He(a,n,r,i),e.headersSent||e.status(a.statusCode).type(`text/plain`).write(L(a),`utf-8`)}e.end()}});var yr=class extends W{constructor(e){super(vr(e)),this.middlewares=[_r(e)]}};const br=[`total`,`limit`,`offset`],xr=[`nextCursor`,`limit`];function Sr({style:e,itemSchema:t,itemsName:n=`items`,maxLimit:i=100,defaultLimit:a=20}){if(!Number.isInteger(i)||i<1)throw Error(`ez.paginated: maxLimit must be a positive integer`);if(!Number.isInteger(a)||a<1)throw Error(`ez.paginated: defaultLimit must be a positive integer`);if(a>i)throw Error(`ez.paginated: defaultLimit must not be greater than maxLimit`);if(e===`offset`&&br.includes(n))throw Error(`ez.paginated: itemsName must not match reserved keys for offset output (${br.join(`, `)})`);if(e===`cursor`&&xr.includes(n))throw Error(`ez.paginated: itemsName must not match reserved keys for cursor output (${xr.join(`, `)})`);let o=r.coerce.number().int().min(1).max(i).default(a).describe(`Page size (number of ${n} per page)`);if(e===`offset`){let e=r.coerce.number().int().min(0).default(0).describe(`Number of ${n} to skip`);return{input:r.object({limit:o,offset:e}),output:r.object({[n]:r.array(t).describe(`Page of ${n}`),total:r.number().int().min(0).describe(`Total number of ${n}`),limit:r.number().int().min(1).describe(`Page size used`),offset:r.number().int().min(0).describe(`Offset used`)})}}let s=r.string().optional().describe(`Cursor for the next page; omit for first page`);return{input:r.object({cursor:s,limit:o}),output:r.object({[n]:r.array(t).describe(`Page of ${n}`),nextCursor:r.string().nullable().describe(`Cursor for the next page, or null if no more pages`),limit:r.number().int().min(1).describe(`Page size used`)})}}const Cr={dateIn:Ce,dateOut:we,form:je,upload:Me,raw:Fe,buffer:Se,paginated:Sr};export{st as BuiltinLogger,Ln as Documentation,M as DocumentationError,W as EndpointsFactory,yr as EventStreamFactory,N as InputValidationError,pr as Integration,R as Middleware,ke as MissingPeerError,De as OutputValidationError,H as ResultHandler,j as RoutingError,ct as ServeStatic,tt as arrayEndpointsFactory,$e as arrayResultHandler,qt as attachRouting,oe as createConfig,Jt as createServer,et as defaultEndpointsFactory,U as defaultResultHandler,I as ensureHttpError,Cr as ez,C as getMessageFromError,Hn as testEndpoint,Un as testMiddleware};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "express-zod-api",
|
|
3
|
-
"version": "27.
|
|
3
|
+
"version": "27.1.0",
|
|
4
4
|
"description": "A Typescript framework to help you get an API server up and running with I/O schema validation and custom middlewares in minutes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"node-mocks-http": "^1.17.2",
|
|
39
39
|
"openapi3-ts": "^4.5.0",
|
|
40
40
|
"ramda": "^0.32.0",
|
|
41
|
-
"@express-zod-api/zod-plugin": "^4.0.
|
|
41
|
+
"@express-zod-api/zod-plugin": "^4.0.1"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"@types/compression": "^1.7.5",
|