xpref 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.
Files changed (61) hide show
  1. package/api-docs/body-schema.d.ts +1 -0
  2. package/api-docs/body-schema.js +31 -0
  3. package/api-docs/index.d.ts +3 -0
  4. package/api-docs/index.js +49 -0
  5. package/api-docs/parameter-schema.d.ts +1 -0
  6. package/api-docs/parameter-schema.js +57 -0
  7. package/api-docs/path-schema.d.ts +1 -0
  8. package/api-docs/path-schema.js +31 -0
  9. package/api-docs/path.d.ts +2 -0
  10. package/api-docs/path.js +79 -0
  11. package/api-docs/schema.d.ts +1 -0
  12. package/api-docs/schema.js +42 -0
  13. package/api-docs/security.d.ts +1 -0
  14. package/api-docs/security.js +48 -0
  15. package/api-docs/types.d.ts +27 -0
  16. package/api-docs/types.js +2 -0
  17. package/debug.d.ts +6 -0
  18. package/debug.js +26 -0
  19. package/i18n/index.d.ts +9 -0
  20. package/i18n/index.js +51 -0
  21. package/idempotency/index.d.ts +7 -0
  22. package/idempotency/index.js +130 -0
  23. package/idempotency/storage.d.ts +36 -0
  24. package/idempotency/storage.js +54 -0
  25. package/index.d.ts +7 -0
  26. package/index.js +126 -0
  27. package/package.json +36 -0
  28. package/request-forwarder/common.d.ts +11 -0
  29. package/request-forwarder/common.js +36 -0
  30. package/request-forwarder/forwarder.d.ts +2 -0
  31. package/request-forwarder/forwarder.js +81 -0
  32. package/request-forwarder/index.d.ts +2 -0
  33. package/request-forwarder/index.js +10 -0
  34. package/request-forwarder/pass-to-next.d.ts +4 -0
  35. package/request-forwarder/pass-to-next.js +48 -0
  36. package/request-forwarder/proxy.d.ts +8 -0
  37. package/request-forwarder/proxy.js +34 -0
  38. package/request-id.d.ts +7 -0
  39. package/request-id.js +19 -0
  40. package/request-log.d.ts +3 -0
  41. package/request-log.js +88 -0
  42. package/router.d.ts +13 -0
  43. package/router.js +65 -0
  44. package/setting/index.d.ts +1 -0
  45. package/setting/index.js +6 -0
  46. package/static.d.ts +2 -0
  47. package/static.js +12 -0
  48. package/types.d.ts +52 -0
  49. package/types.js +2 -0
  50. package/utils.d.ts +5 -0
  51. package/utils.js +22 -0
  52. package/validator/method-validator.d.ts +6 -0
  53. package/validator/method-validator.js +45 -0
  54. package/validator/route-schema.d.ts +2 -0
  55. package/validator/route-schema.js +71 -0
  56. package/validator/schema.d.ts +15 -0
  57. package/validator/schema.js +63 -0
  58. package/validator/validate.d.ts +8 -0
  59. package/validator/validate.js +94 -0
  60. package/validator/validator.test.d.ts +0 -0
  61. package/validator/validator.test.js +6 -0
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deleteItem = exports.store = exports.getItem = exports.create = exports.exists = exports.getAll = exports.status = void 0;
4
+ const storage = {};
5
+ exports.status = {
6
+ IN_PROGERSS: 'in-progress',
7
+ DONE: 'done',
8
+ };
9
+ const getAll = () => storage;
10
+ exports.getAll = getAll;
11
+ const exists = (key) => !!(storage[key] || false);
12
+ exports.exists = exists;
13
+ /**
14
+ * Creates the storage with minimal information (the predetermined default value)
15
+ * @param {string} key - The key to be added into storage.
16
+ */
17
+ const create = (key) => {
18
+ if ((0, exports.exists)(key))
19
+ throw new Error('Idempotency key exists.');
20
+ storage[key] = {
21
+ createdAt: new Date(),
22
+ status: exports.status.IN_PROGERSS,
23
+ };
24
+ };
25
+ exports.create = create;
26
+ /**
27
+ * Gets the stored item by key
28
+ * @param {string} key - Storage key
29
+ * @return object;
30
+ */
31
+ const getItem = (key) => storage[key] || {};
32
+ exports.getItem = getItem;
33
+ /**
34
+ * Stores the response object to be used when passing the stored
35
+ * result back to the client. This make sure the previouse response
36
+ * (stored response) is sent back.
37
+ * @param {string} key - The key of the storage
38
+ * @param {Response} response - The response information
39
+ */
40
+ const store = (key, response) => {
41
+ const item = (0, exports.getItem)(key);
42
+ storage[key] = {
43
+ ...item,
44
+ response,
45
+ status: exports.status.DONE,
46
+ };
47
+ };
48
+ exports.store = store;
49
+ const deleteItem = (key) => {
50
+ if ((0, exports.exists)(key)) {
51
+ delete storage[key];
52
+ }
53
+ };
54
+ exports.deleteItem = deleteItem;
package/index.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import type { API } from './types';
2
+ import { getReqId } from './request-log';
3
+ export default function api(pProps: API, tried?: number): any;
4
+ export { urlencoded, type Request, type Response, type NextFunction, type Application, } from 'express';
5
+ export declare const getRequestId: typeof getReqId;
6
+ export * from './types';
7
+ export { default as i18n } from './i18n';
package/index.js ADDED
@@ -0,0 +1,126 @@
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
36
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
37
+ };
38
+ var __importDefault = (this && this.__importDefault) || function (mod) {
39
+ return (mod && mod.__esModule) ? mod : { "default": mod };
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.i18n = exports.getRequestId = exports.urlencoded = void 0;
43
+ exports.default = api;
44
+ /* eslint-disable no-console */
45
+ const express_1 = __importStar(require("express"));
46
+ const cors_1 = __importDefault(require("cors"));
47
+ const helmet_1 = __importDefault(require("helmet"));
48
+ const router_1 = __importDefault(require("./router"));
49
+ const static_1 = __importDefault(require("./static"));
50
+ const request_log_1 = __importStar(require("./request-log"));
51
+ const request_id_1 = __importDefault(require("./request-id"));
52
+ const method_validator_1 = __importDefault(require("./validator/method-validator"));
53
+ const getProps = (pProps) => ({
54
+ port: 3000,
55
+ ...pProps,
56
+ });
57
+ const showAppInfo = (props) => {
58
+ const { name, env, port } = props;
59
+ const msg = [
60
+ '------------ API Started ----------',
61
+ ` Name: ${name}`,
62
+ ` Env: ${env}`,
63
+ ` Port: ${port}`,
64
+ '------------------------------------',
65
+ ].join('\n');
66
+ console.log(msg);
67
+ };
68
+ /*
69
+ const startApp = (
70
+ app: Application,
71
+ port: any,
72
+ routes: any,
73
+ ): Promise<any> => new Promise((resolve) => {
74
+
75
+ app.listen(port, () => {
76
+ resolve({ port });
77
+ }).on('error', (error: any) => {
78
+ const { code } = error;
79
+ if (code === 'EADDRINUSE') startApp(app, parseInt(port, 10) + 1, routes);
80
+ });
81
+ });
82
+ */
83
+ function api(pProps, tried = 0) {
84
+ const { appName, appEnv, routes, port, manuallyStart, schemas = {}, staticRoutes = {}, onInit = false, interceptor = false, logger = false, } = getProps(pProps);
85
+ const app = (0, express_1.default)();
86
+ if (onInit)
87
+ onInit(app);
88
+ app.use((0, cors_1.default)());
89
+ app.use((0, helmet_1.default)());
90
+ app.use((0, express_1.json)({ limit: '8mb' }));
91
+ app.use((0, express_1.urlencoded)({ extended: true }));
92
+ app.set('trust proxy', true);
93
+ if (interceptor)
94
+ interceptor(app);
95
+ app.use((0, request_id_1.default)());
96
+ app.use((0, request_log_1.default)(logger, { appName, appEnv }));
97
+ (0, static_1.default)(app, staticRoutes);
98
+ const validator = (0, method_validator_1.default)(schemas);
99
+ (0, router_1.default)(app, routes, { validator });
100
+ const startManually = manuallyStart || false;
101
+ if (startManually) {
102
+ return Promise.resolve(startManually({
103
+ app,
104
+ port,
105
+ }));
106
+ }
107
+ const thePort = Number(port) + tried;
108
+ return new Promise((resolve) => {
109
+ console.log(`[INFO] Starting application on port ${thePort}`);
110
+ app.listen(thePort, () => {
111
+ showAppInfo({ name: appName, env: appEnv, port });
112
+ resolve({ port: thePort, app });
113
+ }).on('error', (error) => {
114
+ const { code } = error;
115
+ console.log(`[Info] Port ${thePort} already in used...`);
116
+ if (code === 'EADDRINUSE')
117
+ resolve(api(pProps, tried + 1));
118
+ });
119
+ });
120
+ }
121
+ var express_2 = require("express");
122
+ Object.defineProperty(exports, "urlencoded", { enumerable: true, get: function () { return express_2.urlencoded; } });
123
+ exports.getRequestId = request_log_1.getReqId;
124
+ __exportStar(require("./types"), exports);
125
+ var i18n_1 = require("./i18n");
126
+ Object.defineProperty(exports, "i18n", { enumerable: true, get: function () { return __importDefault(i18n_1).default; } });
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "xpref",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "build": "tsc --build -f ./tsconfig.json",
8
+ "start:dev": "tsc --build -f ./tsconfig.json -w",
9
+ "test": "jest --detectOpenHandles --forceExit",
10
+ "test:dev": "npm run test -- --watchAll",
11
+ "jsdoc": "tsc && jsdoc build/**/* -d jsdoc",
12
+ "eslint": "eslint src --ext .ts"
13
+ },
14
+ "author": "",
15
+ "license": "ISC",
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "sideEffects": false,
20
+ "dependencies": {
21
+ "ajv": "^8.17.1",
22
+ "ajv-errors": "^3.0.0",
23
+ "cors": "^2.8.5",
24
+ "express": "^5.1.0",
25
+ "helmet": "^8.1.0",
26
+ "morgan": "^1.10.0",
27
+ "swagger-ui-express": "^5.0.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/ajv": "^0.0.5",
31
+ "@types/cors": "^2.8.12",
32
+ "@types/express": "^5.0.1",
33
+ "@types/morgan": "^1.9.3",
34
+ "@types/swagger-ui-express": "^4.1.3"
35
+ }
36
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Request forwarder is to forwards the traffic to any defined
3
+ * host/server. As the request is forwarded to specific host
4
+ * server, so noly hostname or server ip address is defined
5
+ * with it's prototol (http or https).
6
+ */
7
+ import http from 'http';
8
+ import https from 'https';
9
+ export declare const getRequestHandler: (host: string) => typeof http | typeof https;
10
+ export declare const onError: (error: any) => void;
11
+ export declare const getUrl: (req: any, props: any) => any;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ /**
3
+ * Request forwarder is to forwards the traffic to any defined
4
+ * host/server. As the request is forwarded to specific host
5
+ * server, so noly hostname or server ip address is defined
6
+ * with it's prototol (http or https).
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.getUrl = exports.onError = exports.getRequestHandler = void 0;
13
+ /* eslint-disable no-console */
14
+ const http_1 = __importDefault(require("http"));
15
+ const https_1 = __importDefault(require("https"));
16
+ const getRequestHandler = (host) => {
17
+ const protocol = new URL(host).protocol;
18
+ return protocol === 'https:' ? https_1.default : http_1.default;
19
+ };
20
+ exports.getRequestHandler = getRequestHandler;
21
+ const onError = (error) => {
22
+ const { message = 'Unknown error' } = error;
23
+ console.error(`[ERROR] Request Forwarder - ${message}`);
24
+ };
25
+ exports.onError = onError;
26
+ const getUrl = (req, props) => {
27
+ const { baseUrl, url } = req;
28
+ const cleanUrl = url === '/' ? '' : url;
29
+ const { proxyPrefix = '', withPrefix = false, host, onUrlConstructed, } = props;
30
+ const prefix = withPrefix ? baseUrl : '';
31
+ const proxyUrl = `${host}${proxyPrefix}${prefix}${cleanUrl}`;
32
+ return onUrlConstructed
33
+ ? onUrlConstructed(proxyUrl)
34
+ : proxyUrl;
35
+ };
36
+ exports.getUrl = getUrl;
@@ -0,0 +1,2 @@
1
+ import type { RequestForwarder, Response, Request, NextFunction } from '../types';
2
+ export default function requestFowarder(props: RequestForwarder): (req: Request, res: Response, next: NextFunction) => import("node:http").ClientRequest;
@@ -0,0 +1,81 @@
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.default = requestFowarder;
7
+ const node_querystring_1 = __importDefault(require("node:querystring"));
8
+ const common_1 = require("./common");
9
+ const pass_to_next_1 = require("./pass-to-next");
10
+ const getBodyData = (req) => {
11
+ const { method, body = {} } = req;
12
+ if (method.toUpperCase() === 'GET')
13
+ return JSON.stringify(body);
14
+ const reqBody = req.is('json')
15
+ ? JSON.stringify(body)
16
+ : node_querystring_1.default.stringify(body);
17
+ return reqBody;
18
+ };
19
+ const writeRequest = (client, req, bodyData) => {
20
+ const { method } = req;
21
+ if (method.toUpperCase() === 'GET')
22
+ return false;
23
+ client.write(bodyData);
24
+ return true;
25
+ };
26
+ const getHeaders = (req, props) => {
27
+ const { headers: propHeaders } = props;
28
+ const { headers = {} } = req;
29
+ const { 'content-length': _cl, ...cleanedHeaders } = headers;
30
+ const nextHeaders = {
31
+ 'forwarded-from': req.headers['host'],
32
+ 'forwarded-fequest-id': req.headers['Request-Id'] || req.headers['request-id'] || '',
33
+ ...cleanedHeaders,
34
+ ...propHeaders,
35
+ };
36
+ return nextHeaders;
37
+ };
38
+ const getRequestOptions = (req, props, bodyData) => {
39
+ const headers = getHeaders(req, props);
40
+ const { method } = req;
41
+ const touchedHeaders = method.toUpperCase() === 'GET'
42
+ ? headers
43
+ : { ...headers, 'Content-Length': Buffer.byteLength(bodyData) };
44
+ return {
45
+ method: req.method,
46
+ headers: touchedHeaders,
47
+ };
48
+ };
49
+ function requestFowarder(props) {
50
+ const { passToNext = false } = props;
51
+ return function (req, res, next) {
52
+ const url = (0, common_1.getUrl)(req, props);
53
+ const handler = (0, common_1.getRequestHandler)(url);
54
+ const bodyData = getBodyData(req);
55
+ const requestOptions = getRequestOptions(req, props, bodyData);
56
+ const proxy = handler.request(url, requestOptions, (proxyResponse) => {
57
+ if (passToNext) {
58
+ return (0, pass_to_next_1.collectProxyResult)(proxyResponse)
59
+ .then((result) => {
60
+ (0, pass_to_next_1.applyProxyResultToRequest)(req, res, result);
61
+ next();
62
+ })
63
+ .catch((error) => next(error));
64
+ }
65
+ res.writeHead(proxyResponse.statusCode, {
66
+ ...proxyResponse.headers,
67
+ 'is-proxy': true,
68
+ });
69
+ return proxyResponse.pipe(res);
70
+ });
71
+ proxy.on('error', (error) => {
72
+ if (passToNext) {
73
+ next(error);
74
+ return;
75
+ }
76
+ (0, common_1.onError)(error);
77
+ });
78
+ writeRequest(proxy, req, bodyData);
79
+ return req.pipe(proxy);
80
+ };
81
+ }
@@ -0,0 +1,2 @@
1
+ export { default as forwarder } from './forwarder';
2
+ export { default as proxy } from './proxy';
@@ -0,0 +1,10 @@
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.proxy = exports.forwarder = void 0;
7
+ var forwarder_1 = require("./forwarder");
8
+ Object.defineProperty(exports, "forwarder", { enumerable: true, get: function () { return __importDefault(forwarder_1).default; } });
9
+ var proxy_1 = require("./proxy");
10
+ Object.defineProperty(exports, "proxy", { enumerable: true, get: function () { return __importDefault(proxy_1).default; } });
@@ -0,0 +1,4 @@
1
+ import type { ProxyResult, Request, Response } from '../types';
2
+ import type { IncomingMessage } from 'http';
3
+ export declare const applyProxyResultToRequest: (req: Request, res: Response, result: ProxyResult) => void;
4
+ export declare const collectProxyResult: (proxyResponse: IncomingMessage) => Promise<ProxyResult>;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.collectProxyResult = exports.applyProxyResultToRequest = void 0;
4
+ const normalizeProxyHeaders = (headers) => (Object.entries(headers).reduce((acc, [key, value]) => {
5
+ if (value === undefined)
6
+ return acc;
7
+ const headerKey = key.toLowerCase();
8
+ const nextValue = Array.isArray(value)
9
+ ? value.map((item) => String(item))
10
+ : String(value);
11
+ return { ...acc, [headerKey]: nextValue };
12
+ }, {}));
13
+ const parseProxyBody = (body, headers) => {
14
+ const contentType = String(headers['content-type'] || '');
15
+ const isJson = contentType.includes('application/json');
16
+ if (!isJson)
17
+ return body;
18
+ try {
19
+ return JSON.parse(body.toString('utf8'));
20
+ }
21
+ catch {
22
+ return body.toString('utf8');
23
+ }
24
+ };
25
+ const applyProxyResultToRequest = (req, res, result) => {
26
+ const upstreamHeaders = normalizeProxyHeaders(result.headers);
27
+ req.body = parseProxyBody(result.body, result.headers);
28
+ req.headers = { ...req.headers, ...upstreamHeaders };
29
+ res.statusCode = result.statusCode;
30
+ Object.entries(upstreamHeaders).forEach(([key, value]) => {
31
+ res.setHeader(key, value);
32
+ });
33
+ };
34
+ exports.applyProxyResultToRequest = applyProxyResultToRequest;
35
+ const collectProxyResult = (proxyResponse) => {
36
+ const chunks = [];
37
+ proxyResponse.on('data', (chunk) => chunks.push(chunk));
38
+ return new Promise((resolve, reject) => {
39
+ proxyResponse.on('error', (error) => reject(error));
40
+ proxyResponse.on('aborted', () => reject(new Error('Upstream response aborted.')));
41
+ proxyResponse.on('end', () => resolve({
42
+ statusCode: proxyResponse.statusCode || 500,
43
+ headers: proxyResponse.headers,
44
+ body: Buffer.concat(chunks),
45
+ }));
46
+ });
47
+ };
48
+ exports.collectProxyResult = collectProxyResult;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Request forwarder is to forwards the traffic to any defined
3
+ * host/server. As the request is forwarded to specific host
4
+ * server, so noly hostname or server ip address is defined
5
+ * with it's prototol (http or https).
6
+ */
7
+ import type { Request, Response, RequestForwarder } from '../types';
8
+ export default function requestFowarder(props: RequestForwarder): (req: Request, res: Response) => import("node:http").ClientRequest;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = requestFowarder;
4
+ const common_1 = require("./common");
5
+ const getHeaders = (req, headers = {}) => {
6
+ const nextHeaders = {
7
+ 'forwarded-from': req.headers['host'],
8
+ 'forwarded-fequest-id': req.headers['Request-Id'] || req.headers['request-id'] || '',
9
+ ...headers,
10
+ };
11
+ return nextHeaders;
12
+ };
13
+ const getRequestOptions = (req, extraHeaders) => {
14
+ const headers = { ...extraHeaders, ...req.headers };
15
+ return { method: req.method, headers };
16
+ };
17
+ function requestFowarder(props) {
18
+ const { headers = {} } = props;
19
+ return function (req, res) {
20
+ const url = (0, common_1.getUrl)(req, props);
21
+ const extraHeaders = getHeaders(req, headers);
22
+ const handler = (0, common_1.getRequestHandler)(url);
23
+ const requestOptions = getRequestOptions(req, extraHeaders);
24
+ const proxy = handler.request(url, requestOptions, (proxyResponse) => {
25
+ res.writeHead(proxyResponse.statusCode, {
26
+ ...proxyResponse.headers,
27
+ 'is-proxy': true,
28
+ });
29
+ proxyResponse.pipe(res);
30
+ });
31
+ proxy.on('error', common_1.onError);
32
+ return req.pipe(proxy);
33
+ };
34
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The middleware is to inject the Request Id (UUID format)
3
+ * to identify the each request based on that ID.
4
+ * The process is to inject the ``Request-Id`` into the headers
5
+ * Request object, and Response object.
6
+ */
7
+ export default function requestIdMiddleware(): (req: any, res: any, next: any) => void;
package/request-id.js ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ /**
3
+ * The middleware is to inject the Request Id (UUID format)
4
+ * to identify the each request based on that ID.
5
+ * The process is to inject the ``Request-Id`` into the headers
6
+ * Request object, and Response object.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.default = requestIdMiddleware;
10
+ const crypto_1 = require("crypto");
11
+ function requestIdMiddleware() {
12
+ return (req, res, next) => {
13
+ const uuid = (0, crypto_1.randomUUID)();
14
+ const { headers } = req;
15
+ req.headers = { ...headers, 'Request-Id': uuid };
16
+ res.setHeader('request-id', uuid);
17
+ next();
18
+ };
19
+ }
@@ -0,0 +1,3 @@
1
+ import { type Request } from './index';
2
+ export declare const getReqId: (req: Request) => string | string[];
3
+ export default function loggerMiddleware(logger: any, props: any): (req: any, res: any, callback: (err?: Error) => void) => void;
package/request-log.js ADDED
@@ -0,0 +1,88 @@
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.getReqId = void 0;
7
+ exports.default = loggerMiddleware;
8
+ const morgan_1 = __importDefault(require("morgan"));
9
+ const debug_1 = __importDefault(require("./debug"));
10
+ const getReqId = (req) => {
11
+ const { headers } = req;
12
+ return headers['Request-Id'] || headers['request-id'] || 'N/A';
13
+ };
14
+ exports.getReqId = getReqId;
15
+ const getLanguage = (req) => {
16
+ const { headers } = req;
17
+ const language = headers['language'] || req.acceptsLanguages();
18
+ if (Array.isArray(language)) {
19
+ const [userLang] = language;
20
+ return userLang;
21
+ }
22
+ try {
23
+ const langData = JSON.parse(language);
24
+ const { language: lang } = langData;
25
+ return lang;
26
+ }
27
+ catch {
28
+ return language;
29
+ }
30
+ };
31
+ const getLogInfo = (req, res) => {
32
+ const reqId = (0, exports.getReqId)(req);
33
+ const { headers, method } = req;
34
+ const logInfo = {
35
+ requestId: reqId,
36
+ userAgent: headers['user-agent'],
37
+ deviceId: headers['device-id'],
38
+ country: headers['cf-ipcountry'] || headers['ipcountry'] || headers['country'] || 'N/A',
39
+ language: getLanguage(req),
40
+ origin: headers['origin'],
41
+ referer: headers['referer'],
42
+ ip: req.ip,
43
+ url: req.originalUrl,
44
+ statusCode: res.statusCode,
45
+ method,
46
+ };
47
+ if (method === 'GET')
48
+ return logInfo;
49
+ const strBody = JSON.stringify(req.body || {});
50
+ const encodedBody = Buffer.from(strBody).toString('base64');
51
+ return {
52
+ ...logInfo,
53
+ body: encodedBody,
54
+ };
55
+ };
56
+ const writeToLogger = (req, res, logger) => {
57
+ if (!(logger || false))
58
+ return false;
59
+ try {
60
+ const logInfo = getLogInfo(req, res);
61
+ logger().log(logInfo, { severity: 'request-log' });
62
+ return true;
63
+ }
64
+ catch (error) {
65
+ (0, debug_1.default)(error);
66
+ return false;
67
+ }
68
+ };
69
+ function loggerMiddleware(logger, props) {
70
+ const { appName, appEnv } = props;
71
+ return (0, morgan_1.default)((tokens, req, res) => {
72
+ const reqId = (0, exports.getReqId)(req);
73
+ const timer = setTimeout(() => {
74
+ writeToLogger(req, res, logger);
75
+ clearTimeout(timer);
76
+ }, 10);
77
+ return [
78
+ `${appName}[${appEnv}] -`,
79
+ `[${reqId}]`,
80
+ tokens.method(req, res),
81
+ tokens.status(req, res),
82
+ tokens.url(req, res),
83
+ tokens.res(req, res, 'content-length'), '-',
84
+ tokens['response-time'](req, res), 'ms',
85
+ tokens['user-agent'](req, res),
86
+ ].join(' ');
87
+ });
88
+ }
package/router.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ import { Application } from 'express';
2
+ import { Route } from './types';
3
+ type RouteOptions = {
4
+ validator: CallableFunction;
5
+ };
6
+ /**
7
+ * Registers routes configuration, the way to register routes
8
+ * is based on route base, not url base
9
+ * @param {Application} app - Express Application
10
+ * @param {Route} routes - Routes configuration
11
+ */
12
+ export default function registerRoutes(app: Application, routes: Route, options: RouteOptions): void;
13
+ export {};