api-machine 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -0
- package/LICENSE.md +20 -0
- package/README.md +383 -0
- package/authentication/authenticated-request.d.ts +4 -0
- package/authentication/authenticated-request.js +3 -0
- package/authentication/authenticated-request.js.map +1 -0
- package/authentication/authentication-scheme.d.ts +38 -0
- package/authentication/authentication-scheme.js +21 -0
- package/authentication/authentication-scheme.js.map +1 -0
- package/authentication/index.d.ts +4 -0
- package/authentication/index.js +9 -0
- package/authentication/index.js.map +1 -0
- package/authentication/middleware/bearer-authentication.d.ts +12 -0
- package/authentication/middleware/bearer-authentication.js +49 -0
- package/authentication/middleware/bearer-authentication.js.map +1 -0
- package/authentication/middleware/index.d.ts +1 -0
- package/authentication/middleware/index.js +6 -0
- package/authentication/middleware/index.js.map +1 -0
- package/authentication/schemes/bearer-authentication-scheme.d.ts +37 -0
- package/authentication/schemes/bearer-authentication-scheme.js +43 -0
- package/authentication/schemes/bearer-authentication-scheme.js.map +1 -0
- package/authentication/schemes/index.d.ts +1 -0
- package/authentication/schemes/index.js +6 -0
- package/authentication/schemes/index.js.map +1 -0
- package/error/error-options.d.ts +4 -0
- package/error/error-options.js +3 -0
- package/error/error-options.js.map +1 -0
- package/error/error-response.d.ts +7 -0
- package/error/error-response.js +3 -0
- package/error/error-response.js.map +1 -0
- package/error/http-errors/400-bad-request-error.d.ts +12 -0
- package/error/http-errors/400-bad-request-error.js +20 -0
- package/error/http-errors/400-bad-request-error.js.map +1 -0
- package/error/http-errors/401-unauthorized-error.d.ts +14 -0
- package/error/http-errors/401-unauthorized-error.js +24 -0
- package/error/http-errors/401-unauthorized-error.js.map +1 -0
- package/error/http-errors/402-payment-required-error.d.ts +10 -0
- package/error/http-errors/402-payment-required-error.js +18 -0
- package/error/http-errors/402-payment-required-error.js.map +1 -0
- package/error/http-errors/403-forbidden-error.d.ts +10 -0
- package/error/http-errors/403-forbidden-error.js +18 -0
- package/error/http-errors/403-forbidden-error.js.map +1 -0
- package/error/http-errors/404-not-found-error.d.ts +10 -0
- package/error/http-errors/404-not-found-error.js +18 -0
- package/error/http-errors/404-not-found-error.js.map +1 -0
- package/error/http-errors/405-method-not-allowed-error.d.ts +13 -0
- package/error/http-errors/405-method-not-allowed-error.js +27 -0
- package/error/http-errors/405-method-not-allowed-error.js.map +1 -0
- package/error/http-errors/406-not-acceptable-error.d.ts +11 -0
- package/error/http-errors/406-not-acceptable-error.js +19 -0
- package/error/http-errors/406-not-acceptable-error.js.map +1 -0
- package/error/http-errors/407-proxy-authentication-required-error.d.ts +13 -0
- package/error/http-errors/407-proxy-authentication-required-error.js +23 -0
- package/error/http-errors/407-proxy-authentication-required-error.js.map +1 -0
- package/error/http-errors/408-request-timeout-error.d.ts +10 -0
- package/error/http-errors/408-request-timeout-error.js +18 -0
- package/error/http-errors/408-request-timeout-error.js.map +1 -0
- package/error/http-errors/409-conflict-error.d.ts +10 -0
- package/error/http-errors/409-conflict-error.js +18 -0
- package/error/http-errors/409-conflict-error.js.map +1 -0
- package/error/http-errors/410-gone-error.d.ts +10 -0
- package/error/http-errors/410-gone-error.js +18 -0
- package/error/http-errors/410-gone-error.js.map +1 -0
- package/error/http-errors/411-length-required-error.d.ts +10 -0
- package/error/http-errors/411-length-required-error.js +18 -0
- package/error/http-errors/411-length-required-error.js.map +1 -0
- package/error/http-errors/412-precondition-failed-error.d.ts +10 -0
- package/error/http-errors/412-precondition-failed-error.js +18 -0
- package/error/http-errors/412-precondition-failed-error.js.map +1 -0
- package/error/http-errors/413-payload-too-large-error.d.ts +10 -0
- package/error/http-errors/413-payload-too-large-error.js +18 -0
- package/error/http-errors/413-payload-too-large-error.js.map +1 -0
- package/error/http-errors/414-uri-too-long-error.d.ts +10 -0
- package/error/http-errors/414-uri-too-long-error.js +18 -0
- package/error/http-errors/414-uri-too-long-error.js.map +1 -0
- package/error/http-errors/415-unsupported-media-type-error.d.ts +13 -0
- package/error/http-errors/415-unsupported-media-type-error.js +25 -0
- package/error/http-errors/415-unsupported-media-type-error.js.map +1 -0
- package/error/http-errors/416-range-not-satisfiable-error.d.ts +13 -0
- package/error/http-errors/416-range-not-satisfiable-error.js +25 -0
- package/error/http-errors/416-range-not-satisfiable-error.js.map +1 -0
- package/error/http-errors/417-expectation-failed-error.d.ts +10 -0
- package/error/http-errors/417-expectation-failed-error.js +18 -0
- package/error/http-errors/417-expectation-failed-error.js.map +1 -0
- package/error/http-errors/418-im-a-teapot-error.d.ts +10 -0
- package/error/http-errors/418-im-a-teapot-error.js +18 -0
- package/error/http-errors/418-im-a-teapot-error.js.map +1 -0
- package/error/http-errors/421-misdirected-request-error.d.ts +10 -0
- package/error/http-errors/421-misdirected-request-error.js +18 -0
- package/error/http-errors/421-misdirected-request-error.js.map +1 -0
- package/error/http-errors/422-unprocessable-entity-error.d.ts +10 -0
- package/error/http-errors/422-unprocessable-entity-error.js +18 -0
- package/error/http-errors/422-unprocessable-entity-error.js.map +1 -0
- package/error/http-errors/423-locked-error.d.ts +10 -0
- package/error/http-errors/423-locked-error.js +18 -0
- package/error/http-errors/423-locked-error.js.map +1 -0
- package/error/http-errors/424-failed-dependency-error.d.ts +10 -0
- package/error/http-errors/424-failed-dependency-error.js +18 -0
- package/error/http-errors/424-failed-dependency-error.js.map +1 -0
- package/error/http-errors/425-too-early-error.d.ts +10 -0
- package/error/http-errors/425-too-early-error.js +18 -0
- package/error/http-errors/425-too-early-error.js.map +1 -0
- package/error/http-errors/426-upgrade-required-error.d.ts +13 -0
- package/error/http-errors/426-upgrade-required-error.js +22 -0
- package/error/http-errors/426-upgrade-required-error.js.map +1 -0
- package/error/http-errors/428-precondition-required-error.d.ts +10 -0
- package/error/http-errors/428-precondition-required-error.js +18 -0
- package/error/http-errors/428-precondition-required-error.js.map +1 -0
- package/error/http-errors/429-too-many-requests-error.d.ts +13 -0
- package/error/http-errors/429-too-many-requests-error.js +25 -0
- package/error/http-errors/429-too-many-requests-error.js.map +1 -0
- package/error/http-errors/431-request-header-fields-too-large-error.d.ts +11 -0
- package/error/http-errors/431-request-header-fields-too-large-error.js +19 -0
- package/error/http-errors/431-request-header-fields-too-large-error.js.map +1 -0
- package/error/http-errors/451-unavailable-for-legal-reasons-error.d.ts +10 -0
- package/error/http-errors/451-unavailable-for-legal-reasons-error.js +18 -0
- package/error/http-errors/451-unavailable-for-legal-reasons-error.js.map +1 -0
- package/error/http-errors/http-error.d.ts +26 -0
- package/error/http-errors/http-error.js +37 -0
- package/error/http-errors/http-error.js.map +1 -0
- package/error/http-errors/index.d.ts +30 -0
- package/error/http-errors/index.js +67 -0
- package/error/http-errors/index.js.map +1 -0
- package/error/index.d.ts +3 -0
- package/error/index.js +5 -0
- package/error/index.js.map +1 -0
- package/index.d.ts +4 -0
- package/index.js +8 -0
- package/index.js.map +1 -0
- package/log/index.d.ts +1 -0
- package/log/index.js +3 -0
- package/log/index.js.map +1 -0
- package/log/log-interface.d.ts +7 -0
- package/log/log-interface.js +3 -0
- package/log/log-interface.js.map +1 -0
- package/oas/index.d.ts +2 -0
- package/oas/index.js +8 -0
- package/oas/index.js.map +1 -0
- package/oas/oas-endpoint-component-converter.d.ts +15 -0
- package/oas/oas-endpoint-component-converter.js +33 -0
- package/oas/oas-endpoint-component-converter.js.map +1 -0
- package/oas/oas-endpoint-converter.d.ts +17 -0
- package/oas/oas-endpoint-converter.js +89 -0
- package/oas/oas-endpoint-converter.js.map +1 -0
- package/oas/oas-rest-server-converter.d.ts +13 -0
- package/oas/oas-rest-server-converter.js +82 -0
- package/oas/oas-rest-server-converter.js.map +1 -0
- package/oas/routes.d.ts +8 -0
- package/oas/routes.js +24 -0
- package/oas/routes.js.map +1 -0
- package/package.json +34 -0
- package/router/base.d.ts +35 -0
- package/router/base.js +59 -0
- package/router/base.js.map +1 -0
- package/router/endpoint.d.ts +44 -0
- package/router/endpoint.js +76 -0
- package/router/endpoint.js.map +1 -0
- package/router/endpoints/delete-endpoint.d.ts +5 -0
- package/router/endpoints/delete-endpoint.js +10 -0
- package/router/endpoints/delete-endpoint.js.map +1 -0
- package/router/endpoints/get-endpoint.d.ts +5 -0
- package/router/endpoints/get-endpoint.js +10 -0
- package/router/endpoints/get-endpoint.js.map +1 -0
- package/router/endpoints/health-check-endpoint.d.ts +15 -0
- package/router/endpoints/health-check-endpoint.js +30 -0
- package/router/endpoints/health-check-endpoint.js.map +1 -0
- package/router/endpoints/index.d.ts +6 -0
- package/router/endpoints/index.js +16 -0
- package/router/endpoints/index.js.map +1 -0
- package/router/endpoints/patch-endpoint.d.ts +5 -0
- package/router/endpoints/patch-endpoint.js +10 -0
- package/router/endpoints/patch-endpoint.js.map +1 -0
- package/router/endpoints/post-endpoint.d.ts +5 -0
- package/router/endpoints/post-endpoint.js +10 -0
- package/router/endpoints/post-endpoint.js.map +1 -0
- package/router/endpoints/put-endpoint.d.ts +5 -0
- package/router/endpoints/put-endpoint.js +10 -0
- package/router/endpoints/put-endpoint.js.map +1 -0
- package/router/index.d.ts +3 -0
- package/router/index.js +15 -0
- package/router/index.js.map +1 -0
- package/router/router.d.ts +15 -0
- package/router/router.js +67 -0
- package/router/router.js.map +1 -0
- package/router/validation-middleware.d.ts +13 -0
- package/router/validation-middleware.js +45 -0
- package/router/validation-middleware.js.map +1 -0
- package/server/index.d.ts +2 -0
- package/server/index.js +8 -0
- package/server/index.js.map +1 -0
- package/server/server-options.d.ts +46 -0
- package/server/server-options.js +24 -0
- package/server/server-options.js.map +1 -0
- package/server/server.d.ts +38 -0
- package/server/server.js +178 -0
- package/server/server.js.map +1 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Router as ExpressRouter, Request as ExpressRequest, Response as ExpressResponse, NextFunction as ExpressNextFunction } from 'express';
|
|
2
|
+
import { ObjectSanitizer } from 'valsan/object-sanitizer';
|
|
3
|
+
import { BaseApiRoute } from './base';
|
|
4
|
+
import { HTTPError } from '../error';
|
|
5
|
+
export type ApiRequest = ExpressRequest;
|
|
6
|
+
export type ApiResponse = ExpressResponse;
|
|
7
|
+
export type ApiNextFunction = ExpressNextFunction;
|
|
8
|
+
export type ApiResponseData = {
|
|
9
|
+
[key: string]: any;
|
|
10
|
+
} | {
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
}[];
|
|
13
|
+
export declare enum EndpointMethod {
|
|
14
|
+
GET = "get",
|
|
15
|
+
POST = "post",
|
|
16
|
+
PUT = "put",
|
|
17
|
+
DELETE = "delete",
|
|
18
|
+
PATCH = "patch"
|
|
19
|
+
}
|
|
20
|
+
export declare abstract class BaseApiEndpoint extends BaseApiRoute {
|
|
21
|
+
path: string;
|
|
22
|
+
tag?: string;
|
|
23
|
+
method: EndpointMethod;
|
|
24
|
+
statusCode: number;
|
|
25
|
+
body?: ObjectSanitizer;
|
|
26
|
+
bodyExample?: any;
|
|
27
|
+
query?: ObjectSanitizer;
|
|
28
|
+
queryExample?: any;
|
|
29
|
+
params?: ObjectSanitizer;
|
|
30
|
+
paramsExample?: any;
|
|
31
|
+
headers?: ObjectSanitizer;
|
|
32
|
+
headersExample?: any;
|
|
33
|
+
getErrors(): {
|
|
34
|
+
[key: string]: HTTPError;
|
|
35
|
+
};
|
|
36
|
+
getTag(): string;
|
|
37
|
+
register(parentRouter: ExpressRouter, parentPath: string): Promise<void>;
|
|
38
|
+
handleWrapper(request: ApiRequest, response: ApiResponse, next: ApiNextFunction): Promise<ApiResponseData>;
|
|
39
|
+
abstract handle(request: ApiRequest, response: ApiResponse, next: ApiNextFunction): Promise<ApiResponseData>;
|
|
40
|
+
checkRequest(request: ApiRequest): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
export type ApiEndpoint = {
|
|
43
|
+
new (): BaseApiEndpoint;
|
|
44
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BaseApiEndpoint = exports.EndpointMethod = void 0;
|
|
4
|
+
const base_1 = require("./base");
|
|
5
|
+
const validation_middleware_1 = require("./validation-middleware");
|
|
6
|
+
const error_1 = require("../error");
|
|
7
|
+
var EndpointMethod;
|
|
8
|
+
(function (EndpointMethod) {
|
|
9
|
+
EndpointMethod["GET"] = "get";
|
|
10
|
+
EndpointMethod["POST"] = "post";
|
|
11
|
+
EndpointMethod["PUT"] = "put";
|
|
12
|
+
EndpointMethod["DELETE"] = "delete";
|
|
13
|
+
EndpointMethod["PATCH"] = "patch";
|
|
14
|
+
})(EndpointMethod || (exports.EndpointMethod = EndpointMethod = {}));
|
|
15
|
+
class BaseApiEndpoint extends base_1.BaseApiRoute {
|
|
16
|
+
path = '';
|
|
17
|
+
tag;
|
|
18
|
+
method = EndpointMethod.GET;
|
|
19
|
+
statusCode = 200;
|
|
20
|
+
body;
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
|
+
bodyExample;
|
|
23
|
+
query;
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
25
|
+
queryExample;
|
|
26
|
+
params;
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
28
|
+
paramsExample;
|
|
29
|
+
headers;
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
31
|
+
headersExample;
|
|
32
|
+
getErrors() {
|
|
33
|
+
return {
|
|
34
|
+
parse: new error_1.BadRequestError(),
|
|
35
|
+
validation: new error_1.UnprocessableEntityError(),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
getTag() {
|
|
39
|
+
// Determine tag from router if available, fallback to class name
|
|
40
|
+
return this.tag || this.constructor.name.replace(/Endpoint$/, '');
|
|
41
|
+
}
|
|
42
|
+
async register(parentRouter, parentPath) {
|
|
43
|
+
if (!this.name) {
|
|
44
|
+
this.name = this.constructor.name.replace(/Endpoint$/, '');
|
|
45
|
+
}
|
|
46
|
+
this.registerRoutePath(parentPath);
|
|
47
|
+
// Collect middleware including authentication
|
|
48
|
+
const endpointMiddleware = [...this.middleware];
|
|
49
|
+
// Add authentication middleware based on effective authentication
|
|
50
|
+
// This implements the cascading: endpoint → router → server
|
|
51
|
+
const effectiveAuth = this.getEffectiveAuthentication();
|
|
52
|
+
if (effectiveAuth) {
|
|
53
|
+
endpointMiddleware.push(effectiveAuth.getMiddleware());
|
|
54
|
+
}
|
|
55
|
+
// Register with middleware (if any) before the handler
|
|
56
|
+
if (endpointMiddleware.length > 0) {
|
|
57
|
+
parentRouter[this.method](this.path, ...endpointMiddleware, this.handleWrapper.bind(this));
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
parentRouter[this.method](this.path, this.handleWrapper.bind(this));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async handleWrapper(request, response, next) {
|
|
64
|
+
await this.checkRequest(request);
|
|
65
|
+
const data = await this.handle(request, response, next);
|
|
66
|
+
response.status(this.statusCode);
|
|
67
|
+
return response.send(data);
|
|
68
|
+
}
|
|
69
|
+
async checkRequest(request) {
|
|
70
|
+
// Validate request parts (body, query, params, headers)
|
|
71
|
+
// if sanitizers are present
|
|
72
|
+
await (0, validation_middleware_1.validateRequest)(this, request);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
exports.BaseApiEndpoint = BaseApiEndpoint;
|
|
76
|
+
//# sourceMappingURL=endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint.js","sourceRoot":"","sources":["../../../src/router/endpoint.ts"],"names":[],"mappings":";;;AASA,iCAAsC;AACtC,mEAA0D;AAC1D,oCAAgF;AAShF,IAAY,cAMX;AAND,WAAY,cAAc;IACzB,6BAAW,CAAA;IACX,+BAAa,CAAA;IACb,6BAAW,CAAA;IACX,mCAAiB,CAAA;IACjB,iCAAe,CAAA;AAChB,CAAC,EANW,cAAc,8BAAd,cAAc,QAMzB;AAED,MAAsB,eAAgB,SAAQ,mBAAY;IAChD,IAAI,GAAG,EAAE,CAAC;IACZ,GAAG,CAAU;IACb,MAAM,GAAmB,cAAc,CAAC,GAAG,CAAC;IAC5C,UAAU,GAAW,GAAG,CAAC;IAEzB,IAAI,CAAmB;IAC9B,8DAA8D;IACvD,WAAW,CAAO;IAElB,KAAK,CAAmB;IAC/B,8DAA8D;IACvD,YAAY,CAAO;IAEnB,MAAM,CAAmB;IAChC,8DAA8D;IACvD,aAAa,CAAO;IAEpB,OAAO,CAAmB;IACjC,8DAA8D;IACvD,cAAc,CAAO;IAErB,SAAS;QACf,OAAO;YACN,KAAK,EAAE,IAAI,uBAAe,EAAE;YAC5B,UAAU,EAAE,IAAI,gCAAwB,EAAE;SAC1C,CAAC;IACH,CAAC;IAEM,MAAM;QACZ,iEAAiE;QACjE,OAAO,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IACnE,CAAC;IAEe,KAAK,CAAC,QAAQ,CAC7B,YAA2B,EAC3B,UAAkB;QAElB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAChB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC5D,CAAC;QAED,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;QAEnC,8CAA8C;QAC9C,MAAM,kBAAkB,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;QAEhD,kEAAkE;QAClE,4DAA4D;QAC5D,MAAM,aAAa,GAAG,IAAI,CAAC,0BAA0B,EAAE,CAAC;QACxD,IAAI,aAAa,EAAE,CAAC;YACnB,kBAAkB,CAAC,IAAI,CAAC,aAAa,CAAC,aAAa,EAAE,CAAC,CAAC;QACxD,CAAC;QAED,uDAAuD;QACvD,IAAI,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CACxB,IAAI,CAAC,IAAI,EACT,GAAG,kBAAkB,EACrB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAC7B,CAAC;QACH,CAAC;aACI,CAAC;YACL,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACrE,CAAC;IACF,CAAC;IAEM,KAAK,CAAC,aAAa,CACzB,OAAmB,EACnB,QAAqB,EACrB,IAAqB;QAErB,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;QAExD,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACjC,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAQM,KAAK,CAAC,YAAY,CAAC,OAAmB;QAC5C,wDAAwD;QACxD,6BAA6B;QAC7B,MAAM,IAAA,uCAAe,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACtC,CAAC;CACD;AA1FD,0CA0FC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DeleteEndpoint = void 0;
|
|
4
|
+
const endpoint_1 = require("../endpoint");
|
|
5
|
+
class DeleteEndpoint extends endpoint_1.BaseApiEndpoint {
|
|
6
|
+
method = endpoint_1.EndpointMethod.DELETE;
|
|
7
|
+
statusCode = 204;
|
|
8
|
+
}
|
|
9
|
+
exports.DeleteEndpoint = DeleteEndpoint;
|
|
10
|
+
//# sourceMappingURL=delete-endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delete-endpoint.js","sourceRoot":"","sources":["../../../../src/router/endpoints/delete-endpoint.ts"],"names":[],"mappings":";;;AAAA,0CAA8D;AAE9D,MAAsB,cAAe,SAAQ,0BAAe;IAClD,MAAM,GAAG,yBAAc,CAAC,MAAM,CAAC;IAC/B,UAAU,GAAG,GAAG,CAAC;CAC1B;AAHD,wCAGC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GetEndpoint = void 0;
|
|
4
|
+
const endpoint_1 = require("../endpoint");
|
|
5
|
+
class GetEndpoint extends endpoint_1.BaseApiEndpoint {
|
|
6
|
+
method = endpoint_1.EndpointMethod.GET;
|
|
7
|
+
statusCode = 200;
|
|
8
|
+
}
|
|
9
|
+
exports.GetEndpoint = GetEndpoint;
|
|
10
|
+
//# sourceMappingURL=get-endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-endpoint.js","sourceRoot":"","sources":["../../../../src/router/endpoints/get-endpoint.ts"],"names":[],"mappings":";;;AAAA,0CAA8D;AAE9D,MAAsB,WAAY,SAAQ,0BAAe;IAC/C,MAAM,GAAG,yBAAc,CAAC,GAAG,CAAC;IAC5B,UAAU,GAAG,GAAG,CAAC;CAC1B;AAHD,kCAGC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ApiRequest, ApiResponse } from '../endpoint';
|
|
2
|
+
import { GetEndpoint } from './get-endpoint';
|
|
3
|
+
export declare class HealthCheckEndpoint extends GetEndpoint {
|
|
4
|
+
path: string;
|
|
5
|
+
handle(_request: ApiRequest, _response: ApiResponse): Promise<{
|
|
6
|
+
status: string;
|
|
7
|
+
timestamp: string;
|
|
8
|
+
uptime: number;
|
|
9
|
+
environment: string;
|
|
10
|
+
}>;
|
|
11
|
+
getStatus(): Promise<string>;
|
|
12
|
+
getTimestamp(): Promise<string>;
|
|
13
|
+
getUptime(): Promise<number>;
|
|
14
|
+
getEnvironment(): Promise<string>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HealthCheckEndpoint = void 0;
|
|
4
|
+
const get_endpoint_1 = require("./get-endpoint");
|
|
5
|
+
class HealthCheckEndpoint extends get_endpoint_1.GetEndpoint {
|
|
6
|
+
path = '/health';
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
8
|
+
async handle(_request, _response) {
|
|
9
|
+
return {
|
|
10
|
+
status: await this.getStatus(),
|
|
11
|
+
timestamp: await this.getTimestamp(),
|
|
12
|
+
uptime: await this.getUptime(),
|
|
13
|
+
environment: await this.getEnvironment(),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
async getStatus() {
|
|
17
|
+
return 'ok';
|
|
18
|
+
}
|
|
19
|
+
async getTimestamp() {
|
|
20
|
+
return new Date().toISOString();
|
|
21
|
+
}
|
|
22
|
+
async getUptime() {
|
|
23
|
+
return process.uptime();
|
|
24
|
+
}
|
|
25
|
+
async getEnvironment() {
|
|
26
|
+
return process.env['NODE_ENV'] || 'development';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.HealthCheckEndpoint = HealthCheckEndpoint;
|
|
30
|
+
//# sourceMappingURL=health-check-endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health-check-endpoint.js","sourceRoot":"","sources":["../../../../src/router/endpoints/health-check-endpoint.ts"],"names":[],"mappings":";;;AACA,iDAA6C;AAE7C,MAAa,mBAAoB,SAAQ,0BAAW;IAC1C,IAAI,GAAG,SAAS,CAAC;IAE1B,6DAA6D;IAC7D,KAAK,CAAC,MAAM,CAAC,QAAoB,EAAE,SAAsB;QACxD,OAAO;YACN,MAAM,EAAE,MAAM,IAAI,CAAC,SAAS,EAAE;YAC9B,SAAS,EAAE,MAAM,IAAI,CAAC,YAAY,EAAE;YACpC,MAAM,EAAE,MAAM,IAAI,CAAC,SAAS,EAAE;YAC9B,WAAW,EAAE,MAAM,IAAI,CAAC,cAAc,EAAE;SACxC,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,SAAS;QACrB,OAAO,IAAI,CAAC;IACb,CAAC;IAEM,KAAK,CAAC,YAAY;QACxB,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACjC,CAAC;IAEM,KAAK,CAAC,SAAS;QACrB,OAAO,OAAO,CAAC,MAAM,EAAE,CAAC;IACzB,CAAC;IAEM,KAAK,CAAC,cAAc;QAC1B,OAAO,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,aAAa,CAAC;IACjD,CAAC;CACD;AA5BD,kDA4BC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { GetEndpoint } from './get-endpoint';
|
|
2
|
+
export { PostEndpoint } from './post-endpoint';
|
|
3
|
+
export { PutEndpoint } from './put-endpoint';
|
|
4
|
+
export { DeleteEndpoint } from './delete-endpoint';
|
|
5
|
+
export { PatchEndpoint } from './patch-endpoint';
|
|
6
|
+
export { HealthCheckEndpoint } from './health-check-endpoint';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HealthCheckEndpoint = exports.PatchEndpoint = exports.DeleteEndpoint = exports.PutEndpoint = exports.PostEndpoint = exports.GetEndpoint = void 0;
|
|
4
|
+
var get_endpoint_1 = require("./get-endpoint");
|
|
5
|
+
Object.defineProperty(exports, "GetEndpoint", { enumerable: true, get: function () { return get_endpoint_1.GetEndpoint; } });
|
|
6
|
+
var post_endpoint_1 = require("./post-endpoint");
|
|
7
|
+
Object.defineProperty(exports, "PostEndpoint", { enumerable: true, get: function () { return post_endpoint_1.PostEndpoint; } });
|
|
8
|
+
var put_endpoint_1 = require("./put-endpoint");
|
|
9
|
+
Object.defineProperty(exports, "PutEndpoint", { enumerable: true, get: function () { return put_endpoint_1.PutEndpoint; } });
|
|
10
|
+
var delete_endpoint_1 = require("./delete-endpoint");
|
|
11
|
+
Object.defineProperty(exports, "DeleteEndpoint", { enumerable: true, get: function () { return delete_endpoint_1.DeleteEndpoint; } });
|
|
12
|
+
var patch_endpoint_1 = require("./patch-endpoint");
|
|
13
|
+
Object.defineProperty(exports, "PatchEndpoint", { enumerable: true, get: function () { return patch_endpoint_1.PatchEndpoint; } });
|
|
14
|
+
var health_check_endpoint_1 = require("./health-check-endpoint");
|
|
15
|
+
Object.defineProperty(exports, "HealthCheckEndpoint", { enumerable: true, get: function () { return health_check_endpoint_1.HealthCheckEndpoint; } });
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/router/endpoints/index.ts"],"names":[],"mappings":";;;AAAA,+CAA6C;AAApC,2GAAA,WAAW,OAAA;AACpB,iDAA+C;AAAtC,6GAAA,YAAY,OAAA;AACrB,+CAA6C;AAApC,2GAAA,WAAW,OAAA;AACpB,qDAAmD;AAA1C,iHAAA,cAAc,OAAA;AACvB,mDAAiD;AAAxC,+GAAA,aAAa,OAAA;AACtB,iEAA8D;AAArD,4HAAA,mBAAmB,OAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PatchEndpoint = void 0;
|
|
4
|
+
const endpoint_1 = require("../endpoint");
|
|
5
|
+
class PatchEndpoint extends endpoint_1.BaseApiEndpoint {
|
|
6
|
+
method = endpoint_1.EndpointMethod.PATCH;
|
|
7
|
+
statusCode = 200;
|
|
8
|
+
}
|
|
9
|
+
exports.PatchEndpoint = PatchEndpoint;
|
|
10
|
+
//# sourceMappingURL=patch-endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patch-endpoint.js","sourceRoot":"","sources":["../../../../src/router/endpoints/patch-endpoint.ts"],"names":[],"mappings":";;;AAAA,0CAA8D;AAE9D,MAAsB,aAAc,SAAQ,0BAAe;IACjD,MAAM,GAAG,yBAAc,CAAC,KAAK,CAAC;IAC9B,UAAU,GAAG,GAAG,CAAC;CAC1B;AAHD,sCAGC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PostEndpoint = void 0;
|
|
4
|
+
const endpoint_1 = require("../endpoint");
|
|
5
|
+
class PostEndpoint extends endpoint_1.BaseApiEndpoint {
|
|
6
|
+
method = endpoint_1.EndpointMethod.POST;
|
|
7
|
+
statusCode = 201;
|
|
8
|
+
}
|
|
9
|
+
exports.PostEndpoint = PostEndpoint;
|
|
10
|
+
//# sourceMappingURL=post-endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-endpoint.js","sourceRoot":"","sources":["../../../../src/router/endpoints/post-endpoint.ts"],"names":[],"mappings":";;;AAAA,0CAA8D;AAE9D,MAAsB,YAAa,SAAQ,0BAAe;IAChD,MAAM,GAAG,yBAAc,CAAC,IAAI,CAAC;IAC7B,UAAU,GAAG,GAAG,CAAC;CAC1B;AAHD,oCAGC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PutEndpoint = void 0;
|
|
4
|
+
const endpoint_1 = require("../endpoint");
|
|
5
|
+
class PutEndpoint extends endpoint_1.BaseApiEndpoint {
|
|
6
|
+
method = endpoint_1.EndpointMethod.PUT;
|
|
7
|
+
statusCode = 200;
|
|
8
|
+
}
|
|
9
|
+
exports.PutEndpoint = PutEndpoint;
|
|
10
|
+
//# sourceMappingURL=put-endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"put-endpoint.js","sourceRoot":"","sources":["../../../../src/router/endpoints/put-endpoint.ts"],"names":[],"mappings":";;;AAAA,0CAA8D;AAE9D,MAAsB,WAAY,SAAQ,0BAAe;IAC/C,MAAM,GAAG,yBAAc,CAAC,GAAG,CAAC;IAC5B,UAAU,GAAG,GAAG,CAAC;CAC1B;AAHD,kCAGC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { ApiEndpoint, ApiRequest, ApiResponse, ApiNextFunction, BaseApiEndpoint, } from './endpoint';
|
|
2
|
+
export { ApiRouter, BaseApiRouter } from './router';
|
|
3
|
+
export { GetEndpoint, PostEndpoint, PutEndpoint, DeleteEndpoint, PatchEndpoint, HealthCheckEndpoint, } from './endpoints';
|
package/router/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HealthCheckEndpoint = exports.PatchEndpoint = exports.DeleteEndpoint = exports.PutEndpoint = exports.PostEndpoint = exports.GetEndpoint = exports.BaseApiRouter = exports.BaseApiEndpoint = void 0;
|
|
4
|
+
var endpoint_1 = require("./endpoint");
|
|
5
|
+
Object.defineProperty(exports, "BaseApiEndpoint", { enumerable: true, get: function () { return endpoint_1.BaseApiEndpoint; } });
|
|
6
|
+
var router_1 = require("./router");
|
|
7
|
+
Object.defineProperty(exports, "BaseApiRouter", { enumerable: true, get: function () { return router_1.BaseApiRouter; } });
|
|
8
|
+
var endpoints_1 = require("./endpoints");
|
|
9
|
+
Object.defineProperty(exports, "GetEndpoint", { enumerable: true, get: function () { return endpoints_1.GetEndpoint; } });
|
|
10
|
+
Object.defineProperty(exports, "PostEndpoint", { enumerable: true, get: function () { return endpoints_1.PostEndpoint; } });
|
|
11
|
+
Object.defineProperty(exports, "PutEndpoint", { enumerable: true, get: function () { return endpoints_1.PutEndpoint; } });
|
|
12
|
+
Object.defineProperty(exports, "DeleteEndpoint", { enumerable: true, get: function () { return endpoints_1.DeleteEndpoint; } });
|
|
13
|
+
Object.defineProperty(exports, "PatchEndpoint", { enumerable: true, get: function () { return endpoints_1.PatchEndpoint; } });
|
|
14
|
+
Object.defineProperty(exports, "HealthCheckEndpoint", { enumerable: true, get: function () { return endpoints_1.HealthCheckEndpoint; } });
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/router/index.ts"],"names":[],"mappings":";;;AAAA,uCAMoB;AADnB,2GAAA,eAAe,OAAA;AAGhB,mCAAoD;AAAhC,uGAAA,aAAa,OAAA;AAEjC,yCAOqB;AANpB,wGAAA,WAAW,OAAA;AACX,yGAAA,YAAY,OAAA;AACZ,wGAAA,WAAW,OAAA;AACX,2GAAA,cAAc,OAAA;AACd,0GAAA,aAAa,OAAA;AACb,gHAAA,mBAAmB,OAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Router as ExpressRouter } from 'express';
|
|
2
|
+
import { ApiRoute, BaseApiRoute } from './base';
|
|
3
|
+
export declare abstract class BaseApiRouter extends BaseApiRoute {
|
|
4
|
+
protected router: ExpressRouter;
|
|
5
|
+
registeredRoutes: BaseApiRoute[];
|
|
6
|
+
protected abstract routes(): Promise<ApiRoute[]>;
|
|
7
|
+
protected routeInstances: {
|
|
8
|
+
[key: string]: BaseApiRoute;
|
|
9
|
+
};
|
|
10
|
+
getTag(): string;
|
|
11
|
+
register(parent: ExpressRouter, parentPath: string): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export type ApiRouter = {
|
|
14
|
+
new (): BaseApiRouter;
|
|
15
|
+
};
|
package/router/router.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BaseApiRouter = void 0;
|
|
4
|
+
const express_1 = require("express");
|
|
5
|
+
const base_1 = require("./base");
|
|
6
|
+
const endpoint_1 = require("./endpoint");
|
|
7
|
+
class BaseApiRouter extends base_1.BaseApiRoute {
|
|
8
|
+
router;
|
|
9
|
+
registeredRoutes = [];
|
|
10
|
+
routeInstances = {};
|
|
11
|
+
getTag() {
|
|
12
|
+
return this.name || this.constructor.name.replace(/Router$/, '');
|
|
13
|
+
}
|
|
14
|
+
async register(parent, parentPath) {
|
|
15
|
+
this.router = (0, express_1.Router)();
|
|
16
|
+
this.registerRoutePath(parentPath);
|
|
17
|
+
// Collect non-authentication middleware
|
|
18
|
+
// Authentication is handled at the endpoint level to allow overrides
|
|
19
|
+
const middlewareWithoutAuth = [...this.middleware];
|
|
20
|
+
// Register router with non-auth middleware if any
|
|
21
|
+
if (middlewareWithoutAuth.length > 0) {
|
|
22
|
+
parent.use(this.path, ...middlewareWithoutAuth, this.router);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
parent.use(this.path, this.router);
|
|
26
|
+
}
|
|
27
|
+
const routes = await this.routes();
|
|
28
|
+
// Track which paths have which methods
|
|
29
|
+
const pathMethods = new Map();
|
|
30
|
+
const tag = this.getTag();
|
|
31
|
+
// First pass: register all endpoints and track their methods
|
|
32
|
+
for (const route of routes) {
|
|
33
|
+
const instance = new route();
|
|
34
|
+
// Set parent relationship for authentication cascading
|
|
35
|
+
instance.parentRoute = this;
|
|
36
|
+
if (instance instanceof endpoint_1.BaseApiEndpoint) {
|
|
37
|
+
instance.tag = tag;
|
|
38
|
+
}
|
|
39
|
+
await instance.register(this.router, this.fullPath);
|
|
40
|
+
this.registeredRoutes.push(instance);
|
|
41
|
+
// Track endpoint methods for 405 handling
|
|
42
|
+
if (instance instanceof endpoint_1.BaseApiEndpoint) {
|
|
43
|
+
const path = instance.path;
|
|
44
|
+
if (!pathMethods.has(path)) {
|
|
45
|
+
pathMethods.set(path, new Set());
|
|
46
|
+
}
|
|
47
|
+
pathMethods.get(path).add(instance.method);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Second pass: add 405 handlers for unsupported methods
|
|
51
|
+
const allMethods = Object.values(endpoint_1.EndpointMethod);
|
|
52
|
+
pathMethods.forEach((supportedMethods, path) => {
|
|
53
|
+
allMethods.forEach((method) => {
|
|
54
|
+
if (!supportedMethods.has(method)) {
|
|
55
|
+
this.router[method](path, (req, res) => {
|
|
56
|
+
res.status(405).send({
|
|
57
|
+
error: 'Method Not Allowed',
|
|
58
|
+
message: `Method ${req.method} not allowed`,
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
exports.BaseApiRouter = BaseApiRouter;
|
|
67
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../../src/router/router.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ObjectSanitizer } from 'valsan';
|
|
2
|
+
import { ApiRequest, BaseApiEndpoint } from './endpoint';
|
|
3
|
+
/**
|
|
4
|
+
* Runs a valsan ObjectSanitizer on a value,
|
|
5
|
+
* throws with error details if validation fails.
|
|
6
|
+
*/
|
|
7
|
+
export declare function runSanitizer(sanitizer: ObjectSanitizer, value: any): Promise<Record<string, unknown> | undefined>;
|
|
8
|
+
/**
|
|
9
|
+
* Validates and sanitizes request parts
|
|
10
|
+
* (body, query, params, headers) if the
|
|
11
|
+
* endpoint defines a ObjectSanitizers
|
|
12
|
+
*/
|
|
13
|
+
export declare function validateRequest(endpoint: BaseApiEndpoint, request: ApiRequest): Promise<void>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateRequest = exports.runSanitizer = void 0;
|
|
4
|
+
const error_1 = require("../error");
|
|
5
|
+
/**
|
|
6
|
+
* Runs a valsan ObjectSanitizer on a value,
|
|
7
|
+
* throws with error details if validation fails.
|
|
8
|
+
*/
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
|
+
async function runSanitizer(sanitizer, value) {
|
|
11
|
+
const result = await sanitizer.run(value);
|
|
12
|
+
if (!result.success) {
|
|
13
|
+
throw new error_1.UnprocessableEntityError('Validation failed', {
|
|
14
|
+
details: result.errors,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return result.data;
|
|
18
|
+
}
|
|
19
|
+
exports.runSanitizer = runSanitizer;
|
|
20
|
+
/**
|
|
21
|
+
* Validates and sanitizes request parts
|
|
22
|
+
* (body, query, params, headers) if the
|
|
23
|
+
* endpoint defines a ObjectSanitizers
|
|
24
|
+
*/
|
|
25
|
+
async function validateRequest(endpoint, request) {
|
|
26
|
+
for (const part of ['body', 'query', 'params', 'headers']) {
|
|
27
|
+
const sanitizer = endpoint[part];
|
|
28
|
+
if (!sanitizer) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const sanitized = await runSanitizer(sanitizer, request[part]);
|
|
32
|
+
if (part === 'query') {
|
|
33
|
+
// Mutate the query object instead of reassigning
|
|
34
|
+
Object.keys(request.query).forEach((key) => {
|
|
35
|
+
delete request.query[key];
|
|
36
|
+
});
|
|
37
|
+
Object.assign(request.query, sanitized);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
request[part] = sanitized;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.validateRequest = validateRequest;
|
|
45
|
+
//# sourceMappingURL=validation-middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation-middleware.js","sourceRoot":"","sources":["../../../src/router/validation-middleware.ts"],"names":[],"mappings":";;;AAEA,oCAAoD;AAEpD;;;GAGG;AACH,8DAA8D;AACvD,KAAK,UAAU,YAAY,CAAC,SAA0B,EAAE,KAAU;IACxE,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAE1C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,IAAI,gCAAwB,CAAC,mBAAmB,EAAE;YACvD,OAAO,EAAE,MAAM,CAAC,MAAM;SACtB,CAAC,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC;AACpB,CAAC;AAVD,oCAUC;AAED;;;;GAIG;AACI,KAAK,UAAU,eAAe,CACpC,QAAyB,EACzB,OAAmB;IAEnB,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAU,EAAE,CAAC;QACpE,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAEjC,IAAI,CAAC,SAAS,EAAE,CAAC;YAChB,SAAS;QACV,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAE/D,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YACtB,iDAAiD;YACjD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBAC1C,OAAO,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC3B,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QACzC,CAAC;aACI,CAAC;YACL,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC;QAC3B,CAAC;IACF,CAAC;AACF,CAAC;AAxBD,0CAwBC"}
|
package/server/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultRestServerOptions = exports.RestServer = void 0;
|
|
4
|
+
var server_1 = require("./server");
|
|
5
|
+
Object.defineProperty(exports, "RestServer", { enumerable: true, get: function () { return server_1.RestServer; } });
|
|
6
|
+
var server_options_1 = require("./server-options");
|
|
7
|
+
Object.defineProperty(exports, "defaultRestServerOptions", { enumerable: true, get: function () { return server_options_1.defaultRestServerOptions; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/server/index.ts"],"names":[],"mappings":";;;AAAA,mCAAsC;AAA7B,oGAAA,UAAU,OAAA;AACnB,mDAA+E;AAAnD,0HAAA,wBAAwB,OAAA"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { LogInterface } from '../log';
|
|
2
|
+
import { AuthenticationScheme } from '../authentication/authentication-scheme';
|
|
3
|
+
export interface SecurityHeadersOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Disable the X-Powered-By header to prevent server fingerprinting
|
|
6
|
+
* @default true
|
|
7
|
+
*/
|
|
8
|
+
disableXPoweredBy: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Set X-Content-Type-Options: nosniff to prevent MIME type sniffing
|
|
11
|
+
* @default true
|
|
12
|
+
*/
|
|
13
|
+
noSniff: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Set X-Frame-Options header to prevent clickjacking
|
|
16
|
+
* Options: 'DENY', 'SAMEORIGIN', or false to disable
|
|
17
|
+
* @default 'DENY'
|
|
18
|
+
*/
|
|
19
|
+
frameOptions: 'DENY' | 'SAMEORIGIN' | false;
|
|
20
|
+
/**
|
|
21
|
+
* Set X-XSS-Protection header for legacy browser protection
|
|
22
|
+
* @default true
|
|
23
|
+
*/
|
|
24
|
+
xssProtection: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Set Strict-Transport-Security header (only use with HTTPS)
|
|
27
|
+
* Provide max-age value or false to disable
|
|
28
|
+
* @default false
|
|
29
|
+
*/
|
|
30
|
+
hsts: number | false;
|
|
31
|
+
}
|
|
32
|
+
export interface RestServerOptions {
|
|
33
|
+
port: number;
|
|
34
|
+
maxPayloadSizeMB: number;
|
|
35
|
+
maxUrlEncodedSizeMB: number;
|
|
36
|
+
log: LogInterface;
|
|
37
|
+
securityHeaders: SecurityHeadersOptions;
|
|
38
|
+
swaggerEnabled?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Server-level authentication scheme
|
|
41
|
+
* This will be applied to all routers and endpoints unless overridden
|
|
42
|
+
*/
|
|
43
|
+
authentication?: AuthenticationScheme;
|
|
44
|
+
}
|
|
45
|
+
export declare const defaultSecurityHeadersOptions: SecurityHeadersOptions;
|
|
46
|
+
export declare const defaultRestServerOptions: RestServerOptions;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultRestServerOptions = exports.defaultSecurityHeadersOptions = void 0;
|
|
4
|
+
exports.defaultSecurityHeadersOptions = {
|
|
5
|
+
disableXPoweredBy: true,
|
|
6
|
+
noSniff: true,
|
|
7
|
+
frameOptions: 'DENY',
|
|
8
|
+
xssProtection: true,
|
|
9
|
+
hsts: false, // Disabled by default, enable when using HTTPS
|
|
10
|
+
};
|
|
11
|
+
exports.defaultRestServerOptions = {
|
|
12
|
+
port: 5000,
|
|
13
|
+
maxPayloadSizeMB: 10,
|
|
14
|
+
maxUrlEncodedSizeMB: 1,
|
|
15
|
+
log: {
|
|
16
|
+
...console,
|
|
17
|
+
// eslint-disable-next-line no-console
|
|
18
|
+
fatal: console.error,
|
|
19
|
+
// eslint-disable-next-line no-console
|
|
20
|
+
info: console.log,
|
|
21
|
+
},
|
|
22
|
+
securityHeaders: exports.defaultSecurityHeadersOptions,
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=server-options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-options.js","sourceRoot":"","sources":["../../../src/server/server-options.ts"],"names":[],"mappings":";;;AAoDa,QAAA,6BAA6B,GAA2B;IACpE,iBAAiB,EAAE,IAAI;IACvB,OAAO,EAAE,IAAI;IACb,YAAY,EAAE,MAAM;IACpB,aAAa,EAAE,IAAI;IACnB,IAAI,EAAE,KAAK,EAAE,+CAA+C;CAC5D,CAAC;AAEW,QAAA,wBAAwB,GAAsB;IAC1D,IAAI,EAAE,IAAI;IACV,gBAAgB,EAAE,EAAE;IACpB,mBAAmB,EAAE,CAAC;IACtB,GAAG,EAAE;QACJ,GAAG,OAAO;QACV,sCAAsC;QACtC,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,sCAAsC;QACtC,IAAI,EAAE,OAAO,CAAC,GAAG;KACjB;IACD,eAAe,EAAE,qCAA6B;CAC9C,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import http from 'http';
|
|
4
|
+
import { RestServerOptions } from './server-options';
|
|
5
|
+
import { ApiRouter, BaseApiRouter } from '../router';
|
|
6
|
+
import { AuthenticationScheme } from '../authentication/authentication-scheme';
|
|
7
|
+
import { LogInterface } from '../log';
|
|
8
|
+
export declare abstract class RestServer {
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
version: string;
|
|
12
|
+
router: ApiRouter;
|
|
13
|
+
routerInstance: BaseApiRouter;
|
|
14
|
+
readonly port: number;
|
|
15
|
+
readonly maxPayloadSizeMB: number;
|
|
16
|
+
readonly maxUrlEncodedSizeMB: number;
|
|
17
|
+
readonly securityHeaders: RestServerOptions['securityHeaders'];
|
|
18
|
+
swaggerEnabled: boolean;
|
|
19
|
+
authentication?: AuthenticationScheme;
|
|
20
|
+
protected app: express.Express;
|
|
21
|
+
protected listener: http.Server;
|
|
22
|
+
protected log: LogInterface;
|
|
23
|
+
constructor(options: Partial<RestServerOptions>);
|
|
24
|
+
start(): Promise<void>;
|
|
25
|
+
stop(): Promise<void>;
|
|
26
|
+
protected createRouter(): Promise<void>;
|
|
27
|
+
protected registerAuthentication(): Promise<void>;
|
|
28
|
+
protected registerRoutes(): Promise<void>;
|
|
29
|
+
protected registerSwagger(): Promise<void>;
|
|
30
|
+
protected setupExpress(): Promise<void>;
|
|
31
|
+
protected setupSecurityHeaders(): Promise<void>;
|
|
32
|
+
protected setupExpressCors(): Promise<void>;
|
|
33
|
+
protected setupExpressJson(): Promise<void>;
|
|
34
|
+
protected setupExpressUrlEncoded(): Promise<void>;
|
|
35
|
+
protected setup404Handler(): Promise<void>;
|
|
36
|
+
protected setupErrorHandler(): Promise<void>;
|
|
37
|
+
protected startListening(): Promise<void>;
|
|
38
|
+
}
|