@lucaapp/service-utils 1.30.1 → 1.32.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.
@@ -3,6 +3,7 @@ import 'express-async-errors';
3
3
  import { OpenAPIRegistry } from '@asteasolutions/zod-to-openapi';
4
4
  import { EndpointHandler, EndpointOptions } from './types/endpoint';
5
5
  import { Middleware, EndpointResponseSchema } from './types/middleware';
6
+ import { ZodObjectSchemaOrUndefined } from './types/utils';
6
7
  type OpenApiVersion = '3.0.0' | '3.0.1' | '3.0.2' | '3.0.3' | '3.1.0';
7
8
  type ApiConstructorOptions = {
8
9
  prefixPath?: string;
@@ -11,6 +12,13 @@ type ApiConstructorOptions = {
11
12
  apiTitle?: string;
12
13
  apiDescription?: string;
13
14
  debug?: boolean;
15
+ tags?: string[];
16
+ registry?: OpenAPIRegistry;
17
+ router?: Router;
18
+ };
19
+ type ApiChildOptions = {
20
+ prefixPath?: string;
21
+ tags?: string[];
14
22
  };
15
23
  export declare class Api {
16
24
  router: Router;
@@ -21,12 +29,14 @@ export declare class Api {
21
29
  apiDescription: string;
22
30
  private prefixPath;
23
31
  debug: boolean;
32
+ tags: string[];
24
33
  constructor(options?: ApiConstructorOptions);
25
- get<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBody = undefined, TRequestParams = undefined, TRequestQuery = undefined, TRequestHeaders = undefined, TMiddlewares extends ReadonlyArray<Middleware<any, any, any, any, any, any>> | undefined = undefined>(path: string, summary: string, options: EndpointOptions<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TMiddlewares>, handler: EndpointHandler<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TMiddlewares>): void;
26
- post<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBody = undefined, TRequestParams = undefined, TRequestQuery = undefined, TRequestHeaders = undefined, TMiddlewares extends ReadonlyArray<Middleware<any, any, any, any, any, any>> | undefined = undefined>(path: string, summary: string, options: EndpointOptions<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TMiddlewares>, handler: EndpointHandler<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TMiddlewares>): void;
27
- patch<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBody = undefined, TRequestParams = undefined, TRequestQuery = undefined, TRequestHeaders = undefined, TMiddlewares extends ReadonlyArray<Middleware<any, any, any, any, any, any>> | undefined = undefined>(path: string, summary: string, options: EndpointOptions<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TMiddlewares>, handler: EndpointHandler<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TMiddlewares>): void;
28
- put<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBody = undefined, TRequestParams = undefined, TRequestQuery = undefined, TRequestHeaders = undefined, TMiddlewares extends ReadonlyArray<Middleware<any, any, any, any, any, any>> | undefined = undefined>(path: string, summary: string, options: EndpointOptions<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TMiddlewares>, handler: EndpointHandler<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TMiddlewares>): void;
29
- delete<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBody = undefined, TRequestParams = undefined, TRequestQuery = undefined, TRequestHeaders = undefined, TMiddlewares extends ReadonlyArray<Middleware<any, any, any, any, any, any>> | undefined = undefined>(path: string, summary: string, options: EndpointOptions<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TMiddlewares>, handler: EndpointHandler<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TMiddlewares>): void;
34
+ child(options: ApiChildOptions): Api;
35
+ get<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBodySchema extends ZodObjectSchemaOrUndefined = undefined, TRequestParamsSchema extends ZodObjectSchemaOrUndefined = undefined, TRequestQuerySchema extends ZodObjectSchemaOrUndefined = undefined, TRequestHeadersSchema extends ZodObjectSchemaOrUndefined = undefined, TMiddlewares extends ReadonlyArray<Middleware<any, any, any, any, any, any>> | undefined = undefined>(path: string, summary: string, options: EndpointOptions<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TMiddlewares>, handler: EndpointHandler<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TMiddlewares>): void;
36
+ post<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBodySchema extends ZodObjectSchemaOrUndefined = undefined, TRequestParamsSchema extends ZodObjectSchemaOrUndefined = undefined, TRequestQuerySchema extends ZodObjectSchemaOrUndefined = undefined, TRequestHeadersSchema extends ZodObjectSchemaOrUndefined = undefined, TMiddlewares extends ReadonlyArray<Middleware<any, any, any, any, any, any>> | undefined = undefined>(path: string, summary: string, options: EndpointOptions<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TMiddlewares>, handler: EndpointHandler<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TMiddlewares>): void;
37
+ patch<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBodySchema extends ZodObjectSchemaOrUndefined = undefined, TRequestParamsSchema extends ZodObjectSchemaOrUndefined = undefined, TRequestQuerySchema extends ZodObjectSchemaOrUndefined = undefined, TRequestHeadersSchema extends ZodObjectSchemaOrUndefined = undefined, TMiddlewares extends ReadonlyArray<Middleware<any, any, any, any, any, any>> | undefined = undefined>(path: string, summary: string, options: EndpointOptions<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TMiddlewares>, handler: EndpointHandler<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TMiddlewares>): void;
38
+ put<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBodySchema extends ZodObjectSchemaOrUndefined = undefined, TRequestParamsSchema extends ZodObjectSchemaOrUndefined = undefined, TRequestQuerySchema extends ZodObjectSchemaOrUndefined = undefined, TRequestHeadersSchema extends ZodObjectSchemaOrUndefined = undefined, TMiddlewares extends ReadonlyArray<Middleware<any, any, any, any, any, any>> | undefined = undefined>(path: string, summary: string, options: EndpointOptions<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TMiddlewares>, handler: EndpointHandler<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TMiddlewares>): void;
39
+ delete<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBodySchema extends ZodObjectSchemaOrUndefined = undefined, TRequestParamsSchema extends ZodObjectSchemaOrUndefined = undefined, TRequestQuerySchema extends ZodObjectSchemaOrUndefined = undefined, TRequestHeadersSchema extends ZodObjectSchemaOrUndefined = undefined, TMiddlewares extends ReadonlyArray<Middleware<any, any, any, any, any, any>> | undefined = undefined>(path: string, summary: string, options: EndpointOptions<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TMiddlewares>, handler: EndpointHandler<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TMiddlewares>): void;
30
40
  generateOpenAPISpec(): import("openapi3-ts").OpenAPIObject;
31
41
  mountSwaggerMiddlewares(): void;
32
42
  }
@@ -11,35 +11,44 @@ const zod_to_openapi_1 = require("@asteasolutions/zod-to-openapi");
11
11
  const endpoint_1 = require("./endpoint");
12
12
  class Api {
13
13
  constructor(options = {}) {
14
- this.router = (0, express_1.Router)();
15
- this.registry = new zod_to_openapi_1.OpenAPIRegistry();
14
+ this.router = options.router || (0, express_1.Router)();
15
+ this.registry = options.registry || new zod_to_openapi_1.OpenAPIRegistry();
16
16
  this.prefixPath = options.prefixPath || '';
17
17
  this.openApiVersion = options.openApiVersion || '3.0.0';
18
18
  this.apiVersion = options.apiVersion || '1.0.0';
19
19
  this.apiTitle = options.apiTitle || 'API';
20
20
  this.apiDescription = options.apiDescription || '';
21
21
  this.debug = options.debug || false;
22
- this.mountSwaggerMiddlewares();
22
+ this.tags = options.tags || [];
23
+ }
24
+ child(options) {
25
+ return new Api({
26
+ prefixPath: this.prefixPath + (options.prefixPath || ''),
27
+ debug: this.debug,
28
+ tags: [...this.tags, ...(options.tags || [])],
29
+ registry: this.registry,
30
+ router: this.router,
31
+ });
23
32
  }
24
33
  get(path, summary, options, handler) {
25
34
  (0, endpoint_1.mountEndpoint)(this.router, 'get', path, options, handler, this.debug);
26
- (0, endpoint_1.registerEndpoint)(this.registry, 'get', this.prefixPath, path, summary, options);
35
+ (0, endpoint_1.registerEndpoint)(this.registry, 'get', this.prefixPath, path, summary, options, this.tags, this.debug);
27
36
  }
28
37
  post(path, summary, options, handler) {
29
38
  (0, endpoint_1.mountEndpoint)(this.router, 'post', path, options, handler, this.debug);
30
- (0, endpoint_1.registerEndpoint)(this.registry, 'post', this.prefixPath, path, summary, options);
39
+ (0, endpoint_1.registerEndpoint)(this.registry, 'post', this.prefixPath, path, summary, options, this.tags, this.debug);
31
40
  }
32
41
  patch(path, summary, options, handler) {
33
42
  (0, endpoint_1.mountEndpoint)(this.router, 'patch', path, options, handler, this.debug);
34
- (0, endpoint_1.registerEndpoint)(this.registry, 'patch', this.prefixPath, path, summary, options);
43
+ (0, endpoint_1.registerEndpoint)(this.registry, 'patch', this.prefixPath, path, summary, options, this.tags, this.debug);
35
44
  }
36
45
  put(path, summary, options, handler) {
37
46
  (0, endpoint_1.mountEndpoint)(this.router, 'put', path, options, handler, this.debug);
38
- (0, endpoint_1.registerEndpoint)(this.registry, 'put', this.prefixPath, path, summary, options);
47
+ (0, endpoint_1.registerEndpoint)(this.registry, 'put', this.prefixPath, path, summary, options, this.tags, this.debug);
39
48
  }
40
49
  delete(path, summary, options, handler) {
41
50
  (0, endpoint_1.mountEndpoint)(this.router, 'delete', path, options, handler, this.debug);
42
- (0, endpoint_1.registerEndpoint)(this.registry, 'delete', this.prefixPath, path, summary, options);
51
+ (0, endpoint_1.registerEndpoint)(this.registry, 'delete', this.prefixPath, path, summary, options, this.tags, this.debug);
43
52
  }
44
53
  generateOpenAPISpec() {
45
54
  const generator = new zod_to_openapi_1.OpenAPIGenerator(this.registry.definitions, this.openApiVersion);
@@ -2,7 +2,8 @@ import { Router } from 'express';
2
2
  import { OpenAPIRegistry } from '@asteasolutions/zod-to-openapi';
3
3
  import { Middleware, EndpointResponseSchema } from './types/middleware';
4
4
  import { EndpointOptions, EndpointHandler } from './types/endpoint';
5
+ import { ZodObjectSchemaOrUndefined } from './types/utils';
5
6
  type HttpMethod = 'get' | 'post' | 'put' | 'delete' | 'patch';
6
- export declare const mountEndpoint: <TResponseSchemas extends readonly EndpointResponseSchema[], TRequestBody = undefined, TRequestParams = undefined, TRequestQuery = undefined, TRequestHeaders = undefined, TMiddlewares extends readonly Middleware<any, any, any, any, any, any>[] | undefined = undefined>(router: Router, method: HttpMethod, path: string, options: EndpointOptions<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TMiddlewares>, handler: EndpointHandler<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TMiddlewares>, debug: boolean) => void;
7
- export declare const registerEndpoint: (registry: OpenAPIRegistry, method: HttpMethod, prefixPath: string, path: string, summary: string, options: EndpointOptions<any, any, any, any, any, any>) => void;
7
+ export declare const mountEndpoint: <TResponseSchemas extends readonly EndpointResponseSchema[], TRequestBodySchema extends ZodObjectSchemaOrUndefined, TRequestParamsSchema extends ZodObjectSchemaOrUndefined, TRequestQuerySchema extends ZodObjectSchemaOrUndefined, TRequestHeadersSchema extends ZodObjectSchemaOrUndefined, TMiddlewares extends readonly Middleware<any, any, any, any, any, any>[] | undefined = undefined>(router: Router, method: HttpMethod, path: string, options: EndpointOptions<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TMiddlewares>, handler: EndpointHandler<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TMiddlewares>, debug: boolean) => void;
8
+ export declare const registerEndpoint: (registry: OpenAPIRegistry, method: HttpMethod, prefixPath: string, path: string, summary: string, options: EndpointOptions<any, any, any, any, any, any>, tags: string[], debug: boolean) => void;
8
9
  export {};
@@ -6,7 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.registerEndpoint = exports.mountEndpoint = void 0;
7
7
  const zod_1 = require("zod");
8
8
  const assert_1 = __importDefault(require("assert"));
9
- const boom_1 = require("@hapi/boom");
9
+ const http_1 = require("./types/http");
10
+ const mapExpressParamsToOpenAPIParams = (path) => path.replaceAll(/\:([^\:\/]+)/g, '{$1}');
10
11
  const buildResponseConfig = (responseOptions) => {
11
12
  const responses = {};
12
13
  responseOptions.forEach(response => {
@@ -66,6 +67,27 @@ const validateAndSendResponse = async (expressResponse, response, validResponses
66
67
  }
67
68
  expressResponse.status(response.status).send(validatedResponseBody);
68
69
  };
70
+ const sendBadResponseError = (response, error) => {
71
+ return response.status(500).send({
72
+ error: http_1.HTTPStatus.INTERNAL_SERVER_ERROR,
73
+ message: 'Invalid Response',
74
+ issues: error.issues,
75
+ });
76
+ };
77
+ const sendKnownErrorResponse = (response, statusCode, error, debug) => {
78
+ response.status(statusCode).send({
79
+ error: error.type,
80
+ message: error.message,
81
+ ...(debug && { stack: error.stack }),
82
+ });
83
+ };
84
+ const sendBadRequestError = (response, error) => {
85
+ return response.status(400).send({
86
+ error: http_1.HTTPStatus.BAD_REQUEST,
87
+ message: error.message,
88
+ issues: error.issues,
89
+ });
90
+ };
69
91
  const handleMiddleware = async (middleware, context, request, response, debug) => new Promise(async (resolve, reject) => {
70
92
  try {
71
93
  const handlerRequestBody = ((await middleware.options.schemas?.body?.parseAsync(request.body)) ||
@@ -91,10 +113,9 @@ const handleMiddleware = async (middleware, context, request, response, debug) =
91
113
  resolve(false);
92
114
  }
93
115
  catch (error) {
94
- if (error instanceof Error) {
95
- (0, boom_1.boomify)(error, {
96
- statusCode: 500,
97
- });
116
+ if (error instanceof zod_1.ZodError) {
117
+ sendBadResponseError(response, error);
118
+ return resolve(false);
98
119
  }
99
120
  reject(error);
100
121
  }
@@ -105,27 +126,27 @@ const handleMiddleware = async (middleware, context, request, response, debug) =
105
126
  resolve(true);
106
127
  }
107
128
  catch (error) {
108
- if (error instanceof Error) {
109
- (0, boom_1.boomify)(error, {
110
- statusCode: 500,
111
- });
129
+ if (error instanceof zod_1.ZodError) {
130
+ sendBadResponseError(response, error);
131
+ return resolve(false);
112
132
  }
113
133
  reject(error);
114
134
  }
115
135
  });
116
136
  }
117
137
  catch (error) {
138
+ if (error instanceof zod_1.ZodError) {
139
+ sendBadRequestError(response, error);
140
+ return resolve(false);
141
+ }
118
142
  if (isTypedError(error) &&
119
143
  middleware.options.errors &&
120
144
  middleware.options.errors[error.type]) {
121
145
  const statusCode = middleware.options.errors[error.type];
122
- return response.status(statusCode).send({
123
- statusCode,
124
- error: error.type,
125
- message: error.message,
126
- ...(debug && { stack: error.stack }),
127
- });
146
+ sendKnownErrorResponse(response, statusCode, error, debug);
147
+ return resolve(false);
128
148
  }
149
+ // bubble up unknown errors
129
150
  reject(error);
130
151
  }
131
152
  });
@@ -159,38 +180,41 @@ const mountEndpoint = (router, method, path, options, handler, debug) => {
159
180
  await validateAndSendResponse(response, controllerResponse, options.responses);
160
181
  }
161
182
  catch (error) {
162
- if (error instanceof Error) {
163
- (0, boom_1.boomify)(error, {
164
- statusCode: 500,
165
- });
183
+ if (error instanceof zod_1.ZodError) {
184
+ return sendBadResponseError(response, error);
166
185
  }
167
186
  next(error);
168
187
  }
169
188
  });
170
189
  }
171
190
  catch (error) {
172
- if (error instanceof zod_1.z.ZodError && !(0, boom_1.isBoom)(error)) {
173
- return response.status(400).send({ issues: error.issues });
191
+ if (error instanceof zod_1.ZodError) {
192
+ return sendBadRequestError(response, error);
174
193
  }
175
194
  if (isTypedError(error) &&
176
195
  options.errors &&
177
196
  options.errors[error.type]) {
178
197
  const statusCode = options.errors[error.type];
179
- return response.status(statusCode).send({
180
- statusCode,
181
- error: error.type,
198
+ return sendKnownErrorResponse(response, statusCode, error, debug);
199
+ }
200
+ if (error instanceof Error) {
201
+ return response.status(500).send({
202
+ error: http_1.HTTPStatus.INTERNAL_SERVER_ERROR,
182
203
  message: error.message,
183
204
  ...(debug && { stack: error.stack }),
184
205
  });
185
206
  }
186
- next(error);
207
+ return response.status(500).send({
208
+ error: http_1.HTTPStatus.INTERNAL_SERVER_ERROR,
209
+ message: 'Unknown Error',
210
+ });
187
211
  }
188
212
  });
189
213
  };
190
214
  exports.mountEndpoint = mountEndpoint;
191
215
  const registerEndpoint = (registry, method, prefixPath, path, summary,
192
216
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
193
- options) => {
217
+ options, tags, debug) => {
194
218
  let bodySchema = options.schemas?.body || undefined;
195
219
  let paramsSchema = options.schemas?.params || undefined;
196
220
  let querySchema = options.schemas?.query || undefined;
@@ -199,17 +223,14 @@ options) => {
199
223
  if (options.errors) {
200
224
  for (const errorType of Object.keys(options.errors)) {
201
225
  const statusCode = options.errors[errorType];
202
- responseSchemas = responseSchemas.concat([
203
- {
204
- status: statusCode,
205
- description: errorType,
206
- schema: zod_1.z.object({
207
- statusCode: zod_1.z.literal(statusCode),
208
- error: zod_1.z.literal(errorType),
209
- message: zod_1.z.string(),
210
- }),
211
- },
212
- ]);
226
+ responseSchemas.push({
227
+ status: statusCode,
228
+ description: errorType,
229
+ schema: zod_1.z.object({
230
+ error: zod_1.z.literal(errorType),
231
+ message: zod_1.z.string(),
232
+ }),
233
+ });
213
234
  }
214
235
  }
215
236
  for (const middleware of options.middlewares || []) {
@@ -239,25 +260,47 @@ options) => {
239
260
  if (middleware.options.errors) {
240
261
  for (const errorType of Object.keys(middleware.options.errors)) {
241
262
  const statusCode = middleware.options.errors[errorType];
242
- responseSchemas = responseSchemas.concat([
243
- {
244
- status: statusCode,
245
- description: errorType,
246
- schema: zod_1.z.object({
247
- statusCode: zod_1.z.literal(statusCode),
248
- error: zod_1.z.literal(errorType),
249
- message: zod_1.z.string(),
250
- }),
251
- },
252
- ]);
263
+ responseSchemas.push({
264
+ status: statusCode,
265
+ description: errorType,
266
+ schema: zod_1.z.object({
267
+ error: zod_1.z.literal(errorType),
268
+ message: zod_1.z.string(),
269
+ }),
270
+ });
253
271
  }
254
272
  }
255
273
  }
274
+ // Add ZodError response
275
+ responseSchemas.push({
276
+ status: 400,
277
+ description: 'Bad Request',
278
+ schema: zod_1.z.object({
279
+ error: zod_1.z.literal(http_1.HTTPStatus.BAD_REQUEST),
280
+ message: zod_1.z.string(),
281
+ issues: zod_1.z.array(zod_1.z
282
+ .object({
283
+ message: zod_1.z.string(),
284
+ })
285
+ .openapi({ additionalProperties: true })),
286
+ }),
287
+ });
288
+ // Add UnknownError response
289
+ responseSchemas.push({
290
+ status: 500,
291
+ description: 'Internal Server Error',
292
+ schema: zod_1.z.object({
293
+ error: zod_1.z.literal(http_1.HTTPStatus.INTERNAL_SERVER_ERROR),
294
+ message: zod_1.z.string(),
295
+ ...(debug && { stack: zod_1.z.string().optional() }),
296
+ }),
297
+ });
256
298
  const responseMap = buildResponseConfig(responseSchemas);
257
299
  registry.registerPath({
258
300
  method,
259
- path: (prefixPath + path).replaceAll(/\:([^\:\/]+)/g, '{$1}'),
301
+ path: mapExpressParamsToOpenAPIParams(prefixPath + path),
260
302
  summary,
303
+ tags,
261
304
  // description: summary,
262
305
  request: {
263
306
  ...(bodySchema && {
@@ -1,56 +1,45 @@
1
1
  import { z } from 'zod';
2
+ import { HTTPStatus } from './types/http';
2
3
  declare const noContentSchema: z.ZodVoid;
3
4
  declare const badRequestErrorSchema: z.ZodObject<{
4
- statusCode: z.ZodLiteral<400>;
5
- error: z.ZodString;
5
+ error: z.ZodLiteral<HTTPStatus.BAD_REQUEST>;
6
6
  message: z.ZodString;
7
7
  }, "strip", z.ZodTypeAny, {
8
8
  message: string;
9
- error: string;
10
- statusCode: 400;
9
+ error: HTTPStatus.BAD_REQUEST;
11
10
  }, {
12
11
  message: string;
13
- error: string;
14
- statusCode: 400;
12
+ error: HTTPStatus.BAD_REQUEST;
15
13
  }>;
16
14
  declare const unauthorizedErrorSchema: z.ZodObject<{
17
- statusCode: z.ZodLiteral<401>;
18
- error: z.ZodString;
15
+ error: z.ZodLiteral<HTTPStatus.UNAUTHORIZED>;
19
16
  message: z.ZodString;
20
17
  }, "strip", z.ZodTypeAny, {
21
18
  message: string;
22
- error: string;
23
- statusCode: 401;
19
+ error: HTTPStatus.UNAUTHORIZED;
24
20
  }, {
25
21
  message: string;
26
- error: string;
27
- statusCode: 401;
22
+ error: HTTPStatus.UNAUTHORIZED;
28
23
  }>;
29
24
  declare const forbiddenErrorSchema: z.ZodObject<{
30
- statusCode: z.ZodLiteral<403>;
31
- error: z.ZodString;
25
+ error: z.ZodLiteral<HTTPStatus.FORBIDDEN>;
32
26
  message: z.ZodString;
33
27
  }, "strip", z.ZodTypeAny, {
34
28
  message: string;
35
- error: string;
36
- statusCode: 403;
29
+ error: HTTPStatus.FORBIDDEN;
37
30
  }, {
38
31
  message: string;
39
- error: string;
40
- statusCode: 403;
32
+ error: HTTPStatus.FORBIDDEN;
41
33
  }>;
42
34
  declare const notFoundErrorSchema: z.ZodObject<{
43
- statusCode: z.ZodLiteral<404>;
44
- error: z.ZodString;
35
+ error: z.ZodLiteral<HTTPStatus.NOT_FOUND>;
45
36
  message: z.ZodString;
46
37
  }, "strip", z.ZodTypeAny, {
47
38
  message: string;
48
- error: string;
49
- statusCode: 404;
39
+ error: HTTPStatus.NOT_FOUND;
50
40
  }, {
51
41
  message: string;
52
- error: string;
53
- statusCode: 404;
42
+ error: HTTPStatus.NOT_FOUND;
54
43
  }>;
55
44
  export declare const okResponse: <T>(schema: z.ZodType<T, z.ZodTypeDef, T>) => {
56
45
  status: 200;
@@ -3,27 +3,24 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.notFoundResponse = exports.forbiddenResponse = exports.unauthorizedResponse = exports.badRequestResponse = exports.noContentResponse = exports.okResponse = void 0;
4
4
  const zod_to_openapi_1 = require("@asteasolutions/zod-to-openapi");
5
5
  const zod_1 = require("zod");
6
+ const http_1 = require("./types/http");
6
7
  (0, zod_to_openapi_1.extendZodWithOpenApi)(zod_1.z);
7
8
  // response schemas
8
9
  const noContentSchema = zod_1.z.void();
9
10
  const badRequestErrorSchema = zod_1.z.object({
10
- statusCode: zod_1.z.literal(400),
11
- error: zod_1.z.string(),
11
+ error: zod_1.z.literal(http_1.HTTPStatus.BAD_REQUEST),
12
12
  message: zod_1.z.string(),
13
13
  });
14
14
  const unauthorizedErrorSchema = zod_1.z.object({
15
- statusCode: zod_1.z.literal(401),
16
- error: zod_1.z.string(),
15
+ error: zod_1.z.literal(http_1.HTTPStatus.UNAUTHORIZED),
17
16
  message: zod_1.z.string(),
18
17
  });
19
18
  const forbiddenErrorSchema = zod_1.z.object({
20
- statusCode: zod_1.z.literal(403),
21
- error: zod_1.z.string(),
19
+ error: zod_1.z.literal(http_1.HTTPStatus.FORBIDDEN),
22
20
  message: zod_1.z.string(),
23
21
  });
24
22
  const notFoundErrorSchema = zod_1.z.object({
25
- statusCode: zod_1.z.literal(404),
26
- error: zod_1.z.string(),
23
+ error: zod_1.z.literal(http_1.HTTPStatus.NOT_FOUND),
27
24
  message: zod_1.z.string(),
28
25
  });
29
26
  // response functions
@@ -1,3 +1,4 @@
1
+ import { HTTPStatus } from './types/http';
1
2
  export declare const ok: <T>(body: T) => {
2
3
  status: 200;
3
4
  body: T;
@@ -9,32 +10,28 @@ export declare const noContent: () => {
9
10
  export declare const badRequest: (message?: string) => {
10
11
  status: 400;
11
12
  body: {
12
- statusCode: 400;
13
- error: string;
13
+ error: HTTPStatus.BAD_REQUEST;
14
14
  message: string;
15
15
  };
16
16
  };
17
17
  export declare const unauthorized: (message?: string) => {
18
18
  status: 401;
19
19
  body: {
20
- statusCode: 401;
21
- error: string;
20
+ error: HTTPStatus.UNAUTHORIZED;
22
21
  message: string;
23
22
  };
24
23
  };
25
24
  export declare const forbidden: (message?: string) => {
26
25
  status: 403;
27
26
  body: {
28
- statusCode: 403;
29
- error: string;
27
+ error: HTTPStatus.FORBIDDEN;
30
28
  message: string;
31
29
  };
32
30
  };
33
31
  export declare const notFound: (message?: string) => {
34
32
  status: 404;
35
33
  body: {
36
- statusCode: 404;
37
- error: string;
34
+ error: HTTPStatus.NOT_FOUND;
38
35
  message: string;
39
36
  };
40
37
  };
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.notFound = exports.forbidden = exports.unauthorized = exports.badRequest = exports.noContent = exports.ok = void 0;
4
+ const http_1 = require("./types/http");
4
5
  const ok = (body) => ({
5
6
  status: 200,
6
7
  body,
@@ -14,8 +15,7 @@ exports.noContent = noContent;
14
15
  const badRequest = (message) => ({
15
16
  status: 400,
16
17
  body: {
17
- statusCode: 400,
18
- error: 'Bad request',
18
+ error: http_1.HTTPStatus.BAD_REQUEST,
19
19
  message: message || 'Bad request',
20
20
  },
21
21
  });
@@ -23,8 +23,7 @@ exports.badRequest = badRequest;
23
23
  const unauthorized = (message) => ({
24
24
  status: 401,
25
25
  body: {
26
- statusCode: 401,
27
- error: 'Unauthorized',
26
+ error: http_1.HTTPStatus.UNAUTHORIZED,
28
27
  message: message || 'Unauthorized',
29
28
  },
30
29
  });
@@ -32,8 +31,7 @@ exports.unauthorized = unauthorized;
32
31
  const forbidden = (message) => ({
33
32
  status: 403,
34
33
  body: {
35
- statusCode: 403,
36
- error: 'Forbidden',
34
+ error: http_1.HTTPStatus.FORBIDDEN,
37
35
  message: message || 'Forbidden',
38
36
  },
39
37
  });
@@ -41,8 +39,7 @@ exports.forbidden = forbidden;
41
39
  const notFound = (message) => ({
42
40
  status: 404,
43
41
  body: {
44
- statusCode: 404,
45
- error: 'Not found',
42
+ error: http_1.HTTPStatus.NOT_FOUND,
46
43
  message: message || 'Not found',
47
44
  },
48
45
  });
@@ -1,18 +1,17 @@
1
- import { z } from 'zod';
2
1
  import { Middleware, EndpointResponseSchema } from './middleware';
3
- import { ArrayToUnion, ExtractZodOutput, ExtractZodOutputFromMiddleware, Always, Merge } from './utils';
4
- export type EndpointHandler<TResponse, TRequestBody = undefined, TRequestParams = undefined, TRequestQuery = undefined, TRequestHeaders = undefined, TMiddlewares = undefined> = (request: {
5
- body: TRequestBody;
6
- params: TRequestParams;
7
- query: TRequestQuery;
8
- headers: TRequestHeaders;
2
+ import { ArrayToUnion, ExtractZodOutput, ExtractZodOutputFromMiddleware, Always, Merge, ZodSchemaOuput } from './utils';
3
+ export type EndpointHandler<TResponse, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TMiddlewares> = (request: {
4
+ body: ZodSchemaOuput<TRequestBodySchema>;
5
+ params: ZodSchemaOuput<TRequestParamsSchema>;
6
+ query: ZodSchemaOuput<TRequestQuerySchema>;
7
+ headers: ZodSchemaOuput<TRequestHeadersSchema>;
9
8
  }, context: Merge<Always<ExtractZodOutputFromMiddleware<ArrayToUnion<TMiddlewares>>>>, send: (response: ExtractZodOutput<ArrayToUnion<TResponse>>) => void) => Promise<void>;
10
- export type EndpointOptions<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBody = undefined, TRequestParams = undefined, TRequestQuery = undefined, TRequestHeaders = undefined, TMiddlewares extends ReadonlyArray<Middleware<any, any, any, any, any, any>> | undefined = undefined> = {
9
+ export type EndpointOptions<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TMiddlewares extends ReadonlyArray<Middleware<any, any, any, any, any, any>> | undefined> = {
11
10
  schemas?: {
12
- body?: z.ZodObject<z.ZodRawShape, 'strip', z.ZodTypeAny, TRequestBody>;
13
- params?: z.ZodObject<z.ZodRawShape, 'strip', z.ZodTypeAny, TRequestParams>;
14
- query?: z.ZodObject<z.ZodRawShape, 'strip', z.ZodTypeAny, TRequestQuery>;
15
- headers?: z.ZodObject<z.ZodRawShape, 'strip', z.ZodTypeAny, TRequestHeaders>;
11
+ body?: TRequestBodySchema;
12
+ params?: TRequestParamsSchema;
13
+ query?: TRequestQuerySchema;
14
+ headers?: TRequestHeadersSchema;
16
15
  };
17
16
  middlewares?: TMiddlewares;
18
17
  responses: TResponseSchemas;
@@ -0,0 +1,17 @@
1
+ export declare enum HTTPStatus {
2
+ 'OK' = "OK",
3
+ 'CREATED' = "CREATED",
4
+ 'ACCEPTED' = "ACCEPTED",
5
+ 'NO_CONTENT' = "NO_CONTENT",
6
+ 'BAD_REQUEST' = "BAD_REQUEST",
7
+ 'UNAUTHORIZED' = "UNAUTHORIZED",
8
+ 'FORBIDDEN' = "FORBIDDEN",
9
+ 'NOT_FOUND' = "NOT_FOUND",
10
+ 'CONFLICT' = "CONFLICT",
11
+ 'GONE' = "GONE",
12
+ 'TOO_MANY_REQUESTS' = "TOO_MANY_REQUESTS",
13
+ 'INTERNAL_SERVER_ERROR' = "INTERNAL_SERVER_ERROR",
14
+ 'NOT_IMPLEMENTED' = "NOT_IMPLEMENTED",
15
+ 'BAD_GATEWAY' = "BAD_GATEWAY",
16
+ 'SERVICE_UNAVAILABLE' = "SERVICE_UNAVAILABLE"
17
+ }
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HTTPStatus = void 0;
4
+ var HTTPStatus;
5
+ (function (HTTPStatus) {
6
+ HTTPStatus["OK"] = "OK";
7
+ HTTPStatus["CREATED"] = "CREATED";
8
+ HTTPStatus["ACCEPTED"] = "ACCEPTED";
9
+ HTTPStatus["NO_CONTENT"] = "NO_CONTENT";
10
+ HTTPStatus["BAD_REQUEST"] = "BAD_REQUEST";
11
+ HTTPStatus["UNAUTHORIZED"] = "UNAUTHORIZED";
12
+ HTTPStatus["FORBIDDEN"] = "FORBIDDEN";
13
+ HTTPStatus["NOT_FOUND"] = "NOT_FOUND";
14
+ HTTPStatus["CONFLICT"] = "CONFLICT";
15
+ HTTPStatus["GONE"] = "GONE";
16
+ HTTPStatus["TOO_MANY_REQUESTS"] = "TOO_MANY_REQUESTS";
17
+ HTTPStatus["INTERNAL_SERVER_ERROR"] = "INTERNAL_SERVER_ERROR";
18
+ HTTPStatus["NOT_IMPLEMENTED"] = "NOT_IMPLEMENTED";
19
+ HTTPStatus["BAD_GATEWAY"] = "BAD_GATEWAY";
20
+ HTTPStatus["SERVICE_UNAVAILABLE"] = "SERVICE_UNAVAILABLE";
21
+ })(HTTPStatus = exports.HTTPStatus || (exports.HTTPStatus = {}));
@@ -1,32 +1,32 @@
1
1
  import { z } from 'zod';
2
- import { ArrayToUnion, ExtractZodOutput } from './utils';
2
+ import { ArrayToUnion, ExtractZodOutput, ZodSchemaOuput } from './utils';
3
3
  export type EndpointResponseSchema = {
4
4
  status: number;
5
5
  description: string;
6
6
  schema: z.ZodSchema<any> | z.ZodVoid;
7
7
  };
8
- export type MiddlewareHandler<TResponseSchema, TRequestBody = undefined, TRequestParams = undefined, TRequestQuery = undefined, TRequestHeaders = undefined, TContext = undefined> = (request: {
9
- body: TRequestBody;
10
- params: TRequestParams;
11
- query: TRequestQuery;
12
- headers: TRequestHeaders;
8
+ export type MiddlewareHandler<TResponseSchema, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TContextSchema> = (request: {
9
+ body: ZodSchemaOuput<TRequestBodySchema>;
10
+ params: ZodSchemaOuput<TRequestParamsSchema>;
11
+ query: ZodSchemaOuput<TRequestQuerySchema>;
12
+ headers: ZodSchemaOuput<TRequestHeadersSchema>;
13
13
  ip: string;
14
14
  baseUrl: string;
15
15
  path: string;
16
16
  method: string;
17
- }, send: (response: ExtractZodOutput<ArrayToUnion<TResponseSchema>>) => void, next: (context: TContext) => void) => Promise<void>;
18
- export type MiddlewareOptions<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBody = undefined, TRequestParams = undefined, TRequestQuery = undefined, TRequestHeaders = undefined, TContext = undefined> = {
17
+ }, send: (response: ExtractZodOutput<ArrayToUnion<TResponseSchema>>) => void, next: (context: ZodSchemaOuput<TContextSchema>) => void) => Promise<void>;
18
+ export type MiddlewareOptions<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TContextSchema> = {
19
19
  schemas?: {
20
- body?: z.ZodSchema<TRequestBody>;
21
- params?: z.ZodObject<z.ZodRawShape, 'strip', z.ZodTypeAny, TRequestParams>;
22
- query?: z.ZodObject<z.ZodRawShape, 'strip', z.ZodTypeAny, TRequestQuery>;
23
- headers?: z.ZodObject<z.ZodRawShape, 'strip', z.ZodTypeAny, TRequestHeaders>;
24
- context?: z.ZodSchema<TContext>;
20
+ body?: TRequestBodySchema;
21
+ params?: TRequestParamsSchema;
22
+ query?: TRequestQuerySchema;
23
+ headers?: TRequestHeadersSchema;
24
+ context?: TContextSchema;
25
25
  };
26
26
  responses: TResponseSchemas;
27
27
  errors?: Record<string, number>;
28
28
  };
29
- export type Middleware<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBody = undefined, TRequestParams = undefined, TRequestQuery = undefined, TRequestHeaders = undefined, TContext = undefined> = {
30
- options: MiddlewareOptions<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TContext>;
31
- handler: MiddlewareHandler<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TContext>;
29
+ export type Middleware<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TContextSchema> = {
30
+ options: MiddlewareOptions<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TContextSchema>;
31
+ handler: MiddlewareHandler<TResponseSchemas, TRequestBodySchema, TRequestParamsSchema, TRequestQuerySchema, TRequestHeadersSchema, TContextSchema>;
32
32
  };
@@ -7,6 +7,8 @@ export type ExtractZodOutput<T> = T extends {
7
7
  status: Z;
8
8
  body: V;
9
9
  } : never;
10
+ export type ZodObjectSchemaOrUndefined = z.ZodObject<any> | undefined;
11
+ export type ZodSchemaOuput<T> = T extends z.ZodSchema<any> ? z.infer<T> : undefined;
10
12
  export type ExtractZodOutputFromMiddleware<T> = T extends {
11
13
  options: {
12
14
  schemas?: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucaapp/service-utils",
3
- "version": "1.30.1",
3
+ "version": "1.32.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [