@lucaapp/service-utils 1.22.0 → 1.23.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/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/api/api.d.ts +29 -0
- package/dist/lib/api/api.js +58 -0
- package/dist/lib/api/endpoint.d.ts +8 -0
- package/dist/lib/api/endpoint.js +115 -0
- package/dist/lib/api/index.d.ts +6 -0
- package/dist/lib/api/index.js +24 -0
- package/dist/lib/api/middleware.d.ts +2 -0
- package/dist/lib/api/middleware.js +10 -0
- package/dist/lib/api/response.d.ts +85 -0
- package/dist/lib/api/response.js +65 -0
- package/dist/lib/api/send.d.ts +40 -0
- package/dist/lib/api/send.js +49 -0
- package/dist/lib/api/types/endpoint.d.ts +19 -0
- package/dist/lib/api/types/endpoint.js +2 -0
- package/dist/lib/api/types/middleware.d.ts +27 -0
- package/dist/lib/api/types/middleware.js +2 -0
- package/dist/lib/api/types/utils.d.ts +25 -0
- package/dist/lib/api/types/utils.js +2 -0
- package/dist/lib/kafka/events/location.d.ts +1 -1
- package/dist/lib/kafka/index.d.ts +1 -1
- package/dist/lib/kafka/types.d.ts +1 -1
- package/dist/lib/wsEvent/index.js +3 -1
- package/package.json +12 -2
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./lib/api"), exports);
|
|
17
18
|
__exportStar(require("./lib/kafka"), exports);
|
|
18
19
|
__exportStar(require("./lib/serviceIdentity"), exports);
|
|
19
20
|
__exportStar(require("./lib/urlEncoded"), exports);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import 'express-async-errors';
|
|
3
|
+
import { OpenAPIRegistry } from '@asteasolutions/zod-to-openapi';
|
|
4
|
+
import { EndpointHandler, EndpointOptions } from './types/endpoint';
|
|
5
|
+
import { Middleware, EndpointResponseSchema } from './types/middleware';
|
|
6
|
+
type OpenApiVersion = '3.0.0' | '3.0.1' | '3.0.2' | '3.0.3' | '3.1.0';
|
|
7
|
+
type ApiConstructorOptions = {
|
|
8
|
+
prefixPath?: string;
|
|
9
|
+
openApiVersion?: OpenApiVersion;
|
|
10
|
+
apiVersion?: string;
|
|
11
|
+
apiTitle?: string;
|
|
12
|
+
apiDescription?: string;
|
|
13
|
+
};
|
|
14
|
+
export declare class Api {
|
|
15
|
+
router: Router;
|
|
16
|
+
registry: OpenAPIRegistry;
|
|
17
|
+
openApiVersion: OpenApiVersion;
|
|
18
|
+
apiVersion: string;
|
|
19
|
+
apiTitle: string;
|
|
20
|
+
apiDescription: string;
|
|
21
|
+
private prefixPath;
|
|
22
|
+
constructor(options?: ApiConstructorOptions);
|
|
23
|
+
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;
|
|
24
|
+
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;
|
|
25
|
+
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;
|
|
26
|
+
generateOpenAPISpec(): import("openapi3-ts").OpenAPIObject;
|
|
27
|
+
mountSwaggerMiddlewares(): void;
|
|
28
|
+
}
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Api = void 0;
|
|
7
|
+
const express_1 = require("express");
|
|
8
|
+
require("express-async-errors");
|
|
9
|
+
const swagger_ui_express_1 = __importDefault(require("swagger-ui-express"));
|
|
10
|
+
const zod_to_openapi_1 = require("@asteasolutions/zod-to-openapi");
|
|
11
|
+
const endpoint_1 = require("./endpoint");
|
|
12
|
+
class Api {
|
|
13
|
+
constructor(options = {}) {
|
|
14
|
+
this.router = (0, express_1.Router)();
|
|
15
|
+
this.registry = new zod_to_openapi_1.OpenAPIRegistry();
|
|
16
|
+
this.prefixPath = options.prefixPath || '';
|
|
17
|
+
this.openApiVersion = options.openApiVersion || '3.0.0';
|
|
18
|
+
this.apiVersion = options.apiVersion || '1.0.0';
|
|
19
|
+
this.apiTitle = options.apiTitle || 'API';
|
|
20
|
+
this.apiDescription = options.apiDescription || '';
|
|
21
|
+
this.mountSwaggerMiddlewares();
|
|
22
|
+
}
|
|
23
|
+
get(path, summary, options, handler) {
|
|
24
|
+
(0, endpoint_1.mountEndpoint)(this.router, 'get', path, options, handler);
|
|
25
|
+
(0, endpoint_1.registerEndpoint)(this.registry, 'get', this.prefixPath, path, summary, options);
|
|
26
|
+
}
|
|
27
|
+
post(path, summary, options, handler) {
|
|
28
|
+
(0, endpoint_1.mountEndpoint)(this.router, 'post', path, options, handler);
|
|
29
|
+
(0, endpoint_1.registerEndpoint)(this.registry, 'post', this.prefixPath, path, summary, options);
|
|
30
|
+
}
|
|
31
|
+
patch(path, summary, options, handler) {
|
|
32
|
+
(0, endpoint_1.mountEndpoint)(this.router, 'patch', path, options, handler);
|
|
33
|
+
(0, endpoint_1.registerEndpoint)(this.registry, 'patch', this.prefixPath, path, summary, options);
|
|
34
|
+
}
|
|
35
|
+
generateOpenAPISpec() {
|
|
36
|
+
const generator = new zod_to_openapi_1.OpenAPIGenerator(this.registry.definitions, this.openApiVersion);
|
|
37
|
+
const spec = generator.generateDocument({
|
|
38
|
+
info: {
|
|
39
|
+
version: this.apiVersion,
|
|
40
|
+
title: this.apiTitle,
|
|
41
|
+
description: this.apiDescription,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
return spec;
|
|
45
|
+
}
|
|
46
|
+
mountSwaggerMiddlewares() {
|
|
47
|
+
this.router.use('/swagger', swagger_ui_express_1.default.serve);
|
|
48
|
+
this.router.get('/swagger', (request, response, next) => {
|
|
49
|
+
const spec = this.generateOpenAPISpec();
|
|
50
|
+
swagger_ui_express_1.default.setup(spec)(request, response, next);
|
|
51
|
+
});
|
|
52
|
+
this.router.get('/swagger.json', (request, response) => {
|
|
53
|
+
const spec = this.generateOpenAPISpec();
|
|
54
|
+
response.send(spec);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.Api = Api;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { OpenAPIRegistry } from '@asteasolutions/zod-to-openapi';
|
|
3
|
+
import { Middleware, EndpointResponseSchema } from './types/middleware';
|
|
4
|
+
import { EndpointOptions, EndpointHandler } from './types/endpoint';
|
|
5
|
+
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>) => 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;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.registerEndpoint = exports.mountEndpoint = void 0;
|
|
7
|
+
const zod_1 = require("zod");
|
|
8
|
+
const assert_1 = __importDefault(require("assert"));
|
|
9
|
+
const buildResponseConfig = (responseOptions) => {
|
|
10
|
+
const responses = {};
|
|
11
|
+
responseOptions.forEach(response => {
|
|
12
|
+
responses[String(response.status)] = {
|
|
13
|
+
description: response.description,
|
|
14
|
+
...(!(response.schema instanceof zod_1.ZodVoid) && {
|
|
15
|
+
content: {
|
|
16
|
+
'application/json': {
|
|
17
|
+
schema: response.schema,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
}),
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
return responses;
|
|
24
|
+
};
|
|
25
|
+
const mountEndpoint = (router, method, path, options, handler) => {
|
|
26
|
+
(0, assert_1.default)(options.responses.length > 0, 'You need to specify at least one response');
|
|
27
|
+
router[method](path, async (request, response) => {
|
|
28
|
+
// parse request schemas
|
|
29
|
+
const handlerRequestBody = ((await options.schemas?.body?.parseAsync(request.body)) || undefined);
|
|
30
|
+
const handlerRequestParams = ((await options.schemas?.params?.parseAsync(request.params)) || undefined);
|
|
31
|
+
const handlerRequestQuery = ((await options.schemas?.query?.parseAsync(request.query)) || undefined);
|
|
32
|
+
const handlerRequestHeaders = ((await options.schemas?.headers?.parseAsync(request.headers)) || undefined);
|
|
33
|
+
const handlerRequest = {
|
|
34
|
+
body: handlerRequestBody,
|
|
35
|
+
params: handlerRequestParams,
|
|
36
|
+
query: handlerRequestQuery,
|
|
37
|
+
headers: handlerRequestHeaders,
|
|
38
|
+
};
|
|
39
|
+
// TODO: handle middlewares and build context object
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
41
|
+
const ctx = {};
|
|
42
|
+
await handler(handlerRequest, ctx, controllerResponse => {
|
|
43
|
+
// this assertion is necessary due to the type possibly being unknown because of the edge case of an schema array with 0 elements
|
|
44
|
+
(0, assert_1.default)(typeof controllerResponse.status === 'number');
|
|
45
|
+
// get schema respective to status code
|
|
46
|
+
const { schema } = options.responses.find(responseSchema => responseSchema.status === controllerResponse.status);
|
|
47
|
+
// validate response schema
|
|
48
|
+
const validatedResponseBody = schema.parse(controllerResponse.body);
|
|
49
|
+
if (validatedResponseBody === undefined) {
|
|
50
|
+
// No Content Response
|
|
51
|
+
return response.status(controllerResponse.status).end();
|
|
52
|
+
}
|
|
53
|
+
response.status(controllerResponse.status).send(validatedResponseBody);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
exports.mountEndpoint = mountEndpoint;
|
|
58
|
+
const registerEndpoint = (registry, method, prefixPath, path, summary,
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
60
|
+
options) => {
|
|
61
|
+
let bodySchema = options.schemas?.body || undefined;
|
|
62
|
+
let paramsSchema = options.schemas?.params || undefined;
|
|
63
|
+
let querySchema = options.schemas?.query || undefined;
|
|
64
|
+
let headersSchema = options.schemas?.headers || undefined;
|
|
65
|
+
let responseSchemas = options.responses;
|
|
66
|
+
for (const middleware of options.middlewares || []) {
|
|
67
|
+
if (middleware.options.schemas?.body) {
|
|
68
|
+
bodySchema = bodySchema
|
|
69
|
+
? bodySchema.merge(middleware.options.schemas.body)
|
|
70
|
+
: middleware.options.schemas.body;
|
|
71
|
+
}
|
|
72
|
+
if (middleware.options.schemas?.params) {
|
|
73
|
+
paramsSchema = paramsSchema
|
|
74
|
+
? paramsSchema.merge(middleware.options.schemas.params)
|
|
75
|
+
: middleware.options.schemas.params;
|
|
76
|
+
}
|
|
77
|
+
if (middleware.options.schemas?.query) {
|
|
78
|
+
querySchema = querySchema
|
|
79
|
+
? querySchema.merge(middleware.options.schemas.query)
|
|
80
|
+
: middleware.options.schemas.query;
|
|
81
|
+
}
|
|
82
|
+
if (middleware.options.schemas?.headers) {
|
|
83
|
+
headersSchema = headersSchema
|
|
84
|
+
? headersSchema.merge(middleware.options.schemas.headers)
|
|
85
|
+
: middleware.options.schemas.headers;
|
|
86
|
+
}
|
|
87
|
+
if (middleware.options.responses) {
|
|
88
|
+
responseSchemas = responseSchemas.concat(middleware.options.responses);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const responseMap = buildResponseConfig(responseSchemas);
|
|
92
|
+
registry.registerPath({
|
|
93
|
+
method,
|
|
94
|
+
path: prefixPath + path,
|
|
95
|
+
summary,
|
|
96
|
+
// description: summary,
|
|
97
|
+
request: {
|
|
98
|
+
...(bodySchema && {
|
|
99
|
+
body: {
|
|
100
|
+
content: {
|
|
101
|
+
'application/json': {
|
|
102
|
+
schema: bodySchema,
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
}),
|
|
107
|
+
params: paramsSchema,
|
|
108
|
+
query: querySchema,
|
|
109
|
+
headers: headersSchema ? [headersSchema] : [],
|
|
110
|
+
},
|
|
111
|
+
// tags: ['meep'],
|
|
112
|
+
responses: responseMap,
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
exports.registerEndpoint = registerEndpoint;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.extendZodWithOpenApi = void 0;
|
|
18
|
+
var zod_to_openapi_1 = require("@asteasolutions/zod-to-openapi");
|
|
19
|
+
Object.defineProperty(exports, "extendZodWithOpenApi", { enumerable: true, get: function () { return zod_to_openapi_1.extendZodWithOpenApi; } });
|
|
20
|
+
__exportStar(require("./api"), exports);
|
|
21
|
+
__exportStar(require("./endpoint"), exports);
|
|
22
|
+
__exportStar(require("./middleware"), exports);
|
|
23
|
+
__exportStar(require("./response"), exports);
|
|
24
|
+
__exportStar(require("./send"), exports);
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { Middleware, MiddlewareOptions, MiddlewareHandler, EndpointResponseSchema } from './types/middleware';
|
|
2
|
+
export declare const createMiddleware: <TResponseSchemas extends readonly EndpointResponseSchema[], TRequestBody = undefined, TRequestParams = undefined, TRequestQuery = undefined, TRequestHeaders = undefined, TContext = undefined>(options: MiddlewareOptions<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TContext>, handler: MiddlewareHandler<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TContext>) => Middleware<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TContext>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
declare const noContentSchema: z.ZodVoid;
|
|
3
|
+
declare const badRequestErrorSchema: z.ZodObject<{
|
|
4
|
+
statusCode: z.ZodLiteral<400>;
|
|
5
|
+
error: z.ZodString;
|
|
6
|
+
message: z.ZodString;
|
|
7
|
+
}, "strip", z.ZodTypeAny, {
|
|
8
|
+
error: string;
|
|
9
|
+
message: string;
|
|
10
|
+
statusCode: 400;
|
|
11
|
+
}, {
|
|
12
|
+
error: string;
|
|
13
|
+
message: string;
|
|
14
|
+
statusCode: 400;
|
|
15
|
+
}>;
|
|
16
|
+
declare const unauthorizedErrorSchema: z.ZodObject<{
|
|
17
|
+
statusCode: z.ZodLiteral<401>;
|
|
18
|
+
error: z.ZodString;
|
|
19
|
+
message: z.ZodString;
|
|
20
|
+
}, "strip", z.ZodTypeAny, {
|
|
21
|
+
error: string;
|
|
22
|
+
message: string;
|
|
23
|
+
statusCode: 401;
|
|
24
|
+
}, {
|
|
25
|
+
error: string;
|
|
26
|
+
message: string;
|
|
27
|
+
statusCode: 401;
|
|
28
|
+
}>;
|
|
29
|
+
declare const forbiddenErrorSchema: z.ZodObject<{
|
|
30
|
+
statusCode: z.ZodLiteral<403>;
|
|
31
|
+
error: z.ZodString;
|
|
32
|
+
message: z.ZodString;
|
|
33
|
+
}, "strip", z.ZodTypeAny, {
|
|
34
|
+
error: string;
|
|
35
|
+
message: string;
|
|
36
|
+
statusCode: 403;
|
|
37
|
+
}, {
|
|
38
|
+
error: string;
|
|
39
|
+
message: string;
|
|
40
|
+
statusCode: 403;
|
|
41
|
+
}>;
|
|
42
|
+
declare const notFoundErrorSchema: z.ZodObject<{
|
|
43
|
+
statusCode: z.ZodLiteral<404>;
|
|
44
|
+
error: z.ZodString;
|
|
45
|
+
message: z.ZodString;
|
|
46
|
+
}, "strip", z.ZodTypeAny, {
|
|
47
|
+
error: string;
|
|
48
|
+
message: string;
|
|
49
|
+
statusCode: 404;
|
|
50
|
+
}, {
|
|
51
|
+
error: string;
|
|
52
|
+
message: string;
|
|
53
|
+
statusCode: 404;
|
|
54
|
+
}>;
|
|
55
|
+
export declare const okResponse: <T>(schema: z.ZodType<T, z.ZodTypeDef, T>) => {
|
|
56
|
+
status: 200;
|
|
57
|
+
description: string;
|
|
58
|
+
schema: z.ZodType<T, z.ZodTypeDef, T>;
|
|
59
|
+
};
|
|
60
|
+
export declare const noContentResponse: () => {
|
|
61
|
+
status: 204;
|
|
62
|
+
description: string;
|
|
63
|
+
schema: typeof noContentSchema;
|
|
64
|
+
};
|
|
65
|
+
export declare const badRequestResponse: () => {
|
|
66
|
+
status: 400;
|
|
67
|
+
description: string;
|
|
68
|
+
schema: typeof badRequestErrorSchema;
|
|
69
|
+
};
|
|
70
|
+
export declare const unauthorizedResponse: () => {
|
|
71
|
+
status: 401;
|
|
72
|
+
description: string;
|
|
73
|
+
schema: typeof unauthorizedErrorSchema;
|
|
74
|
+
};
|
|
75
|
+
export declare const forbiddenResponse: () => {
|
|
76
|
+
status: 403;
|
|
77
|
+
description: string;
|
|
78
|
+
schema: typeof forbiddenErrorSchema;
|
|
79
|
+
};
|
|
80
|
+
export declare const notFoundResponse: () => {
|
|
81
|
+
status: 404;
|
|
82
|
+
description: string;
|
|
83
|
+
schema: typeof notFoundErrorSchema;
|
|
84
|
+
};
|
|
85
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.notFoundResponse = exports.forbiddenResponse = exports.unauthorizedResponse = exports.badRequestResponse = exports.noContentResponse = exports.okResponse = void 0;
|
|
4
|
+
const zod_to_openapi_1 = require("@asteasolutions/zod-to-openapi");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
(0, zod_to_openapi_1.extendZodWithOpenApi)(zod_1.z);
|
|
7
|
+
// response schemas
|
|
8
|
+
const noContentSchema = zod_1.z.void();
|
|
9
|
+
const badRequestErrorSchema = zod_1.z.object({
|
|
10
|
+
statusCode: zod_1.z.literal(400),
|
|
11
|
+
error: zod_1.z.string(),
|
|
12
|
+
message: zod_1.z.string(),
|
|
13
|
+
});
|
|
14
|
+
const unauthorizedErrorSchema = zod_1.z.object({
|
|
15
|
+
statusCode: zod_1.z.literal(401),
|
|
16
|
+
error: zod_1.z.string(),
|
|
17
|
+
message: zod_1.z.string(),
|
|
18
|
+
});
|
|
19
|
+
const forbiddenErrorSchema = zod_1.z.object({
|
|
20
|
+
statusCode: zod_1.z.literal(403),
|
|
21
|
+
error: zod_1.z.string(),
|
|
22
|
+
message: zod_1.z.string(),
|
|
23
|
+
});
|
|
24
|
+
const notFoundErrorSchema = zod_1.z.object({
|
|
25
|
+
statusCode: zod_1.z.literal(404),
|
|
26
|
+
error: zod_1.z.string(),
|
|
27
|
+
message: zod_1.z.string(),
|
|
28
|
+
});
|
|
29
|
+
// response functions
|
|
30
|
+
const okResponse = (schema) => ({
|
|
31
|
+
status: 200,
|
|
32
|
+
description: 'OK',
|
|
33
|
+
schema,
|
|
34
|
+
});
|
|
35
|
+
exports.okResponse = okResponse;
|
|
36
|
+
const noContentResponse = () => ({
|
|
37
|
+
status: 204,
|
|
38
|
+
description: 'No Content',
|
|
39
|
+
schema: noContentSchema,
|
|
40
|
+
});
|
|
41
|
+
exports.noContentResponse = noContentResponse;
|
|
42
|
+
const badRequestResponse = () => ({
|
|
43
|
+
status: 400,
|
|
44
|
+
description: 'Bad Request',
|
|
45
|
+
schema: badRequestErrorSchema,
|
|
46
|
+
});
|
|
47
|
+
exports.badRequestResponse = badRequestResponse;
|
|
48
|
+
const unauthorizedResponse = () => ({
|
|
49
|
+
status: 401,
|
|
50
|
+
description: 'Unauthorized',
|
|
51
|
+
schema: unauthorizedErrorSchema,
|
|
52
|
+
});
|
|
53
|
+
exports.unauthorizedResponse = unauthorizedResponse;
|
|
54
|
+
const forbiddenResponse = () => ({
|
|
55
|
+
status: 403,
|
|
56
|
+
description: 'Forbidden',
|
|
57
|
+
schema: forbiddenErrorSchema,
|
|
58
|
+
});
|
|
59
|
+
exports.forbiddenResponse = forbiddenResponse;
|
|
60
|
+
const notFoundResponse = () => ({
|
|
61
|
+
status: 404,
|
|
62
|
+
description: 'Not Found',
|
|
63
|
+
schema: notFoundErrorSchema,
|
|
64
|
+
});
|
|
65
|
+
exports.notFoundResponse = notFoundResponse;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export declare const ok: <T>(body: T) => {
|
|
2
|
+
status: 200;
|
|
3
|
+
body: T;
|
|
4
|
+
};
|
|
5
|
+
export declare const noContent: () => {
|
|
6
|
+
status: 204;
|
|
7
|
+
body: void;
|
|
8
|
+
};
|
|
9
|
+
export declare const badRequest: (message?: string) => {
|
|
10
|
+
status: 400;
|
|
11
|
+
body: {
|
|
12
|
+
statusCode: 400;
|
|
13
|
+
error: string;
|
|
14
|
+
message: string;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export declare const unauthorized: (message?: string) => {
|
|
18
|
+
status: 401;
|
|
19
|
+
body: {
|
|
20
|
+
statusCode: 401;
|
|
21
|
+
error: string;
|
|
22
|
+
message: string;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
export declare const forbidden: (message?: string) => {
|
|
26
|
+
status: 403;
|
|
27
|
+
body: {
|
|
28
|
+
statusCode: 403;
|
|
29
|
+
error: string;
|
|
30
|
+
message: string;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
export declare const notFound: (message?: string) => {
|
|
34
|
+
status: 404;
|
|
35
|
+
body: {
|
|
36
|
+
statusCode: 404;
|
|
37
|
+
error: string;
|
|
38
|
+
message: string;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.notFound = exports.forbidden = exports.unauthorized = exports.badRequest = exports.noContent = exports.ok = void 0;
|
|
4
|
+
const ok = (body) => ({
|
|
5
|
+
status: 200,
|
|
6
|
+
body,
|
|
7
|
+
});
|
|
8
|
+
exports.ok = ok;
|
|
9
|
+
const noContent = () => ({
|
|
10
|
+
status: 204,
|
|
11
|
+
body: undefined,
|
|
12
|
+
});
|
|
13
|
+
exports.noContent = noContent;
|
|
14
|
+
const badRequest = (message) => ({
|
|
15
|
+
status: 400,
|
|
16
|
+
body: {
|
|
17
|
+
statusCode: 400,
|
|
18
|
+
error: 'Bad request',
|
|
19
|
+
message: message || 'Bad request',
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
exports.badRequest = badRequest;
|
|
23
|
+
const unauthorized = (message) => ({
|
|
24
|
+
status: 401,
|
|
25
|
+
body: {
|
|
26
|
+
statusCode: 401,
|
|
27
|
+
error: 'Unauthorized',
|
|
28
|
+
message: message || 'Unauthorized',
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
exports.unauthorized = unauthorized;
|
|
32
|
+
const forbidden = (message) => ({
|
|
33
|
+
status: 403,
|
|
34
|
+
body: {
|
|
35
|
+
statusCode: 403,
|
|
36
|
+
error: 'Forbidden',
|
|
37
|
+
message: message || 'Forbidden',
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
exports.forbidden = forbidden;
|
|
41
|
+
const notFound = (message) => ({
|
|
42
|
+
status: 404,
|
|
43
|
+
body: {
|
|
44
|
+
statusCode: 404,
|
|
45
|
+
error: 'Not found',
|
|
46
|
+
message: message || 'Not found',
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
exports.notFound = notFound;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
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;
|
|
9
|
+
}, 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> = {
|
|
11
|
+
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>;
|
|
16
|
+
};
|
|
17
|
+
middlewares?: TMiddlewares;
|
|
18
|
+
responses: TResponseSchemas;
|
|
19
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ArrayToUnion, ExtractZodOutput } from './utils';
|
|
3
|
+
export type EndpointResponseSchema = {
|
|
4
|
+
status: number;
|
|
5
|
+
description: string;
|
|
6
|
+
schema: z.ZodSchema<any> | z.ZodVoid;
|
|
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;
|
|
13
|
+
}, send: (response: ExtractZodOutput<ArrayToUnion<TResponseSchema>>) => void, next: (context: TContext) => void) => Promise<void>;
|
|
14
|
+
export type MiddlewareOptions<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBody = undefined, TRequestParams = undefined, TRequestQuery = undefined, TRequestHeaders = undefined, TContext = undefined> = {
|
|
15
|
+
schemas?: {
|
|
16
|
+
body?: z.ZodSchema<TRequestBody>;
|
|
17
|
+
params?: z.ZodObject<z.ZodRawShape, 'strip', z.ZodTypeAny, TRequestParams>;
|
|
18
|
+
query?: z.ZodObject<z.ZodRawShape, 'strip', z.ZodTypeAny, TRequestQuery>;
|
|
19
|
+
headers?: z.ZodObject<z.ZodRawShape, 'strip', z.ZodTypeAny, TRequestHeaders>;
|
|
20
|
+
context?: z.ZodSchema<TContext>;
|
|
21
|
+
};
|
|
22
|
+
responses: TResponseSchemas;
|
|
23
|
+
};
|
|
24
|
+
export type Middleware<TResponseSchemas extends ReadonlyArray<EndpointResponseSchema>, TRequestBody = undefined, TRequestParams = undefined, TRequestQuery = undefined, TRequestHeaders = undefined, TContext = undefined> = {
|
|
25
|
+
options: MiddlewareOptions<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TContext>;
|
|
26
|
+
handler: MiddlewareHandler<TResponseSchemas, TRequestBody, TRequestParams, TRequestQuery, TRequestHeaders, TContext>;
|
|
27
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export type ArrayToUnion<T> = T[keyof T];
|
|
3
|
+
export type ExtractZodOutput<T> = T extends {
|
|
4
|
+
status: infer Z;
|
|
5
|
+
schema: z.ZodSchema<infer V>;
|
|
6
|
+
} ? {
|
|
7
|
+
status: Z;
|
|
8
|
+
body: V;
|
|
9
|
+
} : never;
|
|
10
|
+
export type ExtractZodOutputFromMiddleware<T> = T extends {
|
|
11
|
+
options: {
|
|
12
|
+
schemas?: {
|
|
13
|
+
context?: z.ZodSchema<infer V>;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
} ? V : undefined;
|
|
17
|
+
export type Always<T> = T extends object ? T : {};
|
|
18
|
+
type AllKeys<T> = T extends any ? keyof T : never;
|
|
19
|
+
type PickType<T, K extends AllKeys<T>> = T extends {
|
|
20
|
+
[k in K]: any;
|
|
21
|
+
} ? T[K] : never;
|
|
22
|
+
export type Merge<T extends object> = {
|
|
23
|
+
[k in AllKeys<T>]: PickType<T, k>;
|
|
24
|
+
};
|
|
25
|
+
export {};
|
|
@@ -17,4 +17,4 @@ type KafkaConfiguration = {
|
|
|
17
17
|
type EventPayloadHandler<T extends KafkaTopic> = (message: Omit<KafkaMessage, 'value'> & {
|
|
18
18
|
value: KafkaEvent<T>;
|
|
19
19
|
}) => Promise<void>;
|
|
20
|
-
export type { KafkaEvent, KafkaConfiguration, EventPayloadHandler
|
|
20
|
+
export type { KafkaEvent, KafkaConfiguration, EventPayloadHandler };
|
|
@@ -7,7 +7,9 @@ const generateSubscriptionId = () => {
|
|
|
7
7
|
return (0, crypto_1.randomBytes)(32).toString('base64');
|
|
8
8
|
};
|
|
9
9
|
exports.generateSubscriptionId = generateSubscriptionId;
|
|
10
|
-
const emitWebsocketEvent = async (kafkaClient, subId, type,
|
|
10
|
+
const emitWebsocketEvent = async (kafkaClient, subId, type,
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
|
+
data) => {
|
|
11
13
|
const issuer = kafkaClient.serviceIdentity.identityName;
|
|
12
14
|
// using WS_EVENT_backend since all WS_EVENTs use same schema
|
|
13
15
|
const topic = `wsevent_${issuer}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lucaapp/service-utils",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.23.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -26,20 +26,28 @@
|
|
|
26
26
|
"@typescript-eslint/parser": "^5.30.6",
|
|
27
27
|
"conventional-changelog-conventionalcommits": "^5.0.0",
|
|
28
28
|
"eslint": "^8.19.0",
|
|
29
|
+
"eslint-plugin-prettier": "4.2.1",
|
|
29
30
|
"improved-yarn-audit": "^3.0.0",
|
|
30
31
|
"jest": "^28.1.2",
|
|
31
32
|
"jest-junit": "^14.0.0",
|
|
33
|
+
"prettier": "2.7.1",
|
|
32
34
|
"semantic-release": "^19.0.3",
|
|
33
35
|
"semantic-release-monorepo": "^7.0.5",
|
|
36
|
+
"supertest": "^6.3.3",
|
|
34
37
|
"ts-jest": "^28.0.5",
|
|
35
38
|
"typescript": "^4.7.4"
|
|
36
39
|
},
|
|
37
40
|
"dependencies": {
|
|
41
|
+
"@asteasolutions/zod-to-openapi": "4.1.0",
|
|
38
42
|
"@hapi/boom": "^10.0.0",
|
|
39
43
|
"@types/express": "4.17.13",
|
|
40
44
|
"@types/response-time": "^2.3.5",
|
|
45
|
+
"@types/supertest": "^2.0.12",
|
|
46
|
+
"@types/swagger-ui-express": "4.1.3",
|
|
41
47
|
"axios": "^0.27.2",
|
|
42
48
|
"cls-rtracer": "^2.6.2",
|
|
49
|
+
"express": "4.18.1",
|
|
50
|
+
"express-async-errors": "3.1.1",
|
|
43
51
|
"jose": "4.9.2",
|
|
44
52
|
"kafkajs": "2.1.0",
|
|
45
53
|
"lodash": "^4.17.21",
|
|
@@ -47,7 +55,9 @@
|
|
|
47
55
|
"pino-http": "8.2.1",
|
|
48
56
|
"prom-client": "14.1.0",
|
|
49
57
|
"response-time": "^2.3.2",
|
|
58
|
+
"swagger-ui-express": "4.5.0",
|
|
50
59
|
"url-value-parser": "^2.2.0",
|
|
51
|
-
"uuid": "^9.0.0"
|
|
60
|
+
"uuid": "^9.0.0",
|
|
61
|
+
"zod": "3.11.6"
|
|
52
62
|
}
|
|
53
63
|
}
|