@ti-engine/core 1.2.4 → 1.3.3
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 +44 -0
- package/README.md +7 -9
- package/bin/localization/labels.json +94 -60
- package/bin/start-instance.js +1 -1
- package/components/auditing.js +14 -13
- package/components/connection-observer.js +19 -4
- package/components/exchange/message-exchange.js +16 -1
- package/components/exchange/message-handler.js +37 -7
- package/components/exchange/message-observer.js +51 -4
- package/components/exchange/message-receiver.js +1 -1
- package/components/service-caller.js +248 -147
- package/components/service-executor.js +19 -4
- package/components/service-instance.js +8 -3
- package/integrations/redis-integration.js +86 -23
- package/package.json +1 -1
- package/utils/cache.js +24 -2
- package/utils/config.js +5 -5
- package/utils/exceptions.js +41 -35
- package/utils/localization.js +249 -12
- package/utils/logger.js +3 -3
- package/utils/tools.js +2 -2
|
@@ -28,6 +28,7 @@ let cacheCommandsEnum = tools.enum( {
|
|
|
28
28
|
HASH_GET: [ "hget", "hash get", "https://redis.io/docs/latest/commands/hget/" ],
|
|
29
29
|
HASH_GET_ALL: [ "hgetall", "hash get all", "https://redis.io/docs/latest/commands/hgetall/" ],
|
|
30
30
|
HASH_REMOVE: [ "hdel", "hash remove", "https://redis.io/docs/latest/commands/hdel/" ],
|
|
31
|
+
HASH_EXPIRE: [ "hexpire", "hash expire", "https://redis.io/docs/latest/commands/hexpire/" ],
|
|
31
32
|
HASH_SET: [ "hset", "", "https://redis.io/docs/latest/commands/hset/" ],
|
|
32
33
|
HASH_SET_MANY: [ "hmset", "(deprecated) use HSET with multiple fields", "https://redis.io/docs/latest/commands/hmset/" ],
|
|
33
34
|
IS_SET_MEMBER: [ "sismember", "", "https://redis.io/docs/latest/commands/sismember/" ],
|
|
@@ -43,6 +44,21 @@ let cacheCommandsEnum = tools.enum( {
|
|
|
43
44
|
UNION_OF_SETS: [ "sunion", "union of sets", "https://redis.io/docs/latest/commands/sunion/" ]
|
|
44
45
|
} );
|
|
45
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Enum for listing all client statuses.
|
|
49
|
+
*
|
|
50
|
+
* @readonly
|
|
51
|
+
* @enum {number}
|
|
52
|
+
*/
|
|
53
|
+
let clientStatusEnum = tools.enum( {
|
|
54
|
+
UNINITIALIZED: [ 0, "uninitialized", "Redis client is offline and not yet initialized." ],
|
|
55
|
+
CONNECTED: [ 1, "connected", "Redis client is connected and online." ],
|
|
56
|
+
CONNECTING: [ 2, "connecting", "Redis client is connecting to server." ],
|
|
57
|
+
DISRUPTED: [ 3, "disrupted", "Redis client is temporarily disconnected from server due to a disruption." ],
|
|
58
|
+
SHUTTING_DOWN: [ 4, "shutting down", "Redis client is shutting down." ],
|
|
59
|
+
DISCONNECTED: [ 5, "disconnected", "Redis client is permanently disconnected from server." ]
|
|
60
|
+
} );
|
|
61
|
+
|
|
46
62
|
/**
|
|
47
63
|
* Enum for listing the Redis key override modes.
|
|
48
64
|
*
|
|
@@ -63,6 +79,10 @@ module.exports.cacheCommands = cacheCommandsEnum;
|
|
|
63
79
|
* @typedef {string} TiRedisOverrideMode
|
|
64
80
|
*/
|
|
65
81
|
module.exports.cacheOverrideMode = cacheOverrideModeEnum;
|
|
82
|
+
/**
|
|
83
|
+
* @typedef {number} TiRedisClientStatus
|
|
84
|
+
*/
|
|
85
|
+
module.exports.clientStatus = clientStatusEnum;
|
|
66
86
|
|
|
67
87
|
/**
|
|
68
88
|
* Used to create a Redis Cache client.
|
|
@@ -76,6 +96,7 @@ module.exports.cacheOverrideMode = cacheOverrideModeEnum;
|
|
|
76
96
|
class RedisClient {
|
|
77
97
|
|
|
78
98
|
#clientIdentifier;
|
|
99
|
+
#clientStatus = clientStatusEnum.UNINITIALIZED;
|
|
79
100
|
#retryMaxInterval = 1000;
|
|
80
101
|
#retryMaxAttempts = undefined;
|
|
81
102
|
#redisConnection = undefined;
|
|
@@ -118,6 +139,17 @@ class RedisClient {
|
|
|
118
139
|
return this.#redisClientID;
|
|
119
140
|
}
|
|
120
141
|
|
|
142
|
+
/**
|
|
143
|
+
* Used to return the Redis client status.
|
|
144
|
+
*
|
|
145
|
+
* @property
|
|
146
|
+
* @returns {number}
|
|
147
|
+
* @public
|
|
148
|
+
*/
|
|
149
|
+
get clientStatus() {
|
|
150
|
+
return this.#clientStatus;
|
|
151
|
+
}
|
|
152
|
+
|
|
121
153
|
/**
|
|
122
154
|
* Used to return the Redis server version.
|
|
123
155
|
*
|
|
@@ -167,12 +199,6 @@ class RedisClient {
|
|
|
167
199
|
} ).then( ( clientID ) => {
|
|
168
200
|
// Store the client ID:
|
|
169
201
|
this.#redisClientID = clientID;
|
|
170
|
-
|
|
171
|
-
// Notify all connection observers about the initialization success:
|
|
172
|
-
_.forEach( this.#connectionObservers, ( connectionObservers ) => {
|
|
173
|
-
connectionObservers.onConnectionRecovered( this.#clientIdentifier );
|
|
174
|
-
} );
|
|
175
|
-
|
|
176
202
|
resolve();
|
|
177
203
|
} ).catch( ( error ) => {
|
|
178
204
|
reject( exceptions.raise( error ) );
|
|
@@ -359,6 +385,7 @@ class RedisClient {
|
|
|
359
385
|
shutDown( timeoutMs = 1000 ) {
|
|
360
386
|
return new Promise( ( resolve ) => {
|
|
361
387
|
let finished = false;
|
|
388
|
+
this.#clientStatus = clientStatusEnum.SHUTTING_DOWN;
|
|
362
389
|
const done = () => {
|
|
363
390
|
if ( !finished ) {
|
|
364
391
|
finished = true;
|
|
@@ -403,7 +430,8 @@ class RedisClient {
|
|
|
403
430
|
* @param {number} defaultDB
|
|
404
431
|
* @param {number} [retryMaxIntervalMs=1000] Optional max backoff interval.
|
|
405
432
|
* @param {number|undefined} [retryMaxAttempts=undefined] Optional max (re)connection attempts before abort.
|
|
406
|
-
* @
|
|
433
|
+
* @returns {Promise}
|
|
434
|
+
* @private
|
|
407
435
|
*/
|
|
408
436
|
#setupClient( host, port, authKey, user, defaultDB, retryMaxIntervalMs, retryMaxAttempts ) {
|
|
409
437
|
return new Promise( ( resolve, reject ) => {
|
|
@@ -412,19 +440,22 @@ class RedisClient {
|
|
|
412
440
|
this.#retryMaxAttempts = retryMaxAttempts;
|
|
413
441
|
|
|
414
442
|
let retryStrategy = ( attempt ) => {
|
|
415
|
-
let
|
|
416
|
-
|
|
443
|
+
let retryInterval = Math.min( attempt * 50, this.#retryMaxInterval );
|
|
417
444
|
if ( this.#retryMaxAttempts != null && attempt > this.#retryMaxAttempts ) {
|
|
418
445
|
logger.log( "In Redis retry strategy: reached max attempts for command retry. Aborting...", logger.logSeverity.WARNING, { attempts: attempt } );
|
|
419
|
-
|
|
446
|
+
retryInterval = exceptions.raise( exceptions.exceptionCode.E_COM_RETRY_ATTEMPTS_EXCEEDED );
|
|
420
447
|
}
|
|
421
|
-
|
|
422
|
-
return result;
|
|
448
|
+
return retryInterval;
|
|
423
449
|
};
|
|
424
450
|
|
|
425
451
|
let reconnectOnError = ( error ) => {
|
|
426
452
|
logger.log( `In Redis reconnect on error strategy: ${ error.message }`, logger.logSeverity.ERROR, error );
|
|
427
|
-
|
|
453
|
+
if ( error.message.includes( "READONLY" ) ) {
|
|
454
|
+
// Returning 2 will also resubmit the failed command:
|
|
455
|
+
return 2;
|
|
456
|
+
} else {
|
|
457
|
+
return 0;
|
|
458
|
+
}
|
|
428
459
|
};
|
|
429
460
|
|
|
430
461
|
let options = {
|
|
@@ -441,22 +472,33 @@ class RedisClient {
|
|
|
441
472
|
|
|
442
473
|
/** @type Redis */
|
|
443
474
|
this.#redisConnection = new Redis( options );
|
|
475
|
+
this.#clientStatus = clientStatusEnum.CONNECTING;
|
|
476
|
+
|
|
477
|
+
this.#redisConnection.once( "ready", () => {
|
|
478
|
+
this.#clientStatus = clientStatusEnum.CONNECTED;
|
|
479
|
+
this.#notifyConnectionObservers();
|
|
480
|
+
|
|
481
|
+
this.#redisConnection.on( "ready", () => {
|
|
482
|
+
this.#clientStatus = clientStatusEnum.CONNECTED;
|
|
483
|
+
this.#notifyConnectionObservers();
|
|
484
|
+
} );
|
|
444
485
|
|
|
445
|
-
this.#redisConnection.on( "ready", () => {
|
|
446
|
-
logger.log( `Connection to Redis server ${ host }:${ port } (re)established by client '${ this.identifier }' and is ready to be used.`, logger.logSeverity.INFO );
|
|
447
486
|
resolve();
|
|
448
487
|
} );
|
|
449
488
|
this.#redisConnection.on( "error", ( error ) => {
|
|
489
|
+
this.#clientStatus = clientStatusEnum.DISRUPTED;
|
|
450
490
|
logger.log( `Error received in Redis client '${ this.identifier }'.`, logger.logSeverity.ERROR, error );
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
} );
|
|
491
|
+
this.#notifyConnectionObservers();
|
|
492
|
+
} );
|
|
493
|
+
this.#redisConnection.on( "reconnecting", ( retryInterval ) => {
|
|
494
|
+
this.#clientStatus = clientStatusEnum.CONNECTING;
|
|
495
|
+
logger.log( `Client '${ this.identifier }' reconnecting to Redis server after ${ retryInterval } ms.`, logger.logSeverity.DEBUG );
|
|
456
496
|
} );
|
|
457
|
-
this.#redisConnection.on( "
|
|
458
|
-
if (
|
|
459
|
-
|
|
497
|
+
this.#redisConnection.on( "end", () => {
|
|
498
|
+
if ( this.#clientStatus !== clientStatusEnum.SHUTTING_DOWN ) {
|
|
499
|
+
this.#clientStatus = clientStatusEnum.DISCONNECTED;
|
|
500
|
+
logger.log( `Client '${ this.identifier }' cannot reconnect to Redis server and has been shut down.`, logger.logSeverity.WARNING );
|
|
501
|
+
this.#notifyConnectionObservers();
|
|
460
502
|
}
|
|
461
503
|
} );
|
|
462
504
|
} catch ( error ) {
|
|
@@ -465,10 +507,31 @@ class RedisClient {
|
|
|
465
507
|
} );
|
|
466
508
|
}
|
|
467
509
|
|
|
510
|
+
/**
|
|
511
|
+
* Used to notify all connection observers about the current connection state.
|
|
512
|
+
*
|
|
513
|
+
* @method
|
|
514
|
+
* @private
|
|
515
|
+
*/
|
|
516
|
+
#notifyConnectionObservers() {
|
|
517
|
+
// Notify all connection observers about the event:
|
|
518
|
+
_.forEach( this.#connectionObservers, ( connectionObservers ) => {
|
|
519
|
+
if ( this.#clientStatus === clientStatusEnum.CONNECTED ) {
|
|
520
|
+
logger.log( `Connection to Redis server ${ this.#redisConnection.options.host }:${ this.#redisConnection.options.port } (re)established by client '${ this.identifier }' and is ready to be used.`, logger.logSeverity.INFO );
|
|
521
|
+
connectionObservers.onConnectionRecovered( this.#clientIdentifier );
|
|
522
|
+
} else if ( this.#clientStatus === clientStatusEnum.DISRUPTED ) {
|
|
523
|
+
connectionObservers.onConnectionDisrupted( this.#clientIdentifier );
|
|
524
|
+
} else if ( this.#clientStatus === clientStatusEnum.DISCONNECTED ) {
|
|
525
|
+
connectionObservers.onConnectionLost( this.#clientIdentifier );
|
|
526
|
+
}
|
|
527
|
+
} );
|
|
528
|
+
}
|
|
529
|
+
|
|
468
530
|
/**
|
|
469
531
|
* Used to fetch and store Redis server information.
|
|
470
532
|
*
|
|
471
533
|
* @method
|
|
534
|
+
* @returns {Promise}
|
|
472
535
|
* @private
|
|
473
536
|
*/
|
|
474
537
|
#fetchServerInfo() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ti-engine/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.3",
|
|
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
|
"author": "Boris Kostadinov <kostadinov.boris@gmail.com>",
|
|
6
6
|
"license": "GPL-3.0-or-later",
|
package/utils/cache.js
CHANGED
|
@@ -124,6 +124,22 @@ class CommonMemoryCache extends ConnectionObserver {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Needs to be invoked by the connection handler when the connection is irrevocably lost.
|
|
129
|
+
*
|
|
130
|
+
* @method
|
|
131
|
+
* @param {string} identifier The identifier of the observed connection.
|
|
132
|
+
* @override
|
|
133
|
+
* @public
|
|
134
|
+
*/
|
|
135
|
+
onConnectionLost( identifier ) {
|
|
136
|
+
if ( identifier === this.#connectionIdentifier ) {
|
|
137
|
+
this.#isOperational = false;
|
|
138
|
+
// TODO: implement forced shut down of the service instance instead of crashing it outright
|
|
139
|
+
throw exceptions.raise( exceptions.exceptionCode.E_GEN_SYSTEM_CACHE_UNAVAILABLE );
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
127
143
|
/**
|
|
128
144
|
* Used to register a new {@link ConnectionObserver} for events related to the underlying Redis connection state.
|
|
129
145
|
*
|
|
@@ -317,13 +333,19 @@ class CommonMemoryCache extends ConnectionObserver {
|
|
|
317
333
|
* @method
|
|
318
334
|
* @param {string} key
|
|
319
335
|
* @param {number} seconds
|
|
336
|
+
* @param {string} [name] If you need to expire a field in a hash set instead, provide the name of the set here.
|
|
320
337
|
* @returns {Promise<number>} This will resolve with the seconds as provided initially by the caller.
|
|
321
338
|
* @public
|
|
322
339
|
*/
|
|
323
|
-
expireValue( key, seconds ) {
|
|
340
|
+
expireValue( key, seconds, name ) {
|
|
324
341
|
return new Promise( ( resolve, reject ) => {
|
|
325
342
|
if ( this.#isOperational === true ) {
|
|
326
|
-
let commandExpire = [
|
|
343
|
+
let commandExpire = [];
|
|
344
|
+
if ( name ) {
|
|
345
|
+
commandExpire = [ redis.cacheCommands.HASH_EXPIRE, name, seconds, "FIELDS", 1, key ];
|
|
346
|
+
} else {
|
|
347
|
+
commandExpire = [ redis.cacheCommands.EXPIRE, key, seconds ];
|
|
348
|
+
}
|
|
327
349
|
this.#redisClient.executeCommands( [ commandExpire ] ).then( () => {
|
|
328
350
|
resolve( seconds );
|
|
329
351
|
} ).catch( ( error ) => {
|
package/utils/config.js
CHANGED
|
@@ -73,7 +73,7 @@ const tools = require( "#tools" );
|
|
|
73
73
|
/**
|
|
74
74
|
* @typedef {Object} SettingsLocalization
|
|
75
75
|
* @property {Array<string>} labelsPath
|
|
76
|
-
* @property {
|
|
76
|
+
* @property {TiLocalizationLanguage} language
|
|
77
77
|
*/
|
|
78
78
|
|
|
79
79
|
/**
|
|
@@ -113,7 +113,7 @@ const tools = require( "#tools" );
|
|
|
113
113
|
* @readonly
|
|
114
114
|
* @enum {string} Keys of this ENUM are strings.
|
|
115
115
|
*/
|
|
116
|
-
|
|
116
|
+
const settingsEnum = tools.enum( {
|
|
117
117
|
AUDITING_LOG_CONSOLE_ENABLED: [ "auditing.logConsoleEnabled", "logConsoleEnabled", "" ],
|
|
118
118
|
AUDITING_LOG_DETAILS: [ "auditing.logDetails", "logDetails", "" ],
|
|
119
119
|
AUDITING_LOG_MIN_LEVEL: [ "auditing.logMinLevel", "logMinLevel", "" ],
|
|
@@ -152,7 +152,7 @@ module.exports.setting = settingsEnum;
|
|
|
152
152
|
/** @type {SettingsMain} */
|
|
153
153
|
const settings = require( "#settings" );
|
|
154
154
|
|
|
155
|
-
//
|
|
155
|
+
// Override the remaining settings with ENV variables (if provided):
|
|
156
156
|
if ( settings.auditing ) {
|
|
157
157
|
settings.auditing.logConsoleEnabled = ( process.env.TI_AUDITING_LOG_CONSOLE_ENABLED !== undefined ) ? tools.toBool( process.env.TI_AUDITING_LOG_CONSOLE_ENABLED ) : settings.auditing.logConsoleEnabled;
|
|
158
158
|
settings.auditing.logDetails = ( process.env.TI_AUDITING_LOG_DETAILS !== undefined ) ? tools.toBool( process.env.TI_AUDITING_LOG_DETAILS ) : settings.auditing.logDetails;
|
|
@@ -160,7 +160,7 @@ if ( settings.auditing ) {
|
|
|
160
160
|
settings.auditing.logUsesJSON = ( process.env.TI_AUDITING_LOG_USES_JSON !== undefined ) ? tools.toBool( process.env.TI_AUDITING_LOG_USES_JSON ) : settings.auditing.logUsesJSON;
|
|
161
161
|
}
|
|
162
162
|
if ( settings.localization ) {
|
|
163
|
-
settings.localization.labelsPath = ( process.env.TI_LOCALIZATION_LABELS_PATH !== undefined ) ? process.env.TI_LOCALIZATION_LABELS_PATH : settings.localization.labelsPath;
|
|
163
|
+
settings.localization.labelsPath = ( process.env.TI_LOCALIZATION_LABELS_PATH !== undefined ) ? [ process.env.TI_LOCALIZATION_LABELS_PATH ] : settings.localization.labelsPath;
|
|
164
164
|
settings.localization.language = ( process.env.TI_LOCALIZATION_LANGUAGE !== undefined ) ? process.env.TI_LOCALIZATION_LANGUAGE : settings.localization.language;
|
|
165
165
|
}
|
|
166
166
|
if ( settings.memoryCache ) {
|
|
@@ -186,7 +186,7 @@ if ( process.env.TI_GCLOUD_ENABLED === true && settings.gcloudIntegration ) {
|
|
|
186
186
|
|
|
187
187
|
settings.operationMode = process.env.NODE_ENV || settings.operationMode;
|
|
188
188
|
|
|
189
|
-
//
|
|
189
|
+
// Prevent further modifications to the settings object:
|
|
190
190
|
Object.freeze( settings );
|
|
191
191
|
|
|
192
192
|
/**
|
package/utils/exceptions.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* 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.
|
|
3
|
-
* Copyright © 2021-
|
|
3
|
+
* Copyright © 2021-2025 Boris Kostadinov <kostadinov.boris@gmail.com>
|
|
4
4
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
5
5
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
6
6
|
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
@@ -15,7 +15,7 @@ const tools = require( "#tools" );
|
|
|
15
15
|
* @readonly
|
|
16
16
|
* @enum {number}
|
|
17
17
|
*/
|
|
18
|
-
|
|
18
|
+
const exceptionCodeEnum = tools.enum( {
|
|
19
19
|
E_UNKNOWN_ERROR: [ 0, "unknown error", "Unidentified error encountered or unrecognized exception code provided." ],
|
|
20
20
|
/** General exceptions - codes under 1xxx */
|
|
21
21
|
E_GEN_JS_INTERNAL_ERROR: [ 1000, "js internal error", "Error thrown by internal JS source." ],
|
|
@@ -25,7 +25,7 @@ let exceptionCodeEnum = tools.enum( {
|
|
|
25
25
|
E_GEN_SYSTEM_CACHE_UNAVAILABLE: [ 1004, "system cache unavailable", "The system cache required for proper engine operation is unavailable." ],
|
|
26
26
|
E_GEN_BAD_SERVICE_HANDLER: [ 1005, "bad service handler", "The provided service handler is not a proper function." ],
|
|
27
27
|
E_GEN_FEATURE_UNSUPPORTED: [ 1006, "feature unsupported", "The requested feature is not supported by current configuration or version." ],
|
|
28
|
-
/** Security & Administration
|
|
28
|
+
/** Security & Administration exceptions - codes under 2xxx */
|
|
29
29
|
E_SEC_INVALID_AUTH_TOKEN: [ 2000, "invalid auth token", "Invalid authorization token provided." ],
|
|
30
30
|
E_SEC_INVALID_EXPIRED_SESSION: [ 2001, "invalid or expired session", "Invalid or expired session encountered." ],
|
|
31
31
|
E_SEC_UNAUTHORIZED_ACCESS: [ 2002, "unauthorized access", "Attempt for unauthorized access detected." ],
|
|
@@ -38,16 +38,19 @@ let exceptionCodeEnum = tools.enum( {
|
|
|
38
38
|
E_COM_SERVICE_NOT_FOUND: [ 3004, "service not found", "The specified service is not found in the service definition interface." ],
|
|
39
39
|
E_COM_SERVICE_HANDLER_NOT_FOUND: [ 3005, "service handler not found", "No handler found in the interface for the specified service or service version." ],
|
|
40
40
|
E_COM_MESSAGE_RECEIVER_UNAVAILABLE: [ 3006, "message receiver unavailable", "The message receiver instance is currently unavailable." ],
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
41
|
+
E_COM_MESSAGE_EXCHANGE_BROKEN: [ 3007, "message exchange broken", "The message exchange is irrevocably broken and cannot be used any longer." ],
|
|
42
|
+
E_COM_RETRY_ATTEMPTS_EXCEEDED: [ 3010, "retry attempts exceeded", "Connection retry attempts exceeded the configured limit." ],
|
|
43
|
+
/** Web server exceptions - codes under 4xxx */
|
|
44
|
+
E_WEB_INVALID_REQUEST_METHOD: [ 4000, "invalid request method", "The request method is not recognized or not supported." ],
|
|
45
|
+
E_WEB_INVALID_REQUEST_URI: [ 4001, "invalid request uri", "The request URI is not recognized or not supported." ],
|
|
46
|
+
E_WEB_INVALID_REQUEST_BODY: [ 4002, "invalid request body", "The request body is not recognized or not supported." ],
|
|
47
|
+
E_WEB_INVALID_REQUEST_QUERY: [ 4003, "invalid request query", "The request query is not recognized or not supported." ],
|
|
48
|
+
E_WEB_INVALID_REQUEST_HEADERS: [ 4004, "invalid request headers", "The request headers are not recognized or not supported." ],
|
|
49
|
+
E_WEB_INVALID_REQUEST_PARAMETERS: [ 4005, "invalid request parameters", "The request parameters are not recognized or not supported." ],
|
|
50
|
+
E_WEB_INVALID_REQUEST_FORMAT: [ 4006, "invalid request format", "The request format is not recognized or not supported." ],
|
|
51
|
+
E_WEB_INVALID_REQUEST_CONTENT_TYPE: [ 4007, "invalid request content type", "The request content type is not recognized or not supported." ],
|
|
52
|
+
E_WEB_INVALID_REQUEST_CONTENT_LENGTH: [ 4008, "invalid request content length", "The request content length is not recognized or not supported." ],
|
|
53
|
+
E_WEB_INVALID_REQUEST_CONTENT_ENCODING: [ 4009, "invalid request content encoding", "The request content encoding is not recognized or not supported." ]
|
|
51
54
|
} );
|
|
52
55
|
|
|
53
56
|
/**
|
|
@@ -55,6 +58,8 @@ let exceptionCodeEnum = tools.enum( {
|
|
|
55
58
|
*/
|
|
56
59
|
module.exports.exceptionCode = exceptionCodeEnum;
|
|
57
60
|
|
|
61
|
+
const labelPath = "system.exceptions.";
|
|
62
|
+
|
|
58
63
|
/**
|
|
59
64
|
* Represents an exception.
|
|
60
65
|
*
|
|
@@ -83,8 +88,8 @@ class Exception {
|
|
|
83
88
|
this.#id = id;
|
|
84
89
|
this.#code = exceptionCode;
|
|
85
90
|
this.#httpCode = undefined;
|
|
86
|
-
this.#label =
|
|
87
|
-
this.#description = exceptionCodeEnum.properties[ exceptionCode ].description;
|
|
91
|
+
this.#label = labelPath + exceptionCode;
|
|
92
|
+
this.#description = description || exceptionCodeEnum.properties[ exceptionCode ].description;
|
|
88
93
|
this.#data = data || {};
|
|
89
94
|
}
|
|
90
95
|
|
|
@@ -93,8 +98,8 @@ class Exception {
|
|
|
93
98
|
/**
|
|
94
99
|
* Unique identifier of the exception instance. Can be used for tracing problems with customer support cases.
|
|
95
100
|
*
|
|
96
|
-
* @
|
|
97
|
-
* @
|
|
101
|
+
* @property
|
|
102
|
+
* @returns {string}
|
|
98
103
|
* @public
|
|
99
104
|
*/
|
|
100
105
|
get id() {
|
|
@@ -104,8 +109,8 @@ class Exception {
|
|
|
104
109
|
/**
|
|
105
110
|
* Identifier code of the exception type.
|
|
106
111
|
*
|
|
107
|
-
* @
|
|
108
|
-
* @
|
|
112
|
+
* @property
|
|
113
|
+
* @returns {TiExceptionCode}
|
|
109
114
|
* @public
|
|
110
115
|
*/
|
|
111
116
|
get code() {
|
|
@@ -115,8 +120,8 @@ class Exception {
|
|
|
115
120
|
/**
|
|
116
121
|
* HTTP error code if relevant.
|
|
117
122
|
*
|
|
118
|
-
* @
|
|
119
|
-
* @
|
|
123
|
+
* @property
|
|
124
|
+
* @returns {number}
|
|
120
125
|
* @public
|
|
121
126
|
*/
|
|
122
127
|
get httpCode() {
|
|
@@ -126,7 +131,7 @@ class Exception {
|
|
|
126
131
|
/**
|
|
127
132
|
* HTTP error code if relevant.
|
|
128
133
|
*
|
|
129
|
-
* @
|
|
134
|
+
* @property
|
|
130
135
|
* @param {number} httpCode
|
|
131
136
|
* @public
|
|
132
137
|
*/
|
|
@@ -137,8 +142,8 @@ class Exception {
|
|
|
137
142
|
/**
|
|
138
143
|
* Localized label identifier.
|
|
139
144
|
*
|
|
140
|
-
* @
|
|
141
|
-
* @
|
|
145
|
+
* @property
|
|
146
|
+
* @returns {string}
|
|
142
147
|
* @public
|
|
143
148
|
*/
|
|
144
149
|
get label() {
|
|
@@ -148,8 +153,8 @@ class Exception {
|
|
|
148
153
|
/**
|
|
149
154
|
* Description or additional technical information that is NOT localized.
|
|
150
155
|
*
|
|
151
|
-
* @
|
|
152
|
-
* @
|
|
156
|
+
* @property
|
|
157
|
+
* @returns {string}
|
|
153
158
|
* @public
|
|
154
159
|
*/
|
|
155
160
|
get description() {
|
|
@@ -159,8 +164,8 @@ class Exception {
|
|
|
159
164
|
/**
|
|
160
165
|
* JSON containing any additional data that has relevance for the exception. Can be converted JavaScript {@link Error} object as well.
|
|
161
166
|
*
|
|
162
|
-
* @
|
|
163
|
-
* @
|
|
167
|
+
* @property
|
|
168
|
+
* @returns {Object}
|
|
164
169
|
* @public
|
|
165
170
|
*/
|
|
166
171
|
get data() {
|
|
@@ -170,7 +175,7 @@ class Exception {
|
|
|
170
175
|
/**
|
|
171
176
|
* JSON containing any additional data that has relevance for the exception. Can be converted JavaScript {@link Error} object as well.
|
|
172
177
|
*
|
|
173
|
-
* @
|
|
178
|
+
* @property
|
|
174
179
|
* @param {Object} data
|
|
175
180
|
* @public
|
|
176
181
|
*/
|
|
@@ -182,17 +187,18 @@ class Exception {
|
|
|
182
187
|
* Extracts the essential information about the Exception and returns it as JSON.
|
|
183
188
|
*
|
|
184
189
|
* @method
|
|
190
|
+
* @param {boolean} [includeData=true] Whether to include the data property in the output.
|
|
185
191
|
* @returns {Object}
|
|
186
192
|
* @public
|
|
187
193
|
*/
|
|
188
|
-
asJSON() {
|
|
194
|
+
asJSON( includeData = true ) {
|
|
189
195
|
return {
|
|
190
196
|
id: this.id,
|
|
191
197
|
code: this.code,
|
|
192
198
|
httpCode: this.httpCode,
|
|
193
199
|
label: this.label,
|
|
194
200
|
description: this.description,
|
|
195
|
-
data: this.data
|
|
201
|
+
data: ( includeData === true ) ? this.data : undefined
|
|
196
202
|
};
|
|
197
203
|
}
|
|
198
204
|
}
|
|
@@ -202,7 +208,7 @@ class Exception {
|
|
|
202
208
|
*
|
|
203
209
|
* @method
|
|
204
210
|
* @param {Error|TiExceptionCode|Exception} source Could be a standard JS Error, an ExceptionCode, or another Exception (in which case it will be raised further).
|
|
205
|
-
* @param {Object} [data] Additional JSON data that can
|
|
211
|
+
* @param {Object} [data] Additional JSON data that can go with the exception. If more data is added on later Raise calls, it will be merged with the existing one.
|
|
206
212
|
* @param {string} [exceptionID] Should be used only in cases when we have a recognizable exception ID beforehand. Should not be entered otherwise!
|
|
207
213
|
* @returns {Exception}
|
|
208
214
|
* @public
|
|
@@ -225,13 +231,13 @@ module.exports.raise = ( source, data, exceptionID ) => {
|
|
|
225
231
|
exception = new Exception( exceptionID || tools.getUUID(), ( exceptionCodeEnum.properties[ source ] ) ? source : module.exports.exceptionCode.E_UNKNOWN_ERROR );
|
|
226
232
|
}
|
|
227
233
|
|
|
228
|
-
//
|
|
234
|
+
// Merge the default exception data with the additional one if it's provided:
|
|
229
235
|
if ( data ) {
|
|
230
236
|
exception.data = _.mergeWith( ( exception.data || {} ), _.cloneDeep( data ), ( objValue, srcValue ) => {
|
|
231
237
|
return ( _.isArray( objValue ) ) ? objValue.concat( srcValue ) : undefined;
|
|
232
238
|
} );
|
|
233
239
|
|
|
234
|
-
//
|
|
240
|
+
// Make sure to eliminate any circular dependencies inside the data object (these should never be needed for an error description):
|
|
235
241
|
exception.data = tools.decycle( exception.data );
|
|
236
242
|
}
|
|
237
243
|
|
|
@@ -242,7 +248,7 @@ module.exports.raise = ( source, data, exceptionID ) => {
|
|
|
242
248
|
* Verifies if the passed object is an Exception.
|
|
243
249
|
*
|
|
244
250
|
* @method
|
|
245
|
-
* @param object
|
|
251
|
+
* @param {*} object
|
|
246
252
|
* @returns {boolean}
|
|
247
253
|
* @public
|
|
248
254
|
*/
|