@ti-engine/core 1.3.13 → 1.4.1

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/utils/config.js CHANGED
@@ -1,201 +1,104 @@
1
- /*
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-2025 Boris Kostadinov <kostadinov.boris@gmail.com>
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
- * 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
- * You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
7
- */
8
-
9
- const _ = require( "lodash" );
10
- const tools = require( "#tools" );
11
-
12
- /**
13
- * @typedef {string} EnvironmentVariable
14
- */
15
-
16
- /**
17
- * @typedef {NodeJS.Process} Environment
18
- * @property {ProcessEnv} env
19
- * @property {EnvironmentVariable} env.TI_GCLOUD_API_KEY
20
- * @property {EnvironmentVariable} env.TI_GCLOUD_ENABLED
21
- * @property {EnvironmentVariable} env.TI_GCLOUD_PROJECT_ID
22
- * @property {EnvironmentVariable} env.TI_INSTANCE_CLASS
23
- * @property {EnvironmentVariable} env.TI_INSTANCE_CONFIG
24
- * @property {EnvironmentVariable} env.TI_INSTANCE_ID
25
- * @property {EnvironmentVariable} env.TI_INSTANCE_NAME
26
- * @property {EnvironmentVariable} env.TI_AUDITING_LOG_CONSOLE_ENABLED
27
- * @property {EnvironmentVariable} env.TI_AUDITING_LOG_DETAILS
28
- * @property {EnvironmentVariable} env.TI_AUDITING_LOG_MIN_LEVEL
29
- * @property {EnvironmentVariable} env.TI_AUDITING_LOG_USES_JSON
30
- * @property {EnvironmentVariable} env.TI_LOCALIZATION_LABELS_PATH
31
- * @property {EnvironmentVariable} env.TI_LOCALIZATION_LANGUAGE
32
- * @property {EnvironmentVariable} env.TI_MEMORY_CACHE_AUTH_KEY
33
- * @property {EnvironmentVariable} env.TI_MEMORY_CACHE_REDIS_DB
34
- * @property {EnvironmentVariable} env.TI_MEMORY_CACHE_REDIS_HOST
35
- * @property {EnvironmentVariable} env.TI_MEMORY_CACHE_REDIS_PORT
36
- * @property {EnvironmentVariable} env.TI_MEMORY_CACHE_RETRY_MAX_ATTEMPTS
37
- * @property {EnvironmentVariable} env.TI_MEMORY_CACHE_RETRY_MAX_INTERVAL
38
- * @property {EnvironmentVariable} env.TI_MEMORY_CACHE_USER
39
- * @property {EnvironmentVariable} env.TI_MESSAGE_EXCHANGE_SECURITY_HASH_ENABLED
40
- * @property {EnvironmentVariable} env.TI_MESSAGE_EXCHANGE_SECURITY_HASH_KEY
41
- * @property {EnvironmentVariable} env.TI_MESSAGE_EXCHANGE_TRACE_LOG_ENABLED
42
- */
43
-
44
- /**
45
- * @typedef {string} CronString
46
- */
47
-
48
- /**
49
- * @typedef {Object} SettingsMain
50
- * @property {SettingsAuditing} auditing
51
- * @property {SettingsGcloudIntegration} gcloudIntegration
52
- * @property {SettingsLocalization} localization
53
- * @property {SettingsMemoryCache} memoryCache
54
- * @property {SettingsMessageExchange} messageExchange
55
- * @property {SettingsServiceConfig} serviceConfig
56
- * @property {string} operationMode
57
- */
58
-
59
- /**
60
- * @typedef {Object} SettingsAuditing
61
- * @property {boolean} logConsoleEnabled
62
- * @property {boolean} logDetails
63
- * @property {TiLogSeverity} logMinLevel
64
- * @property {boolean} logUsesJSON
65
- */
66
-
67
- /**
68
- * @typedef {Object} SettingsGcloudIntegration
69
- * @property {string} apiKey
70
- * @property {string} projectID
71
- */
72
-
73
- /**
74
- * @typedef {Object} SettingsLocalization
75
- * @property {Array<string>} labelsPath
76
- * @property {TiLocalizationLanguage} language
77
- */
78
-
79
- /**
80
- * @typedef {Object} SettingsMemoryCache
81
- * @property {string} authKey
82
- * @property {number} redisDB
83
- * @property {string} redisHost
84
- * @property {number} redisPort
85
- * @property {number} retryMaxAttempts
86
- * @property {number} retryMaxInterval
87
- * @property {string} user
88
- */
89
-
90
- /**
91
- * @typedef {Object} SettingsMessageExchange
92
- * @property {string} messageQueuePrefix
93
- * @property {string} messageStore
94
- * @property {boolean} securityHashEnabled
95
- * @property {string} securityHashKey
96
- * @property {number} traceExpirationTime
97
- * @property {boolean} traceLogEnabled
98
- * @property {string} traceRepository
99
- */
100
-
101
- /**
102
- * @typedef {Object} SettingsServiceConfig
103
- * @property {number} executionTimeout
104
- * @property {string} healthCheckAddress
105
- * @property {CronString} healthCheckInterval
106
- * @property {number} healthCheckTimeout
107
- * @property {string} serviceRegistryAddress
108
- */
109
-
110
- /**
111
- * Enum for listing all system settings.
112
- *
113
- * @readonly
114
- * @enum {string} Keys of this ENUM are strings.
115
- * @typedef {string} TiSetting
116
- */
117
- const settingsEnum = tools.enum( {
118
- AUDITING_LOG_CONSOLE_ENABLED: [ "auditing.logConsoleEnabled", "logConsoleEnabled", "" ],
119
- AUDITING_LOG_DETAILS: [ "auditing.logDetails", "logDetails", "" ],
120
- AUDITING_LOG_MIN_LEVEL: [ "auditing.logMinLevel", "logMinLevel", "" ],
121
- AUDITING_LOG_USES_JSON: [ "auditing.logUsesJSON", "logUsesJSON", "" ],
122
- GCLOUD_API_KEY: [ "gcloudIntegration.apiKey", "apiKey", "" ],
123
- GCLOUD_PROJECT_ID: [ "gcloudIntegration.projectID", "projectID", "" ],
124
- LOCALIZATION_LABELS_PATH: [ "localization.labelsPath", "labelsPath", "" ],
125
- LOCALIZATION_LANGUAGE: [ "localization.language", "language", "" ],
126
- MEMORY_CACHE_AUTH_KEY: [ "memoryCache.authKey", "authKey", "" ],
127
- MEMORY_CACHE_REDIS_DB: [ "memoryCache.redisDB", "redisDB", "" ],
128
- MEMORY_CACHE_REDIS_HOST: [ "memoryCache.redisHost", "redisHost", "" ],
129
- MEMORY_CACHE_REDIS_PORT: [ "memoryCache.redisPort", "redisPort", "" ],
130
- MEMORY_CACHE_RETRY_MAX_ATTEMPTS: [ "memoryCache.retryMaxAttempts", "retryMaxAttempts", "" ],
131
- MEMORY_CACHE_RETRY_MAX_INTERVAL: [ "memoryCache.retryMaxInterval", "retryMaxInterval", "" ],
132
- MEMORY_CACHE_USER: [ "memoryCache.user", "user", "" ],
133
- MESSAGE_EXCHANGE_QUEUE_PREFIX: [ "messageExchange.messageQueuePrefix", "messageQueuePrefix", "" ],
134
- MESSAGE_EXCHANGE_MESSAGE_STORE: [ "messageExchange.messageStore", "messageStore", "" ],
135
- MESSAGE_EXCHANGE_SECURITY_HASH_ENABLED: [ "messageExchange.securityHashEnabled", "securityHashEnabled", "" ],
136
- MESSAGE_EXCHANGE_SECURITY_HASH_KEY: [ "messageExchange.securityHashKey", "securityHashKey", "" ],
137
- MESSAGE_EXCHANGE_TRACE_EXPIRATION_TIME: [ "messageExchange.traceExpirationTime", "traceExpirationTime", "" ],
138
- MESSAGE_EXCHANGE_TRACE_LOG_ENABLED: [ "messageExchange.traceLogEnabled", "traceLogEnabled", "" ],
139
- MESSAGE_EXCHANGE_TRACE_REPOSITORY: [ "messageExchange.traceRepository", "traceRepository", "" ],
140
- SERVICE_EXECUTION_TIMEOUT: [ "serviceConfig.executionTimeout", "executionTimeout", "" ],
141
- SERVICE_HEALTH_CHECK_ADDRESS: [ "serviceConfig.healthCheckAddress", "healthCheckAddress", "" ],
142
- SERVICE_HEALTH_CHECK_INTERVAL: [ "serviceConfig.healthCheckInterval", "healthCheckInterval", "" ],
143
- SERVICE_HEALTH_CHECK_TIMEOUT: [ "serviceConfig.healthCheckTimeout", "healthCheckTimeout", "" ],
144
- SERVICE_REGISTRY_ADDRESS: [ "serviceConfig.serviceRegistryAddress", "serviceRegistryAddress", "" ],
145
- OPERATION_MODE: [ "operationMode", "operationMode", "" ]
146
- } );
147
-
148
- module.exports.setting = settingsEnum;
149
-
150
- /** @type {SettingsMain} */
151
- const settings = require( "#settings" );
152
-
153
- // Override the remaining settings with ENV variables (if provided):
154
- if ( settings.auditing ) {
155
- settings.auditing.logConsoleEnabled = ( process.env.TI_AUDITING_LOG_CONSOLE_ENABLED !== undefined ) ? tools.toBool( process.env.TI_AUDITING_LOG_CONSOLE_ENABLED ) : settings.auditing.logConsoleEnabled;
156
- settings.auditing.logDetails = ( process.env.TI_AUDITING_LOG_DETAILS !== undefined ) ? tools.toBool( process.env.TI_AUDITING_LOG_DETAILS ) : settings.auditing.logDetails;
157
- settings.auditing.logMinLevel = ( process.env.TI_AUDITING_LOG_MIN_LEVEL !== undefined ) ? process.env.TI_AUDITING_LOG_MIN_LEVEL : settings.auditing.logMinLevel;
158
- settings.auditing.logUsesJSON = ( process.env.TI_AUDITING_LOG_USES_JSON !== undefined ) ? tools.toBool( process.env.TI_AUDITING_LOG_USES_JSON ) : settings.auditing.logUsesJSON;
159
- }
160
- if ( settings.localization ) {
161
- settings.localization.labelsPath = ( process.env.TI_LOCALIZATION_LABELS_PATH !== undefined ) ? [ process.env.TI_LOCALIZATION_LABELS_PATH ] : settings.localization.labelsPath;
162
- settings.localization.language = ( process.env.TI_LOCALIZATION_LANGUAGE !== undefined ) ? process.env.TI_LOCALIZATION_LANGUAGE : settings.localization.language;
163
- }
164
- if ( settings.memoryCache ) {
165
- settings.memoryCache.authKey = ( process.env.TI_MEMORY_CACHE_AUTH_KEY !== undefined ) ? process.env.TI_MEMORY_CACHE_AUTH_KEY : settings.memoryCache.authKey;
166
- settings.memoryCache.redisDB = ( process.env.TI_MEMORY_CACHE_REDIS_DB !== undefined ) ? Number( process.env.TI_MEMORY_CACHE_REDIS_DB ) : settings.memoryCache.redisDB;
167
- settings.memoryCache.redisHost = ( process.env.TI_MEMORY_CACHE_REDIS_HOST !== undefined ) ? process.env.TI_MEMORY_CACHE_REDIS_HOST : settings.memoryCache.redisHost;
168
- settings.memoryCache.redisPort = ( process.env.TI_MEMORY_CACHE_REDIS_PORT !== undefined ) ? Number( process.env.TI_MEMORY_CACHE_REDIS_PORT ) : settings.memoryCache.redisPort;
169
- settings.memoryCache.retryMaxAttempts = ( process.env.TI_MEMORY_CACHE_RETRY_MAX_ATTEMPTS !== undefined ) ? Number( process.env.TI_MEMORY_CACHE_RETRY_MAX_ATTEMPTS ) : settings.memoryCache.retryMaxAttempts;
170
- settings.memoryCache.retryMaxInterval = ( process.env.TI_MEMORY_CACHE_RETRY_MAX_INTERVAL !== undefined ) ? Number( process.env.TI_MEMORY_CACHE_RETRY_MAX_INTERVAL ) : settings.memoryCache.retryMaxInterval;
171
- settings.memoryCache.user = ( process.env.TI_MEMORY_CACHE_USER !== undefined ) ? process.env.TI_MEMORY_CACHE_USER : settings.memoryCache.user;
172
- }
173
- if ( settings.messageExchange ) {
174
- settings.messageExchange.securityHashEnabled = ( process.env.TI_MESSAGE_EXCHANGE_SECURITY_HASH_ENABLED !== undefined ) ? tools.toBool( process.env.TI_MESSAGE_EXCHANGE_SECURITY_HASH_ENABLED ) : settings.messageExchange.securityHashEnabled;
175
- settings.messageExchange.securityHashKey = ( process.env.TI_MESSAGE_EXCHANGE_SECURITY_HASH_KEY !== undefined ) ? process.env.TI_MESSAGE_EXCHANGE_SECURITY_HASH_KEY : settings.messageExchange.securityHashKey;
176
- settings.messageExchange.traceLogEnabled = ( process.env.TI_MESSAGE_EXCHANGE_TRACE_LOG_ENABLED !== undefined ) ? tools.toBool( process.env.TI_MESSAGE_EXCHANGE_TRACE_LOG_ENABLED ) : settings.messageExchange.traceLogEnabled;
177
- }
178
-
179
- // Make sure GCloud is enabled before trying to set it up:
180
- if ( tools.toBool( process.env.TI_GCLOUD_ENABLED ) === true && settings.gcloudIntegration ) {
181
- settings.gcloudIntegration.apiKey = ( process.env.TI_GCLOUD_API_KEY !== undefined ) ? process.env.TI_GCLOUD_API_KEY : settings.gcloudIntegration.apiKey;
182
- settings.gcloudIntegration.projectID = ( process.env.TI_GCLOUD_PROJECT_ID !== undefined ) ? process.env.TI_GCLOUD_PROJECT_ID : settings.gcloudIntegration.projectID;
183
- }
184
-
185
- settings.operationMode = process.env.NODE_ENV || settings.operationMode;
186
-
187
- // Prevent further modifications to the settings object:
188
- tools.deepFreeze( settings );
189
-
190
- /**
191
- * A standard getter method for fetching a setting.
192
- *
193
- * @method
194
- * @param {string|TiSetting} setting Specifies either a dot-separated JSON path of the setting, or is a Setting from the settings enum.
195
- * @param {*} [defaultValue] The default value to be returned if the setting is not found in the current configuration.
196
- * @returns {*}
197
- * @public
198
- */
199
- module.exports.getSetting = ( setting, defaultValue ) => {
200
- return _.get( settings, setting, defaultValue );
1
+ /*
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-2026 Boris Kostadinov <kostadinov.boris@gmail.com>
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
+ * 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
+ * You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
7
+ */
8
+
9
+ const _ = require( "lodash" );
10
+ const tools = require( "#tools" );
11
+
12
+ /**
13
+ * Enum for listing all system settings.
14
+ *
15
+ * @readonly
16
+ * @enum {string} Keys of this ENUM are strings.
17
+ * @typedef {string} TiSetting
18
+ */
19
+ const settingsEnum = tools.enum( {
20
+ AUDITING_LOG_CONSOLE_ENABLED: [ "auditing.logConsoleEnabled", "logConsoleEnabled", "" ],
21
+ AUDITING_LOG_DETAILS: [ "auditing.logDetails", "logDetails", "" ],
22
+ AUDITING_LOG_MIN_LEVEL: [ "auditing.logMinLevel", "logMinLevel", "" ],
23
+ AUDITING_LOG_USES_JSON: [ "auditing.logUsesJSON", "logUsesJSON", "" ],
24
+ GCLOUD_API_KEY: [ "gcloudIntegration.apiKey", "apiKey", "" ],
25
+ GCLOUD_PROJECT_ID: [ "gcloudIntegration.projectID", "projectID", "" ],
26
+ LOCALIZATION_LABELS_PATH: [ "localization.labelsPath", "labelsPath", "" ],
27
+ LOCALIZATION_LANGUAGE: [ "localization.language", "language", "" ],
28
+ MEMORY_CACHE_AUTH_KEY: [ "memoryCache.authKey", "authKey", "" ],
29
+ MEMORY_CACHE_REDIS_DB: [ "memoryCache.redisDB", "redisDB", "" ],
30
+ MEMORY_CACHE_REDIS_HOST: [ "memoryCache.redisHost", "redisHost", "" ],
31
+ MEMORY_CACHE_REDIS_PORT: [ "memoryCache.redisPort", "redisPort", "" ],
32
+ MEMORY_CACHE_RETRY_MAX_ATTEMPTS: [ "memoryCache.retryMaxAttempts", "retryMaxAttempts", "" ],
33
+ MEMORY_CACHE_RETRY_MAX_INTERVAL: [ "memoryCache.retryMaxInterval", "retryMaxInterval", "" ],
34
+ MEMORY_CACHE_USER: [ "memoryCache.user", "user", "" ],
35
+ MESSAGE_EXCHANGE_QUEUE_PREFIX: [ "messageExchange.messageQueuePrefix", "messageQueuePrefix", "" ],
36
+ MESSAGE_EXCHANGE_MESSAGE_STORE: [ "messageExchange.messageStore", "messageStore", "" ],
37
+ MESSAGE_EXCHANGE_SECURITY_HASH_ENABLED: [ "messageExchange.securityHashEnabled", "securityHashEnabled", "" ],
38
+ MESSAGE_EXCHANGE_SECURITY_HASH_KEY: [ "messageExchange.securityHashKey", "securityHashKey", "" ],
39
+ MESSAGE_EXCHANGE_TRACE_EXPIRATION_TIME: [ "messageExchange.traceExpirationTime", "traceExpirationTime", "" ],
40
+ MESSAGE_EXCHANGE_TRACE_LOG_ENABLED: [ "messageExchange.traceLogEnabled", "traceLogEnabled", "" ],
41
+ MESSAGE_EXCHANGE_TRACE_REPOSITORY: [ "messageExchange.traceRepository", "traceRepository", "" ],
42
+ SERVICE_EXECUTION_TIMEOUT: [ "serviceConfig.executionTimeout", "executionTimeout", "" ],
43
+ SERVICE_HEALTH_CHECK_ADDRESS: [ "serviceConfig.healthCheckAddress", "healthCheckAddress", "" ],
44
+ SERVICE_HEALTH_CHECK_INTERVAL: [ "serviceConfig.healthCheckInterval", "healthCheckInterval", "" ],
45
+ SERVICE_HEALTH_CHECK_TIMEOUT: [ "serviceConfig.healthCheckTimeout", "healthCheckTimeout", "" ],
46
+ SERVICE_REGISTRY_ADDRESS: [ "serviceConfig.serviceRegistryAddress", "serviceRegistryAddress", "" ],
47
+ OPERATION_MODE: [ "operationMode", "operationMode", "" ]
48
+ } );
49
+ module.exports.setting = settingsEnum;
50
+
51
+ /** @type {SettingsMain} */
52
+ const settings = require( "#settings" );
53
+
54
+ // Override the remaining settings with ENV variables (if provided):
55
+ if ( settings.auditing ) {
56
+ settings.auditing.logConsoleEnabled = ( process.env.TI_AUDITING_LOG_CONSOLE_ENABLED !== undefined ) ? tools.toBool( process.env.TI_AUDITING_LOG_CONSOLE_ENABLED ) : settings.auditing.logConsoleEnabled;
57
+ settings.auditing.logDetails = ( process.env.TI_AUDITING_LOG_DETAILS !== undefined ) ? tools.toBool( process.env.TI_AUDITING_LOG_DETAILS ) : settings.auditing.logDetails;
58
+ settings.auditing.logMinLevel = ( process.env.TI_AUDITING_LOG_MIN_LEVEL !== undefined ) ? process.env.TI_AUDITING_LOG_MIN_LEVEL : settings.auditing.logMinLevel;
59
+ settings.auditing.logUsesJSON = ( process.env.TI_AUDITING_LOG_USES_JSON !== undefined ) ? tools.toBool( process.env.TI_AUDITING_LOG_USES_JSON ) : settings.auditing.logUsesJSON;
60
+ }
61
+ if ( settings.localization ) {
62
+ settings.localization.labelsPath = ( process.env.TI_LOCALIZATION_LABELS_PATH !== undefined )
63
+ ? process.env.TI_LOCALIZATION_LABELS_PATH.split( "," ).map( ( p ) => p.trim() ).filter( Boolean )
64
+ : settings.localization.labelsPath;
65
+ settings.localization.language = ( process.env.TI_LOCALIZATION_LANGUAGE !== undefined ) ? process.env.TI_LOCALIZATION_LANGUAGE : settings.localization.language;
66
+ }
67
+ if ( settings.memoryCache ) {
68
+ settings.memoryCache.authKey = ( process.env.TI_MEMORY_CACHE_AUTH_KEY !== undefined ) ? process.env.TI_MEMORY_CACHE_AUTH_KEY : settings.memoryCache.authKey;
69
+ settings.memoryCache.redisDB = ( process.env.TI_MEMORY_CACHE_REDIS_DB !== undefined ) ? Number( process.env.TI_MEMORY_CACHE_REDIS_DB ) : settings.memoryCache.redisDB;
70
+ settings.memoryCache.redisHost = ( process.env.TI_MEMORY_CACHE_REDIS_HOST !== undefined ) ? process.env.TI_MEMORY_CACHE_REDIS_HOST : settings.memoryCache.redisHost;
71
+ settings.memoryCache.redisPort = ( process.env.TI_MEMORY_CACHE_REDIS_PORT !== undefined ) ? Number( process.env.TI_MEMORY_CACHE_REDIS_PORT ) : settings.memoryCache.redisPort;
72
+ settings.memoryCache.retryMaxAttempts = ( process.env.TI_MEMORY_CACHE_RETRY_MAX_ATTEMPTS !== undefined ) ? Number( process.env.TI_MEMORY_CACHE_RETRY_MAX_ATTEMPTS ) : settings.memoryCache.retryMaxAttempts;
73
+ settings.memoryCache.retryMaxInterval = ( process.env.TI_MEMORY_CACHE_RETRY_MAX_INTERVAL !== undefined ) ? Number( process.env.TI_MEMORY_CACHE_RETRY_MAX_INTERVAL ) : settings.memoryCache.retryMaxInterval;
74
+ settings.memoryCache.user = ( process.env.TI_MEMORY_CACHE_USER !== undefined ) ? process.env.TI_MEMORY_CACHE_USER : settings.memoryCache.user;
75
+ }
76
+ if ( settings.messageExchange ) {
77
+ settings.messageExchange.securityHashEnabled = ( process.env.TI_MESSAGE_EXCHANGE_SECURITY_HASH_ENABLED !== undefined ) ? tools.toBool( process.env.TI_MESSAGE_EXCHANGE_SECURITY_HASH_ENABLED ) : settings.messageExchange.securityHashEnabled;
78
+ settings.messageExchange.securityHashKey = ( process.env.TI_MESSAGE_EXCHANGE_SECURITY_HASH_KEY !== undefined ) ? process.env.TI_MESSAGE_EXCHANGE_SECURITY_HASH_KEY : settings.messageExchange.securityHashKey;
79
+ settings.messageExchange.traceLogEnabled = ( process.env.TI_MESSAGE_EXCHANGE_TRACE_LOG_ENABLED !== undefined ) ? tools.toBool( process.env.TI_MESSAGE_EXCHANGE_TRACE_LOG_ENABLED ) : settings.messageExchange.traceLogEnabled;
80
+ }
81
+
82
+ // Make sure GCloud is enabled before trying to set it up:
83
+ if ( tools.toBool( process.env.TI_GCLOUD_ENABLED ) === true && settings.gcloudIntegration ) {
84
+ settings.gcloudIntegration.apiKey = ( process.env.TI_GCLOUD_API_KEY !== undefined ) ? process.env.TI_GCLOUD_API_KEY : settings.gcloudIntegration.apiKey;
85
+ settings.gcloudIntegration.projectID = ( process.env.TI_GCLOUD_PROJECT_ID !== undefined ) ? process.env.TI_GCLOUD_PROJECT_ID : settings.gcloudIntegration.projectID;
86
+ }
87
+
88
+ settings.operationMode = process.env.NODE_ENV || settings.operationMode;
89
+
90
+ // Prevent further modifications to the settings object:
91
+ tools.deepFreeze( settings );
92
+
93
+ /**
94
+ * A standard getter method for fetching a setting.
95
+ *
96
+ * @method
97
+ * @param {string|TiSetting} setting Specifies either a dot-separated JSON path of the setting, or is a Setting from the settings enum.
98
+ * @param {*} [defaultValue] The default value to be returned if the setting is not found in the current configuration.
99
+ * @returns {*}
100
+ * @public
101
+ */
102
+ module.exports.getSetting = ( setting, defaultValue ) => {
103
+ return _.get( settings, setting, defaultValue );
201
104
  };
@@ -29,6 +29,7 @@ const exceptionCodeEnum = tools.enum( {
29
29
  E_GEN_INVALID_ARGUMENT_TYPE: [ 1007, "invalid argument type", "The provided argument is not of the expected type." ],
30
30
  E_GEN_NOT_INITIALIZED: [ 1008, "not initialized", "The invoked framework component is not initialized." ],
31
31
  E_GEN_UNALLOWED_OVERRIDE: [ 1009, "unallowed override", "Attempt to override a protected or private method or property detected." ],
32
+ E_GEN_NOT_IMPLEMENTED: [ 1010, "not implemented", "The requested functionality is not yet implemented." ],
32
33
  /** Security & Administration exceptions - codes under 2xxx */
33
34
  E_SEC_INVALID_AUTH_TOKEN: [ 2000, "invalid auth token", "Invalid authorization token provided." ],
34
35
  E_SEC_INVALID_EXPIRED_SESSION: [ 2001, "invalid or expired session", "Invalid or expired session encountered." ],
@@ -56,9 +57,11 @@ const exceptionCodeEnum = tools.enum( {
56
57
  E_WEB_INVALID_REQUEST_FORMAT: [ 4006, "invalid request format", "The request format is not recognized or not supported." ],
57
58
  E_WEB_INVALID_REQUEST_CONTENT_TYPE: [ 4007, "invalid request content type", "The request content type is not recognized or not supported." ],
58
59
  E_WEB_INVALID_REQUEST_CONTENT_LENGTH: [ 4008, "invalid request content length", "The request content length is not recognized or not supported." ],
59
- E_WEB_INVALID_REQUEST_CONTENT_ENCODING: [ 4009, "invalid request content encoding", "The request content encoding is not recognized or not supported." ]
60
+ E_WEB_INVALID_REQUEST_CONTENT_ENCODING: [ 4009, "invalid request content encoding", "The request content encoding is not recognized or not supported." ],
61
+ /** Application exceptions - codes under 5xxx */
62
+ E_APP_RESOURCE_NOT_FOUND: [ 5004, "resource not found", "The requested resource cannot be found. See details for more information." ],
63
+ E_APP_SERVICE_ERROR: [ 5005, "app service error", "The application service encountered an error. See details for more information." ]
60
64
  } );
61
-
62
65
  module.exports.exceptionCode = exceptionCodeEnum;
63
66
 
64
67
  /**
@@ -134,18 +137,17 @@ const httpCodeEnum = tools.enum( {
134
137
  C_510: [ 510, "Not Extended", "Further extensions to the request are required for the server to fulfil it." ],
135
138
  C_511: [ 511, "Network Authentication Required", "The client needs to authenticate to gain network access. Intended for use by intercepting proxies used to control access to the network." ]
136
139
  } );
137
-
138
140
  module.exports.httpCode = httpCodeEnum;
139
141
 
140
142
  const labelPath = "system.exceptions.";
141
143
 
142
144
  /**
143
- * Represents an exception.
145
+ * Represents an any-purpose exception.
144
146
  *
145
- * @class Exception
147
+ * @class TiException
146
148
  * @public
147
149
  */
148
- class Exception {
150
+ class TiException {
149
151
 
150
152
  #id;
151
153
  #code;
@@ -266,7 +268,7 @@ class Exception {
266
268
  }
267
269
 
268
270
  /**
269
- * Extracts the essential information about the Exception and returns it as JSON.
271
+ * Extracts the essential information about the {@link TiException} and returns it as JSON.
270
272
  *
271
273
  * @method
272
274
  * @param {boolean} [includeData=true] Whether to include the data property in the output.
@@ -292,38 +294,48 @@ class Exception {
292
294
 
293
295
  /**
294
296
  * Used to raise an exception from the provided source.
297
+ * <br/>
298
+ * NOTE: Custom numeric exception IDs are not supported when 'httpCode' is omitted!
295
299
  *
296
300
  * @method
297
- * @param {Error|TiExceptionCode|Exception} source Could be a standard JS Error, an ExceptionCode, or another Exception (in which case it will be raised further).
301
+ * @param {Error|TiExceptionCode|TiException} source Could be a standard JS Error, an ExceptionCode, or another TiException (in which case it will be raised further).
298
302
  * @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.
299
- * @param {string} [exceptionID] Should be used only in cases when we have a recognizable exception ID beforehand. Should not be entered otherwise!
300
- * @returns {Exception}
303
+ * @param {string} [exceptionID=undefined] Should be used only in cases when we have a recognizable exception ID beforehand. Should not be entered otherwise!
304
+ * @param {TiHttpCode} [httpCode=undefined] An optional HTTP code in case this exception needs to be propagated to a web-application frontend. If provided, this will
305
+ * override any preexisting HTTP code in 'source'!
306
+ * @returns {TiException}
301
307
  * @public
302
308
  */
303
- module.exports.raise = ( source, data, exceptionID ) => {
304
- /** @type Exception */
309
+ module.exports.raise = ( source, data, exceptionID = undefined, httpCode = undefined ) => {
310
+ /** @type TiException */
305
311
  let exception;
306
312
 
313
+ // Support flexible argument passing: if exceptionID is a number (likely an HTTP code) and httpCode is missing, swap them:
314
+ if ( typeof exceptionID === "number" && httpCode === undefined ) {
315
+ httpCode = exceptionID;
316
+ exceptionID = undefined;
317
+ }
318
+
307
319
  if ( source instanceof Error ) {
308
- exception = new Exception( exceptionID || tools.getUUID(), exceptionCodeEnum.E_GEN_JS_INTERNAL_ERROR, tools.errorToJSON( source ) );
309
- } else if ( source instanceof Exception ) {
320
+ exception = new TiException( exceptionID || tools.getUUID(), exceptionCodeEnum.E_GEN_JS_INTERNAL_ERROR, tools.errorToJSON( source ) );
321
+ } else if ( source instanceof TiException ) {
310
322
  exception = source;
311
323
  } else if ( _.isString( source ) ) {
312
- exception = new Exception( exceptionID || tools.getUUID(), exceptionCodeEnum.E_GEN_JS_INTERNAL_ERROR, {
324
+ exception = new TiException( exceptionID || tools.getUUID(), exceptionCodeEnum.E_GEN_JS_INTERNAL_ERROR, {
313
325
  message: source
314
326
  } );
315
327
  } else if ( _.isObjectLike( source ) ) {
316
- exception = new Exception(
328
+ exception = new TiException(
317
329
  exceptionID || ( source.id || tools.getUUID() ),
318
330
  source.code || exceptionCodeEnum.E_GEN_JS_INTERNAL_ERROR,
319
331
  source.data,
320
332
  source.description
321
333
  );
322
- if ( httpCodeEnum.contains( source.httpCode ) ) {
334
+ if ( source.httpCode && httpCodeEnum.contains( source.httpCode ) ) {
323
335
  exception.httpCode = source.httpCode;
324
336
  }
325
337
  } else {
326
- exception = new Exception( exceptionID || tools.getUUID(), ( exceptionCodeEnum.contains( source ) ) ? source : exceptionCodeEnum.E_UNKNOWN_ERROR );
338
+ exception = new TiException( exceptionID || tools.getUUID(), ( exceptionCodeEnum.contains( source ) ) ? source : exceptionCodeEnum.E_UNKNOWN_ERROR );
327
339
  }
328
340
 
329
341
  // Merge the default exception data with the additional one if it's provided:
@@ -336,11 +348,15 @@ module.exports.raise = ( source, data, exceptionID ) => {
336
348
  exception.data = tools.decycle( exception.data );
337
349
  }
338
350
 
351
+ if ( httpCode && httpCodeEnum.contains( httpCode ) ) {
352
+ exception.httpCode = httpCode;
353
+ }
354
+
339
355
  return exception;
340
356
  };
341
357
 
342
358
  /**
343
- * Verifies if the passed object is an Exception.
359
+ * Verifies if the passed object is a {@link TiException}.
344
360
  *
345
361
  * @method
346
362
  * @param {*} object
@@ -348,5 +364,5 @@ module.exports.raise = ( source, data, exceptionID ) => {
348
364
  * @public
349
365
  */
350
366
  module.exports.isException = ( object ) => {
351
- return ( object instanceof Exception );
367
+ return ( object instanceof TiException );
352
368
  };
@@ -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-2025 Boris Kostadinov <kostadinov.boris@gmail.com>
3
+ * Copyright © 2021-2026 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/>.
@@ -18,6 +18,7 @@ const defaultEmptyLabel = "!!! label not found !!!";
18
18
  *
19
19
  * @readonly
20
20
  * @enum {string}
21
+ * @typedef {string} TiLocalizationLanguage
21
22
  */
22
23
  const localizationLanguageEnum = tools.enum( {
23
24
  // A:
@@ -227,24 +228,8 @@ const localizationLanguageEnum = tools.enum( {
227
228
  ZHUANG: [ "za", "Zhuang", "Zhuang" ],
228
229
  ZULU: [ "zu", "Zulu", "Zulu" ]
229
230
  } );
230
-
231
- /**
232
- * @typedef {string} TiLocalizationLanguage
233
- */
234
231
  module.exports.localizationLanguage = localizationLanguageEnum;
235
232
 
236
- /**
237
- * The key of this object is the language code, and the value is the textual representation of the label.
238
- *
239
- * @typedef {Object<TiLocalizationLanguage, string>} TiLocalizedLabel
240
- */
241
-
242
- /**
243
- * A nested labels tree where intermediate nodes are objects and leaf nodes are language-to-text maps.
244
- *
245
- * @typedef {Object<string, TiLocalizedLabel | TiLabelsTree>} TiLabelsTree
246
- */
247
-
248
233
  /** @type {TiLabelsTree} */
249
234
  const labels = require( "#labels" );
250
235
 
package/utils/logger.js CHANGED
@@ -16,6 +16,7 @@ const localization = require( "#localization" );
16
16
  *
17
17
  * @readonly
18
18
  * @enum {number}
19
+ * @typedef {number} TiLogSeverity
19
20
  */
20
21
  const logSeverityEnum = tools.enum( {
21
22
  DEFAULT: [ 0, "default", "The log entry has no assigned severity level." ],
@@ -28,10 +29,6 @@ const logSeverityEnum = tools.enum( {
28
29
  ALERT: [ 700, "alert", "A person must take an action immediately." ],
29
30
  EMERGENCY: [ 800, "emergency", "One or more systems are unusable." ]
30
31
  } );
31
-
32
- /**
33
- * @typedef {number} TiLogSeverity
34
- */
35
32
  module.exports.logSeverity = logSeverityEnum;
36
33
 
37
34
  /**
@@ -46,10 +43,10 @@ module.exports.getSeverityName = ( severity ) => {
46
43
  };
47
44
 
48
45
  /**
49
- * Used to extract information from an Exception and convert it to a loggable data object.
46
+ * Used to extract information from a {@link TiException} and convert it to a loggable data object.
50
47
  *
51
48
  * @method
52
- * @param {Exception} exception
49
+ * @param {TiException} exception
53
50
  * @returns {{description, details: (*|undefined), exceptionID}}
54
51
  * @private
55
52
  */
@@ -66,8 +63,8 @@ const exceptionToLog = ( exception ) => {
66
63
  *
67
64
  * @method
68
65
  * @param {string} message The primary log message.
69
- * @param {TiLogSeverity} [level=DEFAULT] The log severity level. If the current log filtering setting is higher than this then the log entry will be ignored.
70
- * @param {Object|Error|Exception} [data={}] Optional JSON data containing details of the log entry.
66
+ * @param {TiLogSeverity} [level=DEFAULT] The log severity level. If the current log filtering setting is higher than this, then the log entry will be ignored.
67
+ * @param {Object|Error|TiException} [data={}] Optional JSON data containing details of the log entry.
71
68
  * @param {string} [thread='main'] The logging thread to which the log entry belongs.
72
69
  * @public
73
70
  */
package/utils/tools.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-2025 Boris Kostadinov <kostadinov.boris@gmail.com>
3
+ * Copyright © 2021-2026 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/>.
@@ -9,21 +9,6 @@
9
9
  const _ = require( "lodash" );
10
10
  const crypto = require( "node:crypto" );
11
11
 
12
- /**
13
- * @typedef {Object} TiEnumValue
14
- * @property {number|string} value
15
- * @property {string} name
16
- * @property {string} [description]
17
- */
18
-
19
- /**
20
- * @typedef {Object} TiEnum
21
- * @property {Object.<number|string,TiEnumValue>} properties
22
- * @property {function( (number|string), [string] ): (string|undefined)} name
23
- * @property {function( (number|string), [string] ): (string|undefined)} description
24
- * @property {function( (number|string) ): boolean} contains
25
- */
26
-
27
12
  /**
28
13
  * Used to generate and return new UUID.
29
14
  *
@@ -41,7 +26,7 @@ module.exports.getUUID = () => {
41
26
  * @method
42
27
  * @param {Object} object
43
28
  * @param {WeakSet} [seen]
44
- * @return {Object}
29
+ * @returns {Object}
45
30
  * @public
46
31
  */
47
32
  module.exports.deepFreeze = ( object, seen = new WeakSet() ) => {
@@ -367,7 +352,7 @@ module.exports.decycle = ( object, replacer ) => {
367
352
  * replaced with references to the value found by the PATH. This will restore cycles. The object will be mutated.
368
353
  *
369
354
  * The eval function is used to locate the values described by a PATH. The root object is kept in a $ variable. A
370
- * regular expression is used to assure that the PATH is extremely well-formed. The regexp contains nested quantifiers.
355
+ * regular expression is used to ensure that the PATH is extremely well-formed. The regexp contains nested quantifiers.
371
356
  * That has been known to have extremely bad performance problems on some browsers for very long strings. A PATH is
372
357
  * expected to be reasonably short. A PATH is allowed to belong to a very restricted subset of Goessner's JSONPath.
373
358
  *
@@ -455,7 +440,7 @@ module.exports.isJsonString = ( string ) => {
455
440
  };
456
441
 
457
442
  /**
458
- * Use this to parse any JSON string into JSON object for internal system purposes as it ensures to restore any
443
+ * Use this to parse any JSON string into a JSON object for internal system purposes as it ensures to restore any
459
444
  * circular dependencies obscured with 'stringifyJSON'.
460
445
  *
461
446
  * @method
@@ -474,7 +459,7 @@ module.exports.parseJSON = ( value ) => {
474
459
 
475
460
  /**
476
461
  * Use this to decompose a JSON object into a sorted string. The values will be ordered alphabetically and combined with
477
- * their keys, where applicable, starting from the bottom and moving up. Null or undefined values will be ignored and
462
+ * their keys, where applicable, starting from the bottom and moving up. Null or undefined values will be ignored, and
478
463
  * their keys will not be included in the final string.
479
464
  *
480
465
  * @param {Object} input