express-zod-api 2.3.3 → 2.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +76 -1
  2. package/LICENSE +52 -0
  3. package/README.md +49 -11
  4. package/dist/api-response.d.ts +7 -0
  5. package/dist/api-response.js +12 -0
  6. package/dist/api-response.js.map +1 -0
  7. package/dist/config-type.d.ts +4 -0
  8. package/dist/config-type.js.map +1 -1
  9. package/dist/endpoint.d.ts +16 -10
  10. package/dist/endpoint.js +30 -11
  11. package/dist/endpoint.js.map +1 -1
  12. package/dist/endpoints-factory.d.ts +6 -2
  13. package/dist/endpoints-factory.js +3 -1
  14. package/dist/endpoints-factory.js.map +1 -1
  15. package/dist/errors.d.ts +6 -0
  16. package/dist/errors.js +14 -1
  17. package/dist/errors.js.map +1 -1
  18. package/dist/extend-zod.d.ts +2 -0
  19. package/dist/extend-zod.js +3 -1
  20. package/dist/extend-zod.js.map +1 -1
  21. package/dist/file-schema.d.ts +2 -2
  22. package/dist/file-schema.js +4 -5
  23. package/dist/file-schema.js.map +1 -1
  24. package/dist/helpers.d.ts +4 -5
  25. package/dist/helpers.js +10 -13
  26. package/dist/helpers.js.map +1 -1
  27. package/dist/index.d.ts +2 -1
  28. package/dist/index.js +2 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/logger.js +1 -1
  31. package/dist/logger.js.map +1 -1
  32. package/dist/mime.d.ts +3 -0
  33. package/dist/mime.js +7 -0
  34. package/dist/mime.js.map +1 -0
  35. package/dist/open-api.js +57 -26
  36. package/dist/open-api.js.map +1 -1
  37. package/dist/result-handler.d.ts +11 -1
  38. package/dist/result-handler.js +14 -7
  39. package/dist/result-handler.js.map +1 -1
  40. package/dist/routing.js +3 -3
  41. package/dist/routing.js.map +1 -1
  42. package/dist/server.d.ts +4 -0
  43. package/dist/server.js +67 -28
  44. package/dist/server.js.map +1 -1
  45. package/dist/upload-schema.d.ts +11 -0
  46. package/dist/upload-schema.js +28 -0
  47. package/dist/upload-schema.js.map +1 -0
  48. package/package.json +5 -1
package/CHANGELOG.md CHANGED
@@ -2,9 +2,84 @@
2
2
 
3
3
  ## Version 2
4
4
 
5
+ ### v2.5.2
6
+
7
+ - Fixed a bug due to which the API did not respond in case of an error within the `ResultHandler`.
8
+ - In this case the `LastResortHandler` comes into play.
9
+ - It sets the status code to `500` and sends out plain text with an error message.
10
+ - It is not customizable yet, and it's meant to be kept very simple in case of JSON conversion errors.
11
+
12
+ ### v2.5.1
13
+
14
+ - Fixed a bug due to which the execution of the code could continue despite the possible closing of the response
15
+ stream by one of the middlewares.
16
+ - Affected Node versions: below 12.9.0.
17
+
18
+ ### v2.5.0
19
+
20
+ - New feature: file uploads!
21
+ - The processing of files is provided by `express-fileupload` which is based on `busboy`.
22
+ - Introducing the new schema: `z.upload()`.
23
+ - New configuration option:
24
+ ```typescript
25
+ const config = createConfig({
26
+ server: {
27
+ upload: true,
28
+ // or selected express-fileupload's options:
29
+ // @see https://github.com/richardgirges/express-fileupload#available-options
30
+ upload: {
31
+ uploadTimeout: 60000,
32
+ useTempFiles: true,
33
+ safeFileNames: true,
34
+ preserveExtension: 4,
35
+ tempFileDir: '/var/tmp'
36
+ }
37
+ },
38
+ });
39
+ ```
40
+ - Creating the `Endpoint`:
41
+ ```typescript
42
+ const fileUploadEndpoint = defaultEndpointsFactory.build({
43
+ method: 'post',
44
+ type: 'upload', // <- new option, required
45
+ input: z.object({
46
+ avatar: z.upload()
47
+ }),
48
+ output: z.object({...}),
49
+ handler: async ({input: {avatar}}) => {
50
+ // avatar: {name, mv(), mimetype, encoding, data, truncated, size, ...}
51
+ // avatar.truncated is true on failure
52
+ return {...};
53
+ }
54
+ });
55
+ ```
56
+ - The file upload currently supports requests having POST method and `multipart/form-data` content type.
57
+ - You can send other data and specify additional `input` parameters, including arrays and objects.
58
+ - Fixed the OPTIONS duplication issue in response header when `cors` option is enabled:
59
+ ```http request
60
+ # before
61
+ Access-Control-Allow-Methods: POST, OPTIONS, OPTIONS
62
+ # after
63
+ Access-Control-Allow-Methods: POST, OPTIONS
64
+ ```
65
+
66
+ ### v2.4.0
67
+
68
+ - Zod version is 3.8.2.
69
+ - Supporting new string format: `cuid`.
70
+ - Supporting new Zod schema `z.preprocess()`.
71
+ Please avoid using it for Endpoint outputs.
72
+ - Supporting default values of optional properties in OpenAPI/Swagger documentation.
73
+ ```typescript
74
+ // example
75
+ z.object({
76
+ name: z.string().optional().default('John Wick')
77
+ });
78
+ ```
79
+
5
80
  ### v2.3.3
