@ti-engine/core 1.3.10 → 1.3.12
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 +37 -0
- package/README.md +3 -1
- package/bin/localization/labels.json +3 -0
- package/bin/start-instance.js +1 -2
- package/package.json +2 -2
- package/utils/config.js +1 -1
- package/utils/exceptions.js +1 -0
- package/utils/localization.js +41 -7
- package/utils/tools.js +39 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,26 +2,46 @@
|
|
|
2
2
|
|
|
3
3
|
This document will contain the list of changes made to the framework. The format is based on the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification.
|
|
4
4
|
|
|
5
|
+
## Version 1.3.12
|
|
6
|
+
|
|
7
|
+
* feat(exceptions): add new exception code `E_COM_SERVICE_EXEC_FAILED`
|
|
8
|
+
* feat(localization): add new public method `getAllLabels`
|
|
9
|
+
* feat(localization): use new `deepFreeze` method to freeze all label trees
|
|
10
|
+
* feat(tools): add new public method `deepFreeze` for freezing an object and all its sub-objects recursively
|
|
11
|
+
* feat(config): use new `deepFreeze` method to freeze all configuration settings
|
|
12
|
+
* docs: add more information about the `localization` module in `README.md` file
|
|
13
|
+
* build(npm): update npm dependencies to their latest versions
|
|
14
|
+
|
|
15
|
+
## Version 1.3.11
|
|
16
|
+
|
|
17
|
+
* feat(tools): add `arrayUniques` method to the tools module that helps extract only the unique array values
|
|
18
|
+
* fix(start instance): fix `undefined` instance ID in the log message about starting the instance
|
|
19
|
+
|
|
5
20
|
## Version 1.3.10
|
|
21
|
+
|
|
6
22
|
* chore: fix various minor issues reported by the linter
|
|
7
23
|
* build(npm): add more information and options to the `package.json` file
|
|
8
24
|
* docs: add some JSDoc descriptions to classes and methods
|
|
9
25
|
|
|
10
26
|
## Version 1.3.9
|
|
27
|
+
|
|
11
28
|
* feat(exceptions): add new exception code `E_GEN_NOT_INITIALIZED`
|
|
12
29
|
* docs: fix image links in the `README.md` file
|
|
13
30
|
|
|
14
31
|
## Version 1.3.8
|
|
32
|
+
|
|
15
33
|
* fix(tester): fix the relative paths of various files in the tester service. The configuration now assumes that the working directory is the root of the tester package instead of the repository itself
|
|
16
34
|
* build(npm): update npm dependencies to their latest versions
|
|
17
35
|
* docs: fix some outdated information in the `README.md` file and add some more details
|
|
18
36
|
|
|
19
37
|
## Version 1.3.7
|
|
38
|
+
|
|
20
39
|
* feat(exceptions): add new exception code `E_SEC_UNRECOGNIZED_AUTH_METHOD`
|
|
21
40
|
* fix(config): fix potential issue with `TI_GCLOUD_ENABLED` parsing as boolean
|
|
22
41
|
* docs: adjust some of the JSDoc descriptions and definitions
|
|
23
42
|
|
|
24
43
|
## Version 1.3.6
|
|
44
|
+
|
|
25
45
|
* feat(exceptions): add new exception code `E_GEN_INVALID_ARGUMENT_TYPE`
|
|
26
46
|
* feat(exceptions): add public enum with all HTTP codes exported as `httpCode` and typedef `TiHttpCode`. Use it as the type for the `httpCode` exception property
|
|
27
47
|
* feat(tools): add `description` property to enum objects
|
|
@@ -37,19 +57,23 @@ This document will contain the list of changes made to the framework. The format
|
|
|
37
57
|
* build(npm)!: bump the minimum supported Node.js version to 18.0.0
|
|
38
58
|
|
|
39
59
|
## Version 1.3.5
|
|
60
|
+
|
|
40
61
|
* fix(redis integration): fix a duplicated log entry on connection ready event if multiple observers are registered
|
|
41
62
|
* feat(service caller)!: change log level of error result in `process` method from `ERROR` to `DEBUG`. Implementers are expected to handle this and decide if the error should be propagated further or not
|
|
42
63
|
* docs: update and fix various issues with the `README.md` file
|
|
43
64
|
|
|
44
65
|
## Version 1.3.4
|
|
66
|
+
|
|
45
67
|
* fix(service instance): fix the way `ServiceConfiguration` is propagated via child classes and remove unnecessary defaults. Also update the relevant JSDoc
|
|
46
68
|
|
|
47
69
|
## Version 1.3.3
|
|
70
|
+
|
|
48
71
|
* feat(exceptions): add new parameter `includeData` to `Exception.asJSON` method which allows the exclusion of the data parameter from the returned JSON
|
|
49
72
|
* feat(exceptions): remove several excessive exception codes that were unlikely to be used
|
|
50
73
|
* fix(localization): add several missing exception labels
|
|
51
74
|
|
|
52
75
|
## Version 1.3.2
|
|
76
|
+
|
|
53
77
|
* feat(exceptions): add a set of new exception codes for the needs of any wrapping `web-server` standard communication
|
|
54
78
|
* feat(exception)!: change the default prefix path for exception labels to `system.exceptions.`
|
|
55
79
|
* feat(localization): add an Enum list of all language codes based on ISO 639-1 standard
|
|
@@ -63,6 +87,7 @@ This document will contain the list of changes made to the framework. The format
|
|
|
63
87
|
* fix(auditing): fix a potential problem with setting the log entry reporter from an ENV variable; instead, the system will now use the `ServiceInstance.instanceID` property
|
|
64
88
|
|
|
65
89
|
## Version 1.3.1
|
|
90
|
+
|
|
66
91
|
* feat(service caller): refactor the entire service call execution flow for clarity and better performance
|
|
67
92
|
* feat(service caller): create a new private class `ServiceCallProcessor` to handle individual service calls in a contained scope
|
|
68
93
|
* feat(message observer): add new property `priority` to the message observer class. It is used to determine the order in which the observers are notified about the messages
|
|
@@ -73,6 +98,7 @@ This document will contain the list of changes made to the framework. The format
|
|
|
73
98
|
* fix(redis integration): fix an issue which was setting the client status to `DISCONNECTED` during a normal shut down procedure
|
|
74
99
|
|
|
75
100
|
## Version 1.3.0
|
|
101
|
+
|
|
76
102
|
* feat(redis integration)!: change `reconnectOnError` behavior to also resubmit the failed command in case the error was of type `READONLY`
|
|
77
103
|
* feat(redis integration): improve the reliability and usage of the event notification mechanism for connection observers
|
|
78
104
|
* feat(redis integration): implement listener to the `end` event on Redis connection to capture when connection can no longer be recovered
|
|
@@ -86,25 +112,31 @@ This document will contain the list of changes made to the framework. The format
|
|
|
86
112
|
* fix(redis integration): fix broken event propagation on `disrupted` events to some connection observers
|
|
87
113
|
|
|
88
114
|
## Version 1.2.5
|
|
115
|
+
|
|
89
116
|
* feat(cache): extend method `expireValue` to work with has set fields as well
|
|
90
117
|
|
|
91
118
|
## Version 1.2.4
|
|
119
|
+
|
|
92
120
|
* feat(cache): expose the cache module as export in `package.json`
|
|
93
121
|
* feat(cache): add method `hashDeleteField` to remove a hash-set field. This implements the `hdel` Redis command
|
|
94
122
|
* fix(tools): optimize method `stringifyJSON` not to call unnecessary decycling of the value if it's not an object
|
|
95
123
|
* fix(cache): replace `hmset` with `hset` Redis command in both methods that set hash-set values. Also remove unnecessary `_.isObjectLike` call in `hashSetFields` method
|
|
96
124
|
|
|
97
125
|
## Version 1.2.3
|
|
126
|
+
|
|
98
127
|
* feat(start instance): add support for providing a custom path to the `.env` file to be used at service startup as process argument. Accepted arguments are `--env`, `--env-file`, `--dotenv`, `--dotenv-path`, and `-e`. The path itself should be relative to the working directory and should include the file name
|
|
99
128
|
|
|
100
129
|
## Version 1.2.2
|
|
130
|
+
|
|
101
131
|
* feat(start instance): change package `dotenv` to `@dotenvx/dotenvx` for loading of ENV variables. The new package supports encrypting the ENV variables. For more information see https://dotenvx.com/docs/
|
|
102
132
|
|
|
103
133
|
## Version 1.2.1
|
|
134
|
+
|
|
104
135
|
* feat(localization): add support for adding custom labels to the localization system. These have to follow the same format as the system labels
|
|
105
136
|
* docs: add section about localization to the `README.md` file
|
|
106
137
|
|
|
107
138
|
## Version 1.2.0
|
|
139
|
+
|
|
108
140
|
* feat(config)!: change the setting `localization.labelsPath` to be an array of strings. It can now be used to supply any additional custom labels in one or more files to the framework
|
|
109
141
|
* feat(message memory cache): implement graceful exception handling during shut down procedure in `receiveMessage` and `sendMessage` methods
|
|
110
142
|
* fix(default message sender): add missing initialization of the memory cache on enable
|
|
@@ -117,21 +149,25 @@ This document will contain the list of changes made to the framework. The format
|
|
|
117
149
|
* fix(service executor)!: change the individual service registration process to ensure service registration does actually happen before the service provider finishes its initialization
|
|
118
150
|
|
|
119
151
|
## Version 1.1.10
|
|
152
|
+
|
|
120
153
|
* fix(cache): fix redis client creation sequence. It is now created inside the constructor as intended. It still needs to be initialized explicitly using the `initialize` method.
|
|
121
154
|
|
|
122
155
|
## Version 1.1.9
|
|
156
|
+
|
|
123
157
|
* feat(redis integration)!: change the way the `redis` client is initialized. Instead of happening automatically on class instantiation, it is now initialized on demand using the `initialize` method.
|
|
124
158
|
* feat(cache): change the way the main cache instance is initialized in compliance with the new redis integration
|
|
125
159
|
* feat(message memory cache)!: change the way the message memory cache is initialized in compliance with the new redis integration. The `initialize` method needs to be called explicitly to initialize the cache instance before it can be used.
|
|
126
160
|
* fix(message dispatcher): fix the way the `messageExchange` is initialized in the `MessageDispatcher` class (was not returning a promise)
|
|
127
161
|
|
|
128
162
|
## Version 1.1.8
|
|
163
|
+
|
|
129
164
|
* feat(auditing): change export of the singleton class in an `instance` variable for consistency and clarity
|
|
130
165
|
* feat(message dispatcher): change export of the singleton class in an `instance` variable for consistency and clarity
|
|
131
166
|
* feat(cache): change export of the singleton class in an `instance` variable for consistency and clarity
|
|
132
167
|
* feat(service executor): implement service registration retry policy
|
|
133
168
|
|
|
134
169
|
## Version 1.1.7
|
|
170
|
+
|
|
135
171
|
* feat(start instance): add support for the detection of `SIGBREAK` events and graceful shutdown on Windows
|
|
136
172
|
* feat(service instance)!: prevent the initialization of multiple `ServiceInstance` within the same process
|
|
137
173
|
* feat(message tracer)!: covert to singleton instance and add initialization method
|
|
@@ -141,6 +177,7 @@ This document will contain the list of changes made to the framework. The format
|
|
|
141
177
|
* fix(redis integration): update links to official commands documentation
|
|
142
178
|
|
|
143
179
|
## Version 1.1.6
|
|
180
|
+
|
|
144
181
|
* feat(start instance): add fail-fast mode as default behavior on promise unhandled rejections
|
|
145
182
|
* feat(start instance): implement functionality to derive safe default service domain name when none is provided in the configuration
|
|
146
183
|
* feat(config): add support for new ENV variable `TI_FAIL_FAST_ON_UNHANDLED_OFF` that controls the fail-fast mode
|
package/README.md
CHANGED
|
@@ -544,4 +544,6 @@ The following is an example of a custom localization file. The names in brackets
|
|
|
544
544
|
}
|
|
545
545
|
```
|
|
546
546
|
|
|
547
|
-
The individual languages are specified with a two-letter code according to ISO 639-1. The default language is `en` (English). If you want to use a different language, you can set the `LOCALIZATION_LANGUAGE` setting to the desired language code.
|
|
547
|
+
The individual languages are specified with a two-letter code according to ISO 639-1. The default language is `en` (English). If you want to use a different language, you can set the `LOCALIZATION_LANGUAGE` setting to the desired language code.
|
|
548
|
+
|
|
549
|
+
If you want to localize the system labels of the framework, you can do so by providing a custom localization file with the same structure as the default one but containing only the languages you want to add. For example, the default English label for `E_UNKNOWN_ERROR` is found in JSON path `system.exceptions.0.en`. To add an entry for German, your file needs to contain a `system.exceptions.0.de` property. The localization module will handle the rest. You can use the same approach to modify the existing English labels as well. The full list of system labels is found in the `bin/localization/labels.json` file. Avoid modifying the default file since it might get overwritten by future updates.
|
|
@@ -70,6 +70,9 @@
|
|
|
70
70
|
"3007": {
|
|
71
71
|
"en": "The message exchange is irrevocably broken and cannot be used any longer."
|
|
72
72
|
},
|
|
73
|
+
"3008": {
|
|
74
|
+
"en": "The execution of a service reported a failure. This might be a business logic error or a system error."
|
|
75
|
+
},
|
|
73
76
|
"3010": {
|
|
74
77
|
"en": "Connection retry attempts exceeded the configured limit."
|
|
75
78
|
},
|
package/bin/start-instance.js
CHANGED
|
@@ -121,8 +121,6 @@ process.on( "uncaughtException", ( error ) => {
|
|
|
121
121
|
|
|
122
122
|
// Start the instance:
|
|
123
123
|
try {
|
|
124
|
-
logger.log( `Starting new instance of type '${ process.env.TI_INSTANCE_NAME }' with instance ID '${ process.env.TI_INSTANCE_ID }'.`, logger.logSeverity.NOTICE );
|
|
125
|
-
|
|
126
124
|
const serviceConstructor = require( path.join( process.cwd(), process.env.TI_INSTANCE_CLASS ) );
|
|
127
125
|
const serviceConfigPath = process.env.TI_INSTANCE_CONFIG;
|
|
128
126
|
/** @type ServiceConfiguration */
|
|
@@ -144,6 +142,7 @@ try {
|
|
|
144
142
|
};
|
|
145
143
|
|
|
146
144
|
if ( mainInstance.isServiceInstance ) {
|
|
145
|
+
logger.log( `Starting new instance of type '${ process.env.TI_INSTANCE_NAME }' with instance ID '${ process.env.TI_INSTANCE_ID }'.`, logger.logSeverity.NOTICE );
|
|
147
146
|
mainInstance.start().catch( ( error ) => {
|
|
148
147
|
logger.log( `Error detected during instance '${ process.env.TI_INSTANCE_ID }' startup!`, logger.logSeverity.ALERT, error );
|
|
149
148
|
setImmediate( () => process.exit( 1 ) );
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ti-engine/core",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.12",
|
|
4
4
|
"description": "The ti-engine is an open source, free to use—both for personal and commercial projects—framework for the creation of microservice-based solutions using node.js.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"microservices",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"@dotenvx/dotenvx": "^1.51.0",
|
|
61
61
|
"blake2": "^5.0.0",
|
|
62
|
-
"ioredis": "^5.8.
|
|
62
|
+
"ioredis": "^5.8.2",
|
|
63
63
|
"lodash": "^4.17.21",
|
|
64
64
|
"node-schedule": "^2.1.1"
|
|
65
65
|
},
|
package/utils/config.js
CHANGED
|
@@ -185,7 +185,7 @@ if ( tools.toBool( process.env.TI_GCLOUD_ENABLED ) === true && settings.gcloudIn
|
|
|
185
185
|
settings.operationMode = process.env.NODE_ENV || settings.operationMode;
|
|
186
186
|
|
|
187
187
|
// Prevent further modifications to the settings object:
|
|
188
|
-
|
|
188
|
+
tools.deepFreeze( settings );
|
|
189
189
|
|
|
190
190
|
/**
|
|
191
191
|
* A standard getter method for fetching a setting.
|
package/utils/exceptions.js
CHANGED
|
@@ -43,6 +43,7 @@ const exceptionCodeEnum = tools.enum( {
|
|
|
43
43
|
E_COM_SERVICE_HANDLER_NOT_FOUND: [ 3005, "service handler not found", "No handler found in the interface for the specified service or service version." ],
|
|
44
44
|
E_COM_MESSAGE_RECEIVER_UNAVAILABLE: [ 3006, "message receiver unavailable", "The message receiver instance is currently unavailable." ],
|
|
45
45
|
E_COM_MESSAGE_EXCHANGE_BROKEN: [ 3007, "message exchange broken", "The message exchange is irrevocably broken and cannot be used any longer." ],
|
|
46
|
+
E_COM_SERVICE_EXEC_FAILED: [ 3008, "service exec failed", "The execution of a service reported a failure. This might be a business logic error or a system error." ],
|
|
46
47
|
E_COM_RETRY_ATTEMPTS_EXCEEDED: [ 3010, "retry attempts exceeded", "Connection retry attempts exceeded the configured limit." ],
|
|
47
48
|
/** Web server exceptions - codes under 4xxx */
|
|
48
49
|
E_WEB_INVALID_REQUEST_METHOD: [ 4000, "invalid request method", "The request method is not recognized or not supported." ],
|
package/utils/localization.js
CHANGED
|
@@ -245,12 +245,7 @@ module.exports.localizationLanguage = localizationLanguageEnum;
|
|
|
245
245
|
* @typedef {Object<string, TiLocalizedLabel | TiLabelsTree>} TiLabelsTree
|
|
246
246
|
*/
|
|
247
247
|
|
|
248
|
-
/**
|
|
249
|
-
* @typedef {Object} TiLabels
|
|
250
|
-
* @property {TiLabelsTree} labels
|
|
251
|
-
*/
|
|
252
|
-
|
|
253
|
-
/** @type {TiLabels} */
|
|
248
|
+
/** @type {TiLabelsTree} */
|
|
254
249
|
const labels = require( "#labels" );
|
|
255
250
|
|
|
256
251
|
// Load any custom labels defined in the configuration:
|
|
@@ -264,7 +259,7 @@ if ( labelsPaths && _.isArray( labelsPaths ) && labelsPaths.length > 0 ) {
|
|
|
264
259
|
}
|
|
265
260
|
|
|
266
261
|
// Prevent further modifications to the TiLabels object:
|
|
267
|
-
|
|
262
|
+
tools.deepFreeze( labels );
|
|
268
263
|
|
|
269
264
|
/**
|
|
270
265
|
* Used to return the textual value for a label based on the current system language by default or the specified language code if provided.
|
|
@@ -277,4 +272,43 @@ Object.freeze( labels );
|
|
|
277
272
|
*/
|
|
278
273
|
module.exports.getLabel = ( label, language ) => {
|
|
279
274
|
return _.get( labels, label + "." + ( ( language ) ? language : config.getSetting( config.setting.LOCALIZATION_LANGUAGE ) ), defaultEmptyLabel );
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
const labelsCacheByLanguage = new Map();
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Used to return the entire labels tree.
|
|
281
|
+
* <br/>
|
|
282
|
+
* NOTE: The result will be a modified copy of the label tree that has no "language" end-nodes and keeps only the appropriate labels for the requested language.
|
|
283
|
+
* For example, if the original JSON path is "path.to.label.language", the returned path will be just "path.to.label" corresponding to the text label.
|
|
284
|
+
*
|
|
285
|
+
* @method
|
|
286
|
+
* @param {TiLocalizationLanguage} [language] The language code to use for the lookup. If not provided, the current system language will be used.
|
|
287
|
+
* @returns {TiLabelsTree}
|
|
288
|
+
* @public
|
|
289
|
+
*/
|
|
290
|
+
module.exports.getAllLabels = ( language ) => {
|
|
291
|
+
const usedLanguage = language || config.getSetting( config.setting.LOCALIZATION_LANGUAGE );
|
|
292
|
+
|
|
293
|
+
if ( labelsCacheByLanguage.has( usedLanguage ) ) {
|
|
294
|
+
return labelsCacheByLanguage.get( usedLanguage );
|
|
295
|
+
} else {
|
|
296
|
+
const labelsByLanguage = _.cloneDeepWith( labels, ( value ) => {
|
|
297
|
+
if ( _.isPlainObject( value ) ) {
|
|
298
|
+
const values = Object.values( value );
|
|
299
|
+
const isLeaf = values.length > 0 && values.every( v => _.isString( v ) || _.isNil( v ) );
|
|
300
|
+
if ( isLeaf ) {
|
|
301
|
+
// Return only the desired language or default placeholder if missing:
|
|
302
|
+
return _.get( value, usedLanguage, defaultEmptyLabel );
|
|
303
|
+
}
|
|
304
|
+
} else {
|
|
305
|
+
// Return undefined to let lodash handle default deep cloning for non-leaves:
|
|
306
|
+
return undefined;
|
|
307
|
+
}
|
|
308
|
+
} );
|
|
309
|
+
|
|
310
|
+
tools.deepFreeze( labelsByLanguage );
|
|
311
|
+
labelsCacheByLanguage.set( usedLanguage, labelsByLanguage );
|
|
312
|
+
return labelsByLanguage;
|
|
313
|
+
}
|
|
280
314
|
};
|
package/utils/tools.js
CHANGED
|
@@ -35,6 +35,27 @@ module.exports.getUUID = () => {
|
|
|
35
35
|
return crypto.randomUUID( { disableEntropyCache: true } );
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Used to deep-freeze an object.
|
|
40
|
+
*
|
|
41
|
+
* @method
|
|
42
|
+
* @param {Object} object
|
|
43
|
+
* @param {WeakSet} [seen]
|
|
44
|
+
* @return {Object}
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
47
|
+
module.exports.deepFreeze = ( object, seen = new WeakSet() ) => {
|
|
48
|
+
if ( object === null || typeof object !== "object" || seen.has( object ) ) {
|
|
49
|
+
return object;
|
|
50
|
+
} else {
|
|
51
|
+
seen.add( object );
|
|
52
|
+
_.forOwn( object, ( value ) => {
|
|
53
|
+
module.exports.deepFreeze( value, seen );
|
|
54
|
+
} );
|
|
55
|
+
return Object.freeze( object );
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
38
59
|
/**
|
|
39
60
|
* Used to create a custom Enum list.
|
|
40
61
|
*
|
|
@@ -199,6 +220,24 @@ module.exports.toBool = ( value ) => {
|
|
|
199
220
|
return result;
|
|
200
221
|
};
|
|
201
222
|
|
|
223
|
+
/**
|
|
224
|
+
* Used to fetch only the unique values from the provided array.
|
|
225
|
+
* <br/>
|
|
226
|
+
* Note: For objects and arrays, uniqueness is determined by reference equality. Primitives are compared by their value.
|
|
227
|
+
*
|
|
228
|
+
* @method
|
|
229
|
+
* @param {Array} array
|
|
230
|
+
* @returns {Array}
|
|
231
|
+
* @throws {TypeError} If the provided parameter is not an array
|
|
232
|
+
* @public
|
|
233
|
+
*/
|
|
234
|
+
module.exports.arrayUniques = ( array ) => {
|
|
235
|
+
if ( !Array.isArray( array ) ) {
|
|
236
|
+
throw new TypeError( "Expected an array" );
|
|
237
|
+
}
|
|
238
|
+
return [ ...new Set( array ) ];
|
|
239
|
+
};
|
|
240
|
+
|
|
202
241
|
/**
|
|
203
242
|
* Will return a UTC date string in format YYYY-MM-DD from the provided date.
|
|
204
243
|
*
|