@lucaapp/service-utils 1.7.0 → 1.9.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 +2 -0
- package/dist/index.js +2 -0
- package/dist/lib/kafka/events/wsEvent.d.ts +1 -0
- package/dist/lib/lifecycle/index.d.ts +17 -0
- package/dist/lib/lifecycle/index.js +54 -0
- package/dist/lib/lifecycle/sleep.d.ts +3 -0
- package/dist/lib/lifecycle/sleep.js +13 -0
- package/dist/lib/logger/index.d.ts +6 -0
- package/dist/lib/logger/index.js +89 -0
- package/dist/lib/logger/utils.d.ts +9 -0
- package/dist/lib/logger/utils.js +2 -0
- package/dist/lib/serviceIdentity/service.d.ts +2 -0
- package/dist/lib/serviceIdentity/service.js +2 -0
- package/dist/lib/wsEvent/index.d.ts +1 -1
- package/dist/lib/wsEvent/index.js +2 -1
- package/package.json +5 -1
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -18,3 +18,5 @@ __exportStar(require("./lib/kafka"), exports);
|
|
|
18
18
|
__exportStar(require("./lib/serviceIdentity"), exports);
|
|
19
19
|
__exportStar(require("./lib/metrics"), exports);
|
|
20
20
|
__exportStar(require("./lib/wsEvent"), exports);
|
|
21
|
+
__exportStar(require("./lib/lifecycle"), exports);
|
|
22
|
+
__exportStar(require("./lib/logger"), exports);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Logger, LoggerOptions } from 'pino';
|
|
2
|
+
declare class Lifecycle {
|
|
3
|
+
state: {
|
|
4
|
+
isShuttingDown: boolean;
|
|
5
|
+
};
|
|
6
|
+
private readonly shutdownDelay;
|
|
7
|
+
private readonly logger;
|
|
8
|
+
constructor(shutdownDelay: number, logger: Logger<LoggerOptions>);
|
|
9
|
+
shutdownHandlers: Array<() => void>;
|
|
10
|
+
gracefulShutdown: (isImmediate?: boolean) => Promise<void>;
|
|
11
|
+
private sigtermHandler;
|
|
12
|
+
unhandledRejectionHandler: (error: unknown) => void;
|
|
13
|
+
uncaughtExceptionHandler: (error: unknown) => void;
|
|
14
|
+
registerShutdownHandler: (shutdownHandler: () => void) => void;
|
|
15
|
+
registerHooks: () => void;
|
|
16
|
+
}
|
|
17
|
+
export { Lifecycle };
|
|
@@ -0,0 +1,54 @@
|
|
|
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.Lifecycle = void 0;
|
|
7
|
+
const moment_1 = __importDefault(require("moment"));
|
|
8
|
+
const sleep_1 = require("./sleep");
|
|
9
|
+
class Lifecycle {
|
|
10
|
+
constructor(shutdownDelay, logger) {
|
|
11
|
+
this.state = {
|
|
12
|
+
isShuttingDown: false,
|
|
13
|
+
};
|
|
14
|
+
this.shutdownHandlers = [];
|
|
15
|
+
this.gracefulShutdown = async (isImmediate = false) => {
|
|
16
|
+
if (this.state.isShuttingDown)
|
|
17
|
+
return;
|
|
18
|
+
this.state.isShuttingDown = true;
|
|
19
|
+
if (!isImmediate) {
|
|
20
|
+
this.logger.info(`shutting down in ${this.shutdownDelay.as('seconds')}s.`);
|
|
21
|
+
await (0, sleep_1.sleep)(this.shutdownDelay.as('milliseconds'));
|
|
22
|
+
}
|
|
23
|
+
this.logger.info('starting shutdown');
|
|
24
|
+
for (const shutdownHandler of this.shutdownHandlers) {
|
|
25
|
+
shutdownHandler();
|
|
26
|
+
}
|
|
27
|
+
this.logger.info('shutdown complete');
|
|
28
|
+
};
|
|
29
|
+
this.sigtermHandler = async () => {
|
|
30
|
+
this.logger.info('SIGTERM received.');
|
|
31
|
+
await this.gracefulShutdown();
|
|
32
|
+
process.exit(0);
|
|
33
|
+
};
|
|
34
|
+
this.unhandledRejectionHandler = (error) => {
|
|
35
|
+
this.logger.error(error, 'unhandledRejection');
|
|
36
|
+
process.exit(1);
|
|
37
|
+
};
|
|
38
|
+
this.uncaughtExceptionHandler = (error) => {
|
|
39
|
+
this.logger.error(error, 'uncaughtException');
|
|
40
|
+
process.exit(1);
|
|
41
|
+
};
|
|
42
|
+
this.registerShutdownHandler = (shutdownHandler) => {
|
|
43
|
+
this.shutdownHandlers.push(shutdownHandler);
|
|
44
|
+
};
|
|
45
|
+
this.registerHooks = () => {
|
|
46
|
+
process.on('SIGTERM', this.sigtermHandler);
|
|
47
|
+
process.on('uncaughtException', this.uncaughtExceptionHandler);
|
|
48
|
+
process.on('unhandledRejection', this.unhandledRejectionHandler);
|
|
49
|
+
};
|
|
50
|
+
this.shutdownDelay = moment_1.default.duration(shutdownDelay, 'seconds');
|
|
51
|
+
this.logger = logger;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.Lifecycle = Lifecycle;
|
|
@@ -0,0 +1,13 @@
|
|
|
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.randomSleep = exports.sleep = void 0;
|
|
7
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
8
|
+
const util_1 = require("util");
|
|
9
|
+
const setTimeoutPromise = (0, util_1.promisify)(setTimeout);
|
|
10
|
+
const sleep = (msToSleep) => setTimeoutPromise(msToSleep);
|
|
11
|
+
exports.sleep = sleep;
|
|
12
|
+
const randomSleep = () => setTimeoutPromise(crypto_1.default.randomInt(100, 500));
|
|
13
|
+
exports.randomSleep = randomSleep;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Logger, LoggerOptions } from 'pino';
|
|
2
|
+
import { HttpLoggerCreationOptions } from './utils';
|
|
3
|
+
export declare class LoggerFactory {
|
|
4
|
+
static getLogger(logLevel: string): Logger<LoggerOptions>;
|
|
5
|
+
static getHttpLogger(options: HttpLoggerCreationOptions): import("pino-http").HttpLogger;
|
|
6
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
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.LoggerFactory = void 0;
|
|
7
|
+
const pino_1 = __importDefault(require("pino"));
|
|
8
|
+
const pino_http_1 = __importDefault(require("pino-http"));
|
|
9
|
+
const pick_1 = __importDefault(require("lodash/pick"));
|
|
10
|
+
const uuid_1 = require("uuid");
|
|
11
|
+
class LoggerFactory {
|
|
12
|
+
static getLogger(logLevel) {
|
|
13
|
+
return (0, pino_1.default)({ level: logLevel });
|
|
14
|
+
}
|
|
15
|
+
static getHttpLogger(options) {
|
|
16
|
+
const { requestSerializer, responseSerializer, errorSerializer, defaultHttpLogLevel, customMessage, } = new HttpLoggerHelpers(options);
|
|
17
|
+
const logger = this.getLogger(options.logLevel);
|
|
18
|
+
return (0, pino_http_1.default)({
|
|
19
|
+
logger: logger,
|
|
20
|
+
serializers: {
|
|
21
|
+
req: requestSerializer,
|
|
22
|
+
res: responseSerializer,
|
|
23
|
+
err: errorSerializer,
|
|
24
|
+
},
|
|
25
|
+
customLogLevel: (response, error) => {
|
|
26
|
+
if (response.statusCode >= 400 && response.statusCode < 500)
|
|
27
|
+
return 'warn';
|
|
28
|
+
if (response.statusCode >= 500 || error)
|
|
29
|
+
return 'error';
|
|
30
|
+
return defaultHttpLogLevel;
|
|
31
|
+
},
|
|
32
|
+
customSuccessMessage: customMessage,
|
|
33
|
+
customErrorMessage: (_, response) => customMessage(response),
|
|
34
|
+
genReqId: () => (0, uuid_1.v4)(),
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.LoggerFactory = LoggerFactory;
|
|
39
|
+
class HttpLoggerHelpers {
|
|
40
|
+
constructor({ debug, e2e, defaultHttpLogLevel }) {
|
|
41
|
+
this.requestSerializer = (request) => {
|
|
42
|
+
if (this.debug || this.e2e)
|
|
43
|
+
return request;
|
|
44
|
+
request.headers = (0, pick_1.default)(request.headers, [
|
|
45
|
+
'connection',
|
|
46
|
+
'host',
|
|
47
|
+
'origin',
|
|
48
|
+
'x-real-ip',
|
|
49
|
+
'x-forwarded-for',
|
|
50
|
+
'x-forwarded-proto',
|
|
51
|
+
'x-forwarded-host',
|
|
52
|
+
'x-forwarded-port',
|
|
53
|
+
'x-scheme',
|
|
54
|
+
'user-agent',
|
|
55
|
+
'content-type',
|
|
56
|
+
'accept',
|
|
57
|
+
'referer',
|
|
58
|
+
'accept-encoding',
|
|
59
|
+
'ssl-client-subject-dn',
|
|
60
|
+
]);
|
|
61
|
+
return request;
|
|
62
|
+
};
|
|
63
|
+
this.responseSerializer = (response) => {
|
|
64
|
+
if (this.debug)
|
|
65
|
+
return response;
|
|
66
|
+
response.headers = (0, pick_1.default)(response.headers, [
|
|
67
|
+
'content-type',
|
|
68
|
+
'content-length',
|
|
69
|
+
]);
|
|
70
|
+
return response;
|
|
71
|
+
};
|
|
72
|
+
this.errorSerializer = (error) => {
|
|
73
|
+
if (error?.parameters)
|
|
74
|
+
error.parameters = undefined;
|
|
75
|
+
if (error?.parent?.parameters)
|
|
76
|
+
error.parent.parameters = undefined;
|
|
77
|
+
if (error?.original?.parameters)
|
|
78
|
+
error.original.parameters = undefined;
|
|
79
|
+
return error;
|
|
80
|
+
};
|
|
81
|
+
this.customMessage = (response) => {
|
|
82
|
+
const { req: { method, originalUrl }, statusCode, } = response;
|
|
83
|
+
return `${statusCode} ${method} ${originalUrl}`;
|
|
84
|
+
};
|
|
85
|
+
this.debug = !!debug;
|
|
86
|
+
this.e2e = !!e2e;
|
|
87
|
+
this.defaultHttpLogLevel = defaultHttpLogLevel || 'info';
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -6,6 +6,8 @@ var Service;
|
|
|
6
6
|
Service["BACKEND"] = "backend";
|
|
7
7
|
Service["BACKEND_PAY"] = "backend-pay";
|
|
8
8
|
Service["BACKEND_POS"] = "backend-pos";
|
|
9
|
+
Service["BACKEND_ID"] = "backend-id";
|
|
10
|
+
Service["BACKEND_ATTESTATION"] = "backend-attestation";
|
|
9
11
|
Service["BACKEND_PUBSUB"] = "backend-pubsub";
|
|
10
12
|
})(Service || (Service = {}));
|
|
11
13
|
exports.Service = Service;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { KafkaClient } from '../kafka';
|
|
2
2
|
declare const generateSubscriptionId: () => string;
|
|
3
|
-
declare const emitWebsocketEvent: (kafkaClient: KafkaClient, subId: string, data: any) => Promise<void>;
|
|
3
|
+
declare const emitWebsocketEvent: (kafkaClient: KafkaClient, subId: string, type: string, data: any) => Promise<void>;
|
|
4
4
|
export { generateSubscriptionId, emitWebsocketEvent };
|
|
@@ -7,7 +7,7 @@ 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, data) => {
|
|
10
|
+
const emitWebsocketEvent = async (kafkaClient, subId, type, data) => {
|
|
11
11
|
const issuer = kafkaClient.serviceIdentity.identityName;
|
|
12
12
|
// using WS_EVENT_backend since all WS_EVENTs use same schema
|
|
13
13
|
const topic = `wsevent_${issuer}`;
|
|
@@ -16,6 +16,7 @@ const emitWebsocketEvent = async (kafkaClient, subId, data) => {
|
|
|
16
16
|
type: 'create',
|
|
17
17
|
entity: {
|
|
18
18
|
subId,
|
|
19
|
+
type,
|
|
19
20
|
data,
|
|
20
21
|
},
|
|
21
22
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lucaapp/service-utils",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/express": "4.17.13",
|
|
22
22
|
"@types/jest": "^28.1.5",
|
|
23
|
+
"@types/lodash": "^4.14.187",
|
|
23
24
|
"@types/uuid": "^8.3.4",
|
|
24
25
|
"@typescript-eslint/eslint-plugin": "^5.30.6",
|
|
25
26
|
"@typescript-eslint/parser": "^5.30.6",
|
|
@@ -40,7 +41,10 @@
|
|
|
40
41
|
"axios": "^0.27.2",
|
|
41
42
|
"jose": "4.9.2",
|
|
42
43
|
"kafkajs": "2.1.0",
|
|
44
|
+
"lodash": "^4.17.21",
|
|
43
45
|
"moment": "^2.29.4",
|
|
46
|
+
"pino": "7.10.0",
|
|
47
|
+
"pino-http": "6.6.0",
|
|
44
48
|
"prom-client": "14.1.0",
|
|
45
49
|
"uuid": "^9.0.0"
|
|
46
50
|
}
|