6
81
 
7
- - Zod version is 3.7.3
82
+ - Zod version is 3.7.3.
8
83
  - Removed usage of the deprecated `ZodObject`'s method `.nonstrict()` in the example and Readme since it's not required.
9
84
 
10
85
  ### v2.3.2
package/LICENSE CHANGED
@@ -150,3 +150,55 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
150
150
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
151
151
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
152
152
  THE SOFTWARE.
153
+
154
+
155
+
156
+ Mime - https://github.com/broofa/mime
157
+
158
+ The MIT License (MIT)
159
+
160
+ Copyright (c) 2010 Benjamin Thomas, Robert Kieffer
161
+
162
+ Permission is hereby granted, free of charge, to any person obtaining a copy
163
+ of this software and associated documentation files (the "Software"), to deal
164
+ in the Software without restriction, including without limitation the rights
165
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
166
+ copies of the Software, and to permit persons to whom the Software is
167
+ furnished to do so, subject to the following conditions:
168
+
169
+ The above copyright notice and this permission notice shall be included in
170
+ all copies or substantial portions of the Software.
171
+
172
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
173
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
174
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
175
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
176
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
177
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
178
+ THE SOFTWARE.
179
+
180
+
181
+
182
+ Express-FileUpload - https://github.com/richardgirges/express-fileupload
183
+
184
+ The MIT License (MIT)
185
+
186
+ Copyright (c) 2015 Richard Girges
187
+
188
+ Permission is hereby granted, free of charge, to any person obtaining a copy
189
+ of this software and associated documentation files (the "Software"), to deal
190
+ in the Software without restriction, including without limitation the rights
191
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
192
+ copies of the Software, and to permit persons to whom the Software is
193
+ furnished to do so, subject to the following conditions:
194
+
195
+ The above copyright notice and this permission notice shall be included in all
196
+ copies or substantial portions of the Software.
197
+
198
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
199
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
200
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
201
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
202
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
203
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
204
+ SOFTWARE.
package/README.md CHANGED
@@ -19,7 +19,7 @@ Start your API server with I/O schema validation and custom middlewares in minut
19
19
  4. [Basic usage](#basic-usage)
20
20
  1. [Set up config](#set-up-config)
21
21
  2. [Create an endpoints factory](#create-an-endpoints-factory)
22
- 3. [Create your first endpoint](#create-your-first-endpoint)
22
+ 3. [Create your first endpoint](#create-your-first-endpoint)
23
23
  4. [Set up routing](#set-up-routing)
24
24
  5. [Start your server](#start-your-server)
25
25
  5. [Advanced usage](#advanced-usage)
@@ -27,10 +27,11 @@ Start your API server with I/O schema validation and custom middlewares in minut
27
27
  2. [Refinements](#refinements)
28
28
  3. [Transformations](#transformations)
29
29
  4. [ResultHandler](#resulthandler)
30
- 5. [Non-object response](#non-object-response)
31
- 6. [Your custom logger](#your-custom-logger)
32
- 7. [Your custom server](#your-custom-server)
33
- 8. [Multiple schemas for a single route](#multiple-schemas-for-a-single-route)
30
+ 5. [Non-object response](#non-object-response) including file downloads
31
+ 6. [File uploads](#file-uploads)
32
+ 7. [Your custom logger](#your-custom-logger)
33
+ 8. [Your custom server](#your-custom-server)
34
+ 9. [Multiple schemas for a single route](#multiple-schemas-for-a-single-route)
34
35
  6. [Disclosing API specifications](#disclosing-api-specifications)
35
36
  1. [Reusing endpoint types on your frontend](#reusing-endpoint-types-on-your-frontend)
36
37
  2. [Swagger / OpenAPI Specification](#swagger--openapi-specification)
@@ -50,8 +51,8 @@ If you're upgrading from v1 please check out the information in [Changelog](CHAN
50
51
 
51
52
  # Concept
52
53
  The API operates object schemas for input and output, including unions and intersections of object schemas
53
- (`.or()`, `.and()`), but in general the API can respond with any data type
54
- *(see [advanced example below](#non-object-response))*.
54
+ (`.or()`, `.and()`), but in general the API can [respond with any data type](#non-object-response) and
55
+ accept [file uploads](#file-uploads).
55
56
 
56
57
  The object being validated is the `request.query` for GET request, the `request.body` for PUT, PATCH and POST requests,
57
58
  or their merging for DELETE requests.
@@ -306,10 +307,13 @@ import {EndpointsFactory} from 'express-zod-api';
306
307
  const endpointsFactory = new EndpointsFactory(myResultHandler);
307
308
  ```
308
309
 
310
+ Please note: `ResultHandler` must handle any errors and not throw its own. Otherwise, the case will be passed to the
311
+ `LastResortHandler`, which will set the status code to `500` and send the error message as plain text.
312
+
309
313
  ## Non-object response
310
314
 
311
- Starting from the version 2.0.0, `ResultHandler` also supports non-object response types, for example, sending an
312
- image file including its MIME type in `Content-type` header.
315
+ `ResultHandler` also supports non-object response types, for example, sending an image file including its MIME type
316
+ in `Content-type` header.
313
317
 
314
318
  You can find two approaches to `EndpointsFactory` and `ResultHandler` implementation
315
319
  [in this example](https://github.com/RobinTail/express-zod-api/blob/master/example/factories.ts).
@@ -343,6 +347,39 @@ const fileStreamingEndpointsFactory = new EndpointsFactory(
343
347
  );
344
348
  ```
345
349
 
350
+ ## File uploads
351
+
352
+ Starting from the version 2.5.0 you can switch the `Endpoint` to handle requests with the `multipart/formdata`
353
+ content type instead of JSON. Together with a corresponding configuration option, this makes it possible to handle
354
+ file uploads. Here is a simplified example:
355
+
356
+ ```typescript
357
+ import {createConfig, z, defaultEndpointsFactory} from 'express-zod-api';
358
+
359
+ const config = createConfig({
360
+ server: {
361
+ upload: true, // <- required
362
+ ...
363
+ },
364
+ });
365
+
366
+ const fileUploadEndpoint = defaultEndpointsFactory.build({
367
+ method: 'post',
368
+ type: 'upload', // <- required
369
+ input: z.object({
370
+ avatar: z.upload()
371
+ }),
372
+ output: z.object({...}),
373
+ handler: async ({input: {avatar}}) => {
374
+ // avatar: {name, mv(), mimetype, encoding, data, truncated, size, ...}
375
+ // avatar.truncated is true on failure
376
+ return {...};
377
+ }
378
+ });
379
+ ```
380
+
381
+ You can still send other data and specify additional `input` parameters, including arrays and objects.
382
+
346
383
  ## Your custom logger
347
384
 
348
385
  You can specify your custom Winston logger in config:
@@ -409,8 +446,9 @@ export type MyEndpointType = typeof endpoint;
409
446
 
410
447
  Then use provided helpers to obtain their input and response types:
411
448
  ```typescript
412
- import {EndpointInput, EndpointResponse} from 'express-zod-api';
413
- import {MyEndpointType} from '../your/backend';
449
+ import {EndpointInput, EndpointResponse} from 'express-zod-api';
450
+ import type {MyEndpointType} from '../your/backend';
451
+ // ^---- please note the import syntax of the type only
414
452
 
415
453
  type MyEndpointInput = EndpointInput<MyEndpointType>;
416
454
  // unites the positive and the negative response schemas:
@@ -0,0 +1,7 @@
1
+ import { z } from 'zod';
2
+ import { MimeDefinition } from './mime';
3
+ export declare type ApiResponse<A = z.ZodTypeAny> = {
4
+ schema: A;
5
+ mimeTypes: string[];
6
+ };
7
+ export declare const createApiResponse: <S extends z.ZodTypeAny>(schema: S, mimeTypes?: MimeDefinition) => ApiResponse<S>;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createApiResponse = void 0;
4
+ const mime_1 = require("./mime");
5
+ const createApiResponse = (schema, mimeTypes = mime_1.mimeJson) => {
6
+ return {
7
+ schema,
8
+ mimeTypes: typeof mimeTypes === 'string' ? [mimeTypes] : mimeTypes,
9
+ };
10
+ };
11
+ exports.createApiResponse = createApiResponse;
12
+ //# sourceMappingURL=api-response.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-response.js","sourceRoot":"","sources":["../src/api-response.ts"],"names":[],"mappings":";;;AACA,iCAAgD;AAOzC,MAAM,iBAAiB,GAAG,CAAyB,MAAS,EAAE,YAA4B,eAAQ,EAAE,EAAE;IAC3G,OAAO;QACL,MAAM;QACN,SAAS,EAAE,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS;KACjD,CAAC;AACtB,CAAC,CAAC;AALW,QAAA,iBAAiB,qBAK5B"}
@@ -1,5 +1,6 @@
1
1
  import { NextHandleFunction } from 'connect';
2
2
  import { Express } from 'express';
3
+ import fileUpload from 'express-fileupload';
3
4
  import { Logger } from 'winston';
4
5
  import { ResultHandlerDefinition } from './result-handler';
5
6
  export declare const loggerLevels: {
@@ -11,10 +12,12 @@ export interface LoggerConfig {
11
12
  level: keyof typeof loggerLevels;
12
13
  color: boolean;
13
14
  }
15
+ declare type UploadOptions = Pick<fileUpload.Options, 'createParentPath' | 'uriDecodeFileNames' | 'safeFileNames' | 'preserveExtension' | 'useTempFiles' | 'tempFileDir' | 'debug' | 'uploadTimeout'>;
14
16
  export interface ServerConfig {
15
17
  server: {
16
18
  listen: number | string;
17
19
  jsonParser?: NextHandleFunction;
20
+ upload?: boolean | UploadOptions;
18
21
  };
19
22
  }
20
23
  export interface AppConfig {
@@ -33,3 +36,4 @@ export declare const createConfig: <T extends (ServerConfig | AppConfig) & Commo
33
36
  * @todo remove in v3
34
37
  * */
35
38
  export declare type ConfigType = (ServerConfig | AppConfig) & CommonConfig;
39
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"config-type.js","sourceRoot":"","sources":["../src/config-type.ts"],"names":[],"mappings":";;;AAKa,QAAA,YAAY,GAAG;IAC1B,MAAM,EAAE,IAAI;IACZ,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,IAAI;CACZ,CAAC;AA6BK,MAAM,YAAY,GAAG,CAAsD,MAAS,EAAK,EAAE,CAAC,MAAM,CAAC;AAA7F,QAAA,YAAY,gBAAiF"}
1
+ {"version":3,"file":"config-type.js","sourceRoot":"","sources":["../src/config-type.ts"],"names":[],"mappings":";;;AAMa,QAAA,YAAY,GAAG;IAC1B,MAAM,EAAE,IAAI;IACZ,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,IAAI;CACZ,CAAC;AAmCK,MAAM,YAAY,GAAG,CAAsD,MAAS,EAAK,EAAE,CAAC,MAAM,CAAC;AAA7F,QAAA,YAAY,gBAAiF"}
@@ -1,8 +1,9 @@
1
1
  import { Request, Response } from 'express';
2
2
  import { Logger } from 'winston';
3
3
  import { z } from 'zod';
4
+ import { ApiResponse } from './api-response';
4
5
  import { CommonConfig } from './config-type';
5
- import { ApiResponse, IOSchema, Merge, OutputMarker, ReplaceMarkerInShape } from './helpers';
6
+ import { IOSchema, Merge, OutputMarker, ReplaceMarkerInShape } from './helpers';
6
7
  import { Method, MethodsDefinition } from './method';
7
8
  import { MiddlewareDefinition } from './middleware';
8
9
  import { ResultHandlerDefinition } from './result-handler';
@@ -12,19 +13,19 @@ export declare type Handler<IN, OUT, OPT> = (params: {
12
13
  logger: Logger;
13
14
  }) => Promise<OUT>;
14
15
  export declare abstract class AbstractEndpoint {
15
- protected description?: string;
16
16
  abstract execute(params: {
17
17
  request: Request;
18
18
  response: Response;
19
19
  logger: Logger;
20
20
  config: CommonConfig;
21
21
  }): Promise<void>;
22
- getDescription(): string | undefined;
22
+ abstract getDescription(): string | undefined;
23
23
  abstract getMethods(): Method[];
24
24
  abstract getInputSchema(): IOSchema;
25
25
  abstract getOutputSchema(): IOSchema;
26
26
  abstract getPositiveResponseSchema(): z.ZodTypeAny;
27
27
  abstract getNegativeResponseSchema(): z.ZodTypeAny;
28
+ abstract getInputMimeTypes(): string[];
28
29
  abstract getPositiveMimeTypes(): string[];
29
30
  abstract getNegativeMimeTypes(): string[];
30
31
  }
@@ -34,6 +35,7 @@ export declare type EndpointResponse<E extends AbstractEndpoint> = z.output<Retu
34
35
  declare type EndpointProps<IN extends IOSchema, OUT extends IOSchema, mIN, OPT, M extends Method, POS extends ApiResponse, NEG extends ApiResponse> = {
35
36
  middlewares: MiddlewareDefinition<any, any, any>[];
36
37
  inputSchema: IN;
38
+ mimeTypes: string[];
37
39
  outputSchema: OUT;
38
40
  handler: Handler<z.output<Merge<IN, mIN>>, z.input<OUT>, OPT>;
39
41
  resultHandler: ResultHandlerDefinition<POS, NEG>;
@@ -42,18 +44,22 @@ declare type EndpointProps<IN extends IOSchema, OUT extends IOSchema, mIN, OPT,
42
44
  /** mIN, OPT - from Middlewares */
43
45
  export declare class Endpoint<IN extends IOSchema, OUT extends IOSchema, mIN, OPT, M extends Method, POS extends ApiResponse, NEG extends ApiResponse> extends AbstractEndpoint {
44
46
  #private;
45
- protected methods: M[];
46
- protected middlewares: MiddlewareDefinition<any, any, any>[];
47
- protected inputSchema: Merge<IN, mIN>;
48
- protected outputSchema: OUT;
49
- protected handler: Handler<z.output<Merge<IN, mIN>>, z.input<OUT>, OPT>;
50
- protected resultHandler: ResultHandlerDefinition<POS, NEG>;
51
- constructor({ middlewares, inputSchema, outputSchema, handler, resultHandler, description, ...rest }: EndpointProps<IN, OUT, mIN, OPT, M, POS, NEG>);
47
+ protected readonly description?: string;
48
+ protected readonly methods: M[];
49
+ protected readonly middlewares: MiddlewareDefinition<any, any, any>[];
50
+ protected readonly inputSchema: Merge<IN, mIN>;
51
+ protected readonly mimeTypes: string[];
52
+ protected readonly outputSchema: OUT;
53
+ protected readonly handler: Handler<z.output<Merge<IN, mIN>>, z.input<OUT>, OPT>;
54
+ protected readonly resultHandler: ResultHandlerDefinition<POS, NEG>;
55
+ constructor({ middlewares, inputSchema, outputSchema, handler, resultHandler, description, mimeTypes, ...rest }: EndpointProps<IN, OUT, mIN, OPT, M, POS, NEG>);
56
+ getDescription(): string | undefined;
52
57
  getMethods(): M[];
53
58
  getInputSchema(): Merge<IN, mIN>;
54
59
  getOutputSchema(): OUT;
55
60
  getPositiveResponseSchema(): POS['schema'];
56
61
  getNegativeResponseSchema(): NEG['schema'];
62
+ getInputMimeTypes(): string[];
57
63
  getPositiveMimeTypes(): string[];
58
64
  getNegativeMimeTypes(): string[];
59
65
  execute({ request, response, logger, config }: {
package/dist/endpoint.js CHANGED
@@ -8,22 +8,23 @@ var _Endpoint_instances, _Endpoint_setupCorsHeaders, _Endpoint_parseOutput, _End
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.Endpoint = exports.AbstractEndpoint = void 0;
10
10
  const zod_1 = require("zod");
11
+ const errors_1 = require("./errors");
11
12
  const helpers_1 = require("./helpers");
13
+ const mime_1 = require("./mime");
14
+ const result_handler_1 = require("./result-handler");
12
15
  class AbstractEndpoint {
13
- getDescription() {
14
- return this.description;
15
- }
16
16
  }
17
17
  exports.AbstractEndpoint = AbstractEndpoint;
18
18
  /** mIN, OPT - from Middlewares */
19
19
  class Endpoint extends AbstractEndpoint {
20
- constructor({ middlewares, inputSchema, outputSchema, handler, resultHandler, description, ...rest }) {
20
+ constructor({ middlewares, inputSchema, outputSchema, handler, resultHandler, description, mimeTypes, ...rest }) {
21
21
  super();
22
22
  _Endpoint_instances.add(this);
23
23
  this.methods = [];
24
24
  this.middlewares = [];
25
25
  this.middlewares = middlewares;
26
- this.inputSchema = helpers_1.combineEndpointAndMiddlewareInputSchemas(inputSchema, middlewares);
26
+ this.inputSchema = (0, helpers_1.combineEndpointAndMiddlewareInputSchemas)(inputSchema, middlewares);
27
+ this.mimeTypes = mimeTypes;
27
28
  this.outputSchema = outputSchema;
28
29
  this.handler = handler;
29
30
  this.resultHandler = resultHandler;
@@ -35,6 +36,9 @@ class Endpoint extends AbstractEndpoint {
35
36
  this.methods = [rest.method];
36
37
  }
37
38
  }
39
+ getDescription() {
40
+ return this.description;
41
+ }
38
42
  getMethods() {
39
43
  return this.methods;
40
44
  }
@@ -50,6 +54,9 @@ class Endpoint extends AbstractEndpoint {
50
54
  getNegativeResponseSchema() {
51
55
  return this.resultHandler.getNegativeResponse().schema;
52
56
  }
57
+ getInputMimeTypes() {
58
+ return this.mimeTypes;
59
+ }
53
60
  getPositiveMimeTypes() {
54
61
  return this.resultHandler.getPositiveResponse(this.outputSchema).mimeTypes;
55
62
  }
@@ -65,7 +72,9 @@ class Endpoint extends AbstractEndpoint {
65
72
  if (request.method === 'OPTIONS') {
66
73
  return response.end();
67
74
  }
68
- const initialInput = helpers_1.getInitialInput(request);
75
+ const contentType = request.header('content-type') || '';
76
+ const isMultipart = contentType.substr(0, mime_1.mimeMultipart.length).toLowerCase() === mime_1.mimeMultipart;
77
+ const initialInput = (0, helpers_1.getInitialInput)(request, 'files' in request && isMultipart);
69
78
  try {
70
79
  const { input, options, isStreamClosed } = await __classPrivateFieldGet(this, _Endpoint_instances, "m", _Endpoint_runMiddlewares).call(this, {
71
80
  input: { ...initialInput },
@@ -77,7 +86,9 @@ class Endpoint extends AbstractEndpoint {
77
86
  output = __classPrivateFieldGet(this, _Endpoint_instances, "m", _Endpoint_parseOutput).call(this, await __classPrivateFieldGet(this, _Endpoint_instances, "m", _Endpoint_parseAndRunHandler).call(this, { input, options, logger }));
78
87
  }
79
88
  catch (e) {
80
- error = e;
89
+ if (e instanceof Error) {
90
+ error = e;
91
+ }
81
92
  }
82
93
  await __classPrivateFieldGet(this, _Endpoint_instances, "m", _Endpoint_handleResult).call(this, {
83
94
  initialInput, output, request,
@@ -113,17 +124,21 @@ _Endpoint_instances = new WeakSet(), _Endpoint_setupCorsHeaders = function _Endp
113
124
  }
114
125
  }, _Endpoint_runMiddlewares = async function _Endpoint_runMiddlewares({ input, request, response, logger }) {
115
126
  const options = {};
127
+ let isStreamClosed = false;
116
128
  for (const def of this.middlewares) {
117
129
  input = { ...input, ...def.input.parse(input) }; // middleware can transform the input types
118
130
  Object.assign(options, await def.middleware({
119
131
  input, options, request,
120
132
  response, logger
121
133
  }));
122
- if (response.writableEnded) {
134
+ isStreamClosed = ('writableEnded' in response && response.writableEnded) ||
135
+ ('finished' in response && response.finished); // Node v10 and below
136
+ if (isStreamClosed) {
137
+ logger.warn(`The middleware ${def.middleware.name} has closed the stream. Accumulated options:`, options);
123
138
  break;
124
139
  }
125
140
  }
126
- return { input, options, isStreamClosed: response.writableEnded };
141
+ return { input, options, isStreamClosed };
127
142
  }, _Endpoint_parseAndRunHandler = async function _Endpoint_parseAndRunHandler({ input, options, logger }) {
128
143
  return await this.handler({
129
144
  input: this.inputSchema.parse(input),
@@ -137,8 +152,12 @@ _Endpoint_instances = new WeakSet(), _Endpoint_setupCorsHeaders = function _Endp
137
152
  });
138
153
  }
139
154
  catch (e) {
140
- logger.error(`Result handler failure: ${e.message}.`);
141
- // throw e;
155
+ if (e instanceof Error) {
156
+ (0, result_handler_1.lastResortHandler)({
157
+ logger, response,
158
+ error: new errors_1.ResultHandlerError(e.message, error)
159
+ });
160
+ }
142
161
  }
143
162
  };
144
163
  //# sourceMappingURL=endpoint.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"endpoint.js","sourceRoot":"","sources":["../src/endpoint.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"endpoint.js","sourceRoot":"","sources":["../src/endpoint.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod';
2
+ import { ApiResponse } from './api-response';
2
3
  import { Endpoint, Handler } from './endpoint';
3
- import { ApiResponse, FlatObject, IOSchema, Merge } from './helpers';
4
+ import { FlatObject, IOSchema, Merge } from './helpers';
4
5
  import { Method, MethodsDefinition } from './method';
5
6
  import { MiddlewareDefinition } from './middleware';
6
7
  import { ResultHandlerDefinition } from './result-handler';
@@ -9,6 +10,7 @@ declare type BuildProps<IN extends IOSchema, OUT extends IOSchema, mIN, mOUT, M
9
10
  output: OUT;
10
11
  handler: Handler<z.output<Merge<IN, mIN>>, z.input<OUT>, mOUT>;
11
12
  description?: string;
13
+ type?: 'json' | 'upload';
12
14
  } & MethodsDefinition<M>;
13
15
  /** mIN, mOUT - accumulated from all middlewares */
14
16
  export declare class EndpointsFactory<mIN, mOUT, POS extends ApiResponse, NEG extends ApiResponse> {
@@ -17,7 +19,7 @@ export declare class EndpointsFactory<mIN, mOUT, POS extends ApiResponse, NEG ex
17
19
  protected middlewares: MiddlewareDefinition<any, any, any>[];
18
20
  constructor(resultHandler: ResultHandlerDefinition<POS, NEG>);
19
21
  addMiddleware<IN extends IOSchema, OUT extends FlatObject>(definition: MiddlewareDefinition<IN, mOUT, OUT>): EndpointsFactory<Merge<IN, mIN>, mOUT & OUT, POS, NEG>;
20
- build<IN extends IOSchema, OUT extends IOSchema, M extends Method>({ input, output, handler, description, ...rest }: BuildProps<IN, OUT, mIN, mOUT, M>): Endpoint<IN, OUT, mIN, mOUT, M, POS, NEG>;
22
+ build<IN extends IOSchema, OUT extends IOSchema, M extends Method>({ input, output, handler, description, type, ...rest }: BuildProps<IN, OUT, mIN, mOUT, M>): Endpoint<IN, OUT, mIN, mOUT, M, POS, NEG>;
21
23
  }
22
24
  export declare const defaultEndpointsFactory: EndpointsFactory<unknown, unknown, ApiResponse<z.ZodObject<{
23
25
  status: z.ZodLiteral<"success">;
@@ -26,12 +28,14 @@ export declare const defaultEndpointsFactory: EndpointsFactory<unknown, unknown,
26
28
  data: {
27
29
  [x: string]: any;
28
30
  [x: number]: any;
31
+ [x: symbol]: any;
29
32
  };
30
33
  status: "success";
31
34
  }, {
32
35
  data: {
33
36
  [x: string]: any;
34
37
  [x: number]: any;
38
+ [x: symbol]: any;
35
39
  };
36
40
  status: "success";
37
41
  }>>, ApiResponse<z.ZodObject<{
@@ -8,6 +8,7 @@ var _a, _EndpointsFactory_create;
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.defaultEndpointsFactory = exports.EndpointsFactory = void 0;
10
10
  const endpoint_1 = require("./endpoint");
11
+ const mime_1 = require("./mime");
11
12
  const result_handler_1 = require("./result-handler");
12
13
  /** mIN, mOUT - accumulated from all middlewares */
13
14
  class EndpointsFactory {
@@ -19,13 +20,14 @@ class EndpointsFactory {
19
20
  addMiddleware(definition) {
20
21
  return __classPrivateFieldGet(EndpointsFactory, _a, "m", _EndpointsFactory_create).call(EndpointsFactory, this.middlewares.concat(definition), this.resultHandler);
21
22
  }
22
- build({ input, output, handler, description, ...rest }) {
23
+ build({ input, output, handler, description, type, ...rest }) {
23
24
  return new endpoint_1.Endpoint({
24
25
  handler, description,
25
26
  middlewares: this.middlewares,
26
27
  inputSchema: input,
27
28
  outputSchema: output,
28
29
  resultHandler: this.resultHandler,
30
+ mimeTypes: type === 'upload' ? [mime_1.mimeMultipart] : [mime_1.mimeJson],
29
31
  ...rest
30
32
  });
31
33
  }
@@ -1 +1 @@
1
- {"version":3,"file":"endpoints-factory.js","sourceRoot":"","sources":["../src/endpoints-factory.ts"],"names":[],"mappings":";;;;;;;;;AACA,yCAA6C;AAI7C,qDAA+E;AAS/E,mDAAmD;AACnD,MAAa,gBAAgB;IAG3B,YAAsB,aAAgD;QAAhD,kBAAa,GAAb,aAAa,CAAmC;QAF5D,gBAAW,GAA0C,EAAE,CAAC;QAGhE,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IACrC,CAAC;IAWM,aAAa,CAClB,UAA+C;QAE/C,OAAO,uBAAA,gBAAgB,oCAAQ,MAAxB,gBAAgB,EACrB,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,EACnC,IAAI,CAAC,aAAa,CACnB,CAAC;IACJ,CAAC;IAEM,KAAK,CAA8D,EACxE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,IAAI,EACV;QAClC,OAAO,IAAI,mBAAQ,CAAkC;YACnD,OAAO,EAAE,WAAW;YACpB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,KAAK;YAClB,YAAY,EAAE,MAAM;YACpB,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,GAAG,IAAI;SACR,CAAC,CAAC;IACL,CAAC;CACF;AArCD,4CAqCC;oFA7BG,WAAkD,EAClD,aAAkD;IAElD,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAA0B,aAAa,CAAC,CAAC;IAC7E,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC;IAClC,OAAO,OAAO,CAAC;AACjB,CAAC;AAyBU,QAAA,uBAAuB,GAAG,IAAI,gBAAgB,CAAC,qCAAoB,CAAC,CAAC"}
1
+ {"version":3,"file":"endpoints-factory.js","sourceRoot":"","sources":["../src/endpoints-factory.ts"],"names":[],"mappings":";;;;;;;;;AAEA,yCAA6C;AAI7C,iCAA+C;AAC/C,qDAA+E;AAU/E,mDAAmD;AACnD,MAAa,gBAAgB;IAG3B,YAAsB,aAAgD;QAAhD,kBAAa,GAAb,aAAa,CAAmC;QAF5D,gBAAW,GAA0C,EAAE,CAAC;QAGhE,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IACrC,CAAC;IAWM,aAAa,CAClB,UAA+C;QAE/C,OAAO,uBAAA,gBAAgB,oCAAQ,MAAxB,gBAAgB,EACrB,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,EACnC,IAAI,CAAC,aAAa,CACnB,CAAC;IACJ,CAAC;IAEM,KAAK,CAA8D,EACxE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,IAAI,EAChB;QAClC,OAAO,IAAI,mBAAQ,CAAkC;YACnD,OAAO,EAAE,WAAW;YACpB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,KAAK;YAClB,YAAY,EAAE,MAAM;YACpB,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,SAAS,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,oBAAa,CAAC,CAAC,CAAC,CAAC,CAAC,eAAQ,CAAC;YAC3D,GAAG,IAAI;SACR,CAAC,CAAC;IACL,CAAC;CACF;AAtCD,4CAsCC;oFA9BG,WAAkD,EAClD,aAAkD;IAElD,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAA0B,aAAa,CAAC,CAAC;IAC7E,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC;IAClC,OAAO,OAAO,CAAC;AACjB,CAAC;AA0BU,QAAA,uBAAuB,GAAG,IAAI,gBAAgB,CAAC,qCAAoB,CAAC,CAAC"}
package/dist/errors.d.ts CHANGED
@@ -4,3 +4,9 @@ export declare class DependsOnMethodError extends RoutingError {
4
4
  }
5
5
  export declare class OpenAPIError extends Error {
6
6
  }
7
+ export declare class ResultHandlerError extends Error {
8
+ protected readonly originalError?: Error;
9
+ constructor(message: string, originalError?: Error | null);
10
+ hasOriginalError(): boolean;
11
+ getOriginalErrorMessage(): string | undefined;
12
+ }
package/dist/errors.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OpenAPIError = exports.DependsOnMethodError = exports.RoutingError = void 0;
3
+ exports.ResultHandlerError = exports.OpenAPIError = exports.DependsOnMethodError = exports.RoutingError = void 0;
4
4
  class RoutingError extends Error {
5
5
  }
6
6
  exports.RoutingError = RoutingError;
@@ -10,4 +10,17 @@ exports.DependsOnMethodError = DependsOnMethodError;
10
10
  class OpenAPIError extends Error {
11
11
  }
12
12
  exports.OpenAPIError = OpenAPIError;
13
+ class ResultHandlerError extends Error {
14
+ constructor(message, originalError) {
15
+ super(message);
16
+ this.originalError = originalError || undefined;
17
+ }
18
+ hasOriginalError() {
19
+ return this.originalError !== undefined;
20
+ }
21
+ getOriginalErrorMessage() {
22
+ return this.originalError ? this.originalError.message : undefined;
23
+ }
24
+ }
25
+ exports.ResultHandlerError = ResultHandlerError;
13
26
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";;;AAAA,MAAa,YAAa,SAAQ,KAAK;CACtC;AADD,oCACC;AAED,MAAa,oBAAqB,SAAQ,YAAY;CACrD;AADD,oDACC;AAED,MAAa,YAAa,SAAQ,KAAK;CACtC;AADD,oCACC"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";;;AAAA,MAAa,YAAa,SAAQ,KAAK;CACtC;AADD,oCACC;AAED,MAAa,oBAAqB,SAAQ,YAAY;CACrD;AADD,oDACC;AAED,MAAa,YAAa,SAAQ,KAAK;CACtC;AADD,oCACC;AAED,MAAa,kBAAmB,SAAQ,KAAK;IAG3C,YAAY,OAAe,EAAE,aAA4B;QACvD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,aAAa,GAAG,aAAa,IAAI,SAAS,CAAC;IAClD,CAAC;IAEM,gBAAgB;QACrB,OAAO,IAAI,CAAC,aAAa,KAAK,SAAS,CAAC;IAC1C,CAAC;IAEM,uBAAuB;QAC5B,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;IACrE,CAAC;CACF;AAfD,gDAeC"}
@@ -1,3 +1,5 @@
1
1
  import { ZodFile } from './file-schema';
2
+ import { ZodUpload } from './upload-schema';
2
3
  export * from 'zod';
3
4
  export declare const file: () => ZodFile;
5
+ export declare const upload: () => ZodUpload;
@@ -10,8 +10,10 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
10
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
11
  };
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.file = void 0;
13
+ exports.upload = exports.file = void 0;
14
14
  const file_schema_1 = require("./file-schema");
15
+ const upload_schema_1 = require("./upload-schema");
15
16
  __exportStar(require("zod"), exports);
16
17
  exports.file = file_schema_1.ZodFile.create;
18
+ exports.upload = upload_schema_1.ZodUpload.create;
17
19
  //# sourceMappingURL=extend-zod.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"extend-zod.js","sourceRoot":"","sources":["../src/extend-zod.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,+CAAsC;AAEtC,sCAAoB;AACP,QAAA,IAAI,GAAG,qBAAO,CAAC,MAAM,CAAC"}
1
+ {"version":3,"file":"extend-zod.js","sourceRoot":"","sources":["../src/extend-zod.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,+CAAsC;AACtC,mDAA0C;AAE1C,sCAAoB;AACP,QAAA,IAAI,GAAG,qBAAO,CAAC,MAAM,CAAC;AACtB,QAAA,MAAM,GAAG,yBAAS,CAAC,MAAM,CAAC"}