@ti-engine/core 1.6.1 → 1.7.2
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 +383 -364
- package/LICENSE.md +321 -321
- package/README.md +597 -548
- package/bin/localization/labels.json +122 -122
- package/bin/settings.json +41 -41
- package/bin/start-instance.js +164 -156
- package/components/auditing.js +191 -191
- package/components/connection-observer.js +72 -72
- package/components/definitions.types.js +248 -248
- package/components/exchange/default/default-message-exchange.js +136 -136
- package/components/exchange/default/default-message-receiver.js +101 -101
- package/components/exchange/default/default-message-sender.js +100 -100
- package/components/exchange/message-dispatcher.js +168 -168
- package/components/exchange/message-exchange.js +449 -449
- package/components/exchange/message-handler.js +235 -234
- package/components/exchange/message-memory-cache.js +190 -190
- package/components/exchange/message-observer.js +126 -126
- package/components/exchange/message-receiver.js +181 -181
- package/components/exchange/message-sender.js +143 -143
- package/components/exchange/message-tracer.js +212 -212
- package/components/service-caller.js +370 -370
- package/components/service-consumer.js +131 -131
- package/components/service-executor.js +278 -278
- package/components/service-instance.js +316 -316
- package/components/service-provider.js +251 -251
- package/integrations/redis-integration.js +591 -591
- package/package.json +89 -90
- package/utils/cache.js +772 -772
- package/utils/config.js +103 -103
- package/utils/exceptions.js +368 -368
- package/utils/localization.js +298 -298
- package/utils/logger.js +82 -82
- package/utils/tools.js +632 -632
package/utils/exceptions.js
CHANGED
|
@@ -1,369 +1,369 @@
|
|
|
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
|
-
* Enum for listing all system-recognized exceptions.
|
|
14
|
-
*
|
|
15
|
-
* @readonly
|
|
16
|
-
* @enum {number}
|
|
17
|
-
* @typedef {number} TiExceptionCode
|
|
18
|
-
*/
|
|
19
|
-
const exceptionCodeEnum = tools.enum( {
|
|
20
|
-
E_UNKNOWN_ERROR: [ 0, "unknown error", "Unidentified error encountered or unrecognized exception code provided." ],
|
|
21
|
-
/** General exceptions - codes under 1xxx */
|
|
22
|
-
E_GEN_JS_INTERNAL_ERROR: [ 1000, "js internal error", "Error thrown by internal JS source." ],
|
|
23
|
-
E_GEN_ABSTRACT_CLASS_INIT: [ 1001, "abstract class init", "Attempt to construct an abstract class detected." ],
|
|
24
|
-
E_GEN_ABSTRACT_METHOD_CALL: [ 1002, "abstract method call", "Attempt to call an abstract method detected." ],
|
|
25
|
-
E_GEN_INVALID_SERVICE_DOMAIN_NAME: [ 1003, "invalid service domain name", "Invalid or no service domain name provided at microservice startup." ],
|
|
26
|
-
E_GEN_SYSTEM_CACHE_UNAVAILABLE: [ 1004, "system cache unavailable", "The system cache required for proper engine operation is unavailable." ],
|
|
27
|
-
E_GEN_BAD_SERVICE_HANDLER: [ 1005, "bad service handler", "The provided service handler is not a proper function." ],
|
|
28
|
-
E_GEN_FEATURE_UNSUPPORTED: [ 1006, "feature unsupported", "The requested feature is not supported by current configuration or version." ],
|
|
29
|
-
E_GEN_INVALID_ARGUMENT_TYPE: [ 1007, "invalid argument type", "The provided argument is not of the expected type." ],
|
|
30
|
-
E_GEN_NOT_INITIALIZED: [ 1008, "not initialized", "The invoked framework component is not initialized." ],
|
|
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." ],
|
|
33
|
-
/** Security & Administration exceptions - codes under 2xxx */
|
|
34
|
-
E_SEC_INVALID_AUTH_TOKEN: [ 2000, "invalid auth token", "Invalid authorization token provided." ],
|
|
35
|
-
E_SEC_INVALID_EXPIRED_SESSION: [ 2001, "invalid or expired session", "Invalid or expired session encountered." ],
|
|
36
|
-
E_SEC_UNAUTHORIZED_ACCESS: [ 2002, "unauthorized access", "Attempt for unauthorized access detected." ],
|
|
37
|
-
E_SEC_MESSAGE_TAMPERING_DETECTED: [ 2003, "message tampering detected", "The system detected tampering with the message received via message exchange." ],
|
|
38
|
-
E_SEC_UNRECOGNIZED_AUTH_METHOD: [ 2004, "unrecognized auth method", "The requested authentication method is not recognized or supported." ],
|
|
39
|
-
/** Cross-Application Communication exceptions - codes under 3xxx */
|
|
40
|
-
E_COM_GENERAL_ERROR: [ 3000, "general communication error", "General error during cross-application communication." ],
|
|
41
|
-
E_COM_MESSAGE_SENDER_UNAVAILABLE: [ 3001, "message sender unavailable", "The message sender instance is currently unavailable." ],
|
|
42
|
-
E_COM_SERVICE_EXEC_TIMEOUT: [ 3002, "service exec timeout", "The execution of a service could not complete within the allowed timeout." ],
|
|
43
|
-
E_COM_SERVICE_NOT_REGISTERED: [ 3003, "service not registered", "The specified service is not found in the service registry." ],
|
|
44
|
-
E_COM_SERVICE_NOT_FOUND: [ 3004, "service not found", "The specified service is not found in the service definition interface." ],
|
|
45
|
-
E_COM_SERVICE_HANDLER_NOT_FOUND: [ 3005, "service handler not found", "No handler found in the interface for the specified service or service version." ],
|
|
46
|
-
E_COM_MESSAGE_RECEIVER_UNAVAILABLE: [ 3006, "message receiver unavailable", "The message receiver instance is currently unavailable." ],
|
|
47
|
-
E_COM_MESSAGE_EXCHANGE_BROKEN: [ 3007, "message exchange broken", "The message exchange is irrevocably broken and cannot be used any longer." ],
|
|
48
|
-
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." ],
|
|
49
|
-
E_COM_RETRY_ATTEMPTS_EXCEEDED: [ 3010, "retry attempts exceeded", "Connection retry attempts exceeded the configured limit." ],
|
|
50
|
-
/** Web server exceptions - codes under 4xxx */
|
|
51
|
-
E_WEB_INVALID_REQUEST_METHOD: [ 4000, "invalid request method", "The request method is not recognized or not supported." ],
|
|
52
|
-
E_WEB_INVALID_REQUEST_URI: [ 4001, "invalid request uri", "The request URI is not recognized or not supported." ],
|
|
53
|
-
E_WEB_INVALID_REQUEST_BODY: [ 4002, "invalid request body", "The request body is not recognized or not supported." ],
|
|
54
|
-
E_WEB_INVALID_REQUEST_QUERY: [ 4003, "invalid request query", "The request query is not recognized or not supported." ],
|
|
55
|
-
E_WEB_INVALID_REQUEST_HEADERS: [ 4004, "invalid request headers", "The request headers are not recognized or not supported." ],
|
|
56
|
-
E_WEB_INVALID_REQUEST_PARAMETERS: [ 4005, "invalid request parameters", "The request parameters are not recognized or not supported." ],
|
|
57
|
-
E_WEB_INVALID_REQUEST_FORMAT: [ 4006, "invalid request format", "The request format is not recognized or not supported." ],
|
|
58
|
-
E_WEB_INVALID_REQUEST_CONTENT_TYPE: [ 4007, "invalid request content type", "The request content type is not recognized or not supported." ],
|
|
59
|
-
E_WEB_INVALID_REQUEST_CONTENT_LENGTH: [ 4008, "invalid request content length", "The request content length 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." ],
|
|
64
|
-
E_APP_RESOURCE_ALREADY_EXISTS: [ 5006, "resource already exists", "The resource cannot be created because it already exists. See details for more information." ]
|
|
65
|
-
} );
|
|
66
|
-
module.exports.exceptionCode = exceptionCodeEnum;
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Enum for listing all HTTP codes.
|
|
70
|
-
*
|
|
71
|
-
* @readonly
|
|
72
|
-
* @enum {number}
|
|
73
|
-
* @typedef {number} TiHttpCode
|
|
74
|
-
*/
|
|
75
|
-
const httpCodeEnum = tools.enum( {
|
|
76
|
-
/** 1xx informational response */
|
|
77
|
-
C_100: [ 100, "Continue", "The server has received the request headers and the client should proceed to send the request body." ],
|
|
78
|
-
C_101: [ 101, "Switching Protocols", "The requester has asked the server to switch protocols and the server has agreed to do so." ],
|
|
79
|
-
C_102: [ 102, "Processing", "This code indicates that the server has received and is processing the request, but no response is available yet." ],
|
|
80
|
-
C_103: [ 103, "Early Hints", "Used to return some response headers before final HTTP message." ],
|
|
81
|
-
/** 2xx success */
|
|
82
|
-
C_200: [ 200, "OK", "Standard response for successful HTTP requests." ],
|
|
83
|
-
C_201: [ 201, "Created", "The request has been fulfilled, resulting in the creation of a new resource." ],
|
|
84
|
-
C_202: [ 202, "Accepted", "The request has been accepted for processing, but the processing has not been completed." ],
|
|
85
|
-
C_203: [ 203, "Non-Authoritative Information", "The server is a transforming proxy that received a 200 OK from its origin, but is returning a modified version of the origin's response." ],
|
|
86
|
-
C_204: [ 204, "No Content", "The server successfully processed the request, and is not returning any content." ],
|
|
87
|
-
C_205: [ 205, "Reset Content", "The server successfully processed the request, asks that the requester reset its document view, and is not returning any content." ],
|
|
88
|
-
C_206: [ 206, "Partial Content", "The server is delivering only part of the resource (byte serving) due to a range header sent by the client." ],
|
|
89
|
-
C_207: [ 207, "Multi-Status", "The message body that follows is by default an XML message and can contain a number of separate response codes, depending on how many sub-requests were made." ],
|
|
90
|
-
C_208: [ 208, "Already Reported", "The members of a DAV binding have already been enumerated in a preceding part of the (multistatus) response, and are not being included again." ],
|
|
91
|
-
C_226: [ 226, "IM Used", "The server has fulfilled a request for the resource, and the response is a representation of the result of one or more instance-manipulations applied to the current instance." ],
|
|
92
|
-
/** 3xx redirection */
|
|
93
|
-
C_300: [ 300, "Multiple Choices", "Indicates multiple options for the resource from which the client may choose." ],
|
|
94
|
-
C_301: [ 301, "Moved Permanently", "This and all future requests should be directed to the given URI." ],
|
|
95
|
-
C_302: [ 302, "Found", "Tells the client to look at (browse to) another URL." ],
|
|
96
|
-
C_303: [ 303, "See Other", "The response to the request can be found under another URI using the GET method." ],
|
|
97
|
-
C_304: [ 304, "Not Modified", "Indicates that the resource has not been modified since the version specified by the request headers If-Modified-Since or If-None-Match." ],
|
|
98
|
-
C_307: [ 307, "Temporary Redirect", "In this case, the request should be repeated with another URI; however, future requests should still use the original URI." ],
|
|
99
|
-
C_308: [ 308, "Permanent Redirect", "This and all future requests should be directed to the given URI. 308 parallels the behavior of 301, but does not allow the HTTP method to change." ],
|
|
100
|
-
/** 4xx client errors */
|
|
101
|
-
C_400: [ 400, "Bad Request", "The server cannot or will not process the request due to an apparent client error." ],
|
|
102
|
-
C_401: [ 401, "Unauthorized", "Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet been provided." ],
|
|
103
|
-
C_403: [ 403, "Forbidden", "The request contained valid data and was understood by the server, but the server is refusing action. This may be due to the user not having the necessary permissions for a resource or needing an account of some sort, or attempting a prohibited action." ],
|
|
104
|
-
C_404: [ 404, "Not Found", "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible." ],
|
|
105
|
-
C_405: [ 405, "Method Not Allowed", "A request method is not supported for the requested resource; for example, a GET request on a form that requires data to be presented via POST, or a PUT request on a read-only resource." ],
|
|
106
|
-
C_406: [ 406, "Not Acceptable", "The requested resource is capable of generating only content not acceptable according to the Accept headers sent in the request." ],
|
|
107
|
-
C_407: [ 407, "Proxy Authentication Required", "The client must first authenticate itself with the proxy." ],
|
|
108
|
-
C_408: [ 408, "Request Timeout", "The server timed out waiting for the request." ],
|
|
109
|
-
C_409: [ 409, "Conflict", "Indicates that the request could not be processed because of conflict in the current state of the resource, such as an edit conflict between multiple simultaneous updates." ],
|
|
110
|
-
C_410: [ 410, "Gone", "Indicates that the resource requested was previously in use but is no longer available and will not be available again." ],
|
|
111
|
-
C_411: [ 411, "Length Required", "The request did not specify the length of its content, which is required by the requested resource." ],
|
|
112
|
-
C_412: [ 412, "Precondition Failed", "The server does not meet one of the preconditions that the requester put on the request header fields." ],
|
|
113
|
-
C_413: [ 413, "Payload Too Large", "The request is larger than the server is willing or able to process." ],
|
|
114
|
-
C_414: [ 414, "URI Too Long", "The URI provided was too long for the server to process." ],
|
|
115
|
-
C_415: [ 415, "Unsupported Media Type", "The request entity has a media type which the server or resource does not support." ],
|
|
116
|
-
C_416: [ 416, "Range Not Satisfiable", "The client has asked for a portion of the file (byte serving), but the server cannot supply that portion." ],
|
|
117
|
-
C_417: [ 417, "Expectation Failed", "The server cannot meet the requirements of the Expect request-header field." ],
|
|
118
|
-
C_421: [ 421, "Misdirected Request", "The request was directed at a server that is not able to produce a response (for example because of connection reuse)." ],
|
|
119
|
-
C_422: [ 422, "Unprocessable Content", "The request was well-formed (i.e., syntactically correct) but could not be processed." ],
|
|
120
|
-
C_423: [ 423, "Locked", "The resource that is being accessed is locked." ],
|
|
121
|
-
C_424: [ 424, "Failed Dependency", "The request failed because it depended on another request and that request failed." ],
|
|
122
|
-
C_425: [ 425, "Too Early", "Indicates that the server is unwilling to risk processing a request that might be replayed." ],
|
|
123
|
-
C_426: [ 426, "Upgrade Required", "The client should switch to a different protocol such as TLS/1.3, given in the Upgrade header field." ],
|
|
124
|
-
C_428: [ 428, "Precondition Required", "The origin server requires the request to be conditional." ],
|
|
125
|
-
C_429: [ 429, "Too Many Requests", "The user has sent too many requests in a given amount of time. Intended for use with rate-limiting schemes." ],
|
|
126
|
-
C_431: [ 431, "Request Header Fields Too Large", "The server is unwilling to process the request because either an individual header field, or all the header fields collectively, are too large." ],
|
|
127
|
-
C_451: [ 451, "Unavailable For Legal Reasons", "A server operator has received a legal demand to deny access to a resource or to a set of resources that includes the requested resource." ],
|
|
128
|
-
/** 5xx server errors */
|
|
129
|
-
C_500: [ 500, "Internal Server Error", "A generic error message, given when an unexpected condition was encountered and no more specific message is suitable." ],
|
|
130
|
-
C_501: [ 501, "Not Implemented", "The server either does not recognize the request method, or it lacks the ability to fulfil the request." ],
|
|
131
|
-
C_502: [ 502, "Bad Gateway", "The server was acting as a gateway or proxy and received an invalid response from the upstream server." ],
|
|
132
|
-
C_503: [ 503, "Service Unavailable", "The server cannot handle the request (because it is overloaded or down for maintenance)." ],
|
|
133
|
-
C_504: [ 504, "Gateway Timeout", "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server." ],
|
|
134
|
-
C_505: [ 505, "HTTP Version Not Supported", "The server does not support the HTTP version used in the request." ],
|
|
135
|
-
C_506: [ 506, "Variant Also Negotiates", "Transparent content negotiation for the request results in a circular reference." ],
|
|
136
|
-
C_507: [ 507, "Insufficient Storage", "The server is unable to store the representation needed to complete the request." ],
|
|
137
|
-
C_508: [ 508, "Loop Detected", "The server detected an infinite loop while processing the request." ],
|
|
138
|
-
C_510: [ 510, "Not Extended", "Further extensions to the request are required for the server to fulfil it." ],
|
|
139
|
-
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." ]
|
|
140
|
-
} );
|
|
141
|
-
module.exports.httpCode = httpCodeEnum;
|
|
142
|
-
|
|
143
|
-
const labelPath = "system.exceptions.";
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Represents an any-purpose exception.
|
|
147
|
-
*
|
|
148
|
-
* @class TiException
|
|
149
|
-
* @public
|
|
150
|
-
*/
|
|
151
|
-
class TiException {
|
|
152
|
-
|
|
153
|
-
#id;
|
|
154
|
-
#code;
|
|
155
|
-
#httpCode;
|
|
156
|
-
#label;
|
|
157
|
-
#description;
|
|
158
|
-
#data;
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* @constructor
|
|
162
|
-
* @param {string} id The unique ID to be assigned to this exception.
|
|
163
|
-
* @param {TiExceptionCode} exceptionCode An unique exception identifier. If this is not recognized, the default error code will be used instead.
|
|
164
|
-
* @param {Object} [data={}] Any additional data to insert into the exception.
|
|
165
|
-
* @param {string} [description=undefined] Description of the exception.
|
|
166
|
-
*/
|
|
167
|
-
constructor( id, exceptionCode, data, description ) {
|
|
168
|
-
exceptionCode = exceptionCodeEnum.contains( exceptionCode ) ? exceptionCode : exceptionCodeEnum.E_UNKNOWN_ERROR;
|
|
169
|
-
|
|
170
|
-
this.#id = id;
|
|
171
|
-
this.#code = exceptionCode;
|
|
172
|
-
this.#label = labelPath + String( exceptionCode );
|
|
173
|
-
this.#description = description || exceptionCodeEnum.description( exceptionCode );
|
|
174
|
-
this.#data = data || {};
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/* Public interface */
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Unique identifier of the exception instance. Can be used for tracing problems with customer support cases.
|
|
181
|
-
*
|
|
182
|
-
* @property
|
|
183
|
-
* @returns {string}
|
|
184
|
-
* @public
|
|
185
|
-
*/
|
|
186
|
-
get id() {
|
|
187
|
-
return this.#id;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Identifier code of the exception type.
|
|
192
|
-
*
|
|
193
|
-
* @property
|
|
194
|
-
* @returns {TiExceptionCode}
|
|
195
|
-
* @public
|
|
196
|
-
*/
|
|
197
|
-
get code() {
|
|
198
|
-
return this.#code;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* HTTP error code if relevant.
|
|
203
|
-
*
|
|
204
|
-
* @property
|
|
205
|
-
* @returns {TiHttpCode}
|
|
206
|
-
* @public
|
|
207
|
-
*/
|
|
208
|
-
get httpCode() {
|
|
209
|
-
return this.#httpCode;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* HTTP error code if relevant.
|
|
214
|
-
*
|
|
215
|
-
* @property
|
|
216
|
-
* @param {TiHttpCode} httpCode
|
|
217
|
-
* @public
|
|
218
|
-
*/
|
|
219
|
-
set httpCode( httpCode ) {
|
|
220
|
-
if ( httpCodeEnum.contains( httpCode ) ) {
|
|
221
|
-
this.#httpCode = httpCode;
|
|
222
|
-
} else {
|
|
223
|
-
this.#httpCode = undefined;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Localized label identifier.
|
|
229
|
-
*
|
|
230
|
-
* @property
|
|
231
|
-
* @returns {string}
|
|
232
|
-
* @public
|
|
233
|
-
*/
|
|
234
|
-
get label() {
|
|
235
|
-
return this.#label;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Description or additional technical information that is NOT localized.
|
|
240
|
-
*
|
|
241
|
-
* @property
|
|
242
|
-
* @returns {string}
|
|
243
|
-
* @public
|
|
244
|
-
*/
|
|
245
|
-
get description() {
|
|
246
|
-
return this.#description;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* JSON containing any additional data that has relevance for the exception. Can be converted JavaScript {@link Error} object as well.
|
|
251
|
-
*
|
|
252
|
-
* @property
|
|
253
|
-
* @returns {Object}
|
|
254
|
-
* @public
|
|
255
|
-
*/
|
|
256
|
-
get data() {
|
|
257
|
-
return this.#data;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* JSON containing any additional data that has relevance for the exception. Can be converted JavaScript {@link Error} object as well.
|
|
262
|
-
*
|
|
263
|
-
* @property
|
|
264
|
-
* @param {Object} data
|
|
265
|
-
* @public
|
|
266
|
-
*/
|
|
267
|
-
set data( data ) {
|
|
268
|
-
this.#data = data;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Extracts the essential information about the {@link TiException} and returns it as JSON.
|
|
273
|
-
*
|
|
274
|
-
* @method
|
|
275
|
-
* @param {boolean} [includeData=true] Whether to include the data property in the output.
|
|
276
|
-
* @returns {Object}
|
|
277
|
-
* @public
|
|
278
|
-
*/
|
|
279
|
-
asJSON( includeData = true ) {
|
|
280
|
-
let json = {
|
|
281
|
-
id: this.id,
|
|
282
|
-
code: this.code,
|
|
283
|
-
label: this.label,
|
|
284
|
-
description: this.description
|
|
285
|
-
};
|
|
286
|
-
if ( this.#httpCode !== undefined ) {
|
|
287
|
-
json.httpCode = this.#httpCode;
|
|
288
|
-
}
|
|
289
|
-
if ( includeData === true ) {
|
|
290
|
-
json.data = this.#data;
|
|
291
|
-
}
|
|
292
|
-
return json;
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Used to raise an exception from the provided source.
|
|
298
|
-
* <br/>
|
|
299
|
-
* NOTE: Custom numeric exception IDs are not supported when 'httpCode' is omitted!
|
|
300
|
-
*
|
|
301
|
-
* @method
|
|
302
|
-
* @param {Error|TiExceptionCode|TiException} source Could be a standard JS Error, an ExceptionCode, or another TiException (in which case it will be raised further).
|
|
303
|
-
* @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.
|
|
304
|
-
* @param {string} [exceptionID=undefined] Should be used only in cases when we have a recognizable exception ID beforehand. Should not be entered otherwise!
|
|
305
|
-
* @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
|
|
306
|
-
* override any preexisting HTTP code in 'source'!
|
|
307
|
-
* @returns {TiException}
|
|
308
|
-
* @public
|
|
309
|
-
*/
|
|
310
|
-
module.exports.raise = ( source, data, exceptionID = undefined, httpCode = undefined ) => {
|
|
311
|
-
/** @type TiException */
|
|
312
|
-
let exception;
|
|
313
|
-
|
|
314
|
-
// Support flexible argument passing: if exceptionID is a number (likely an HTTP code) and httpCode is missing, swap them:
|
|
315
|
-
if ( typeof exceptionID === "number" && httpCode === undefined ) {
|
|
316
|
-
httpCode = exceptionID;
|
|
317
|
-
exceptionID = undefined;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
if ( source instanceof Error ) {
|
|
321
|
-
exception = new TiException( exceptionID || tools.getUUID(), exceptionCodeEnum.E_GEN_JS_INTERNAL_ERROR, tools.errorToJSON( source ) );
|
|
322
|
-
} else if ( source instanceof TiException ) {
|
|
323
|
-
exception = source;
|
|
324
|
-
} else if ( _.isString( source ) ) {
|
|
325
|
-
exception = new TiException( exceptionID || tools.getUUID(), exceptionCodeEnum.E_GEN_JS_INTERNAL_ERROR, {
|
|
326
|
-
message: source
|
|
327
|
-
} );
|
|
328
|
-
} else if ( _.isObjectLike( source ) ) {
|
|
329
|
-
exception = new TiException(
|
|
330
|
-
exceptionID || ( source.id || tools.getUUID() ),
|
|
331
|
-
source.code || exceptionCodeEnum.E_GEN_JS_INTERNAL_ERROR,
|
|
332
|
-
source.data,
|
|
333
|
-
source.description
|
|
334
|
-
);
|
|
335
|
-
if ( source.httpCode && httpCodeEnum.contains( source.httpCode ) ) {
|
|
336
|
-
exception.httpCode = source.httpCode;
|
|
337
|
-
}
|
|
338
|
-
} else {
|
|
339
|
-
exception = new TiException( exceptionID || tools.getUUID(), ( exceptionCodeEnum.contains( source ) ) ? source : exceptionCodeEnum.E_UNKNOWN_ERROR );
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// Merge the default exception data with the additional one if it's provided:
|
|
343
|
-
if ( data ) {
|
|
344
|
-
exception.data = _.mergeWith( ( exception.data || {} ), _.cloneDeep( data ), ( objValue, srcValue ) => {
|
|
345
|
-
return ( _.isArray( objValue ) ) ? objValue.concat( srcValue ) : undefined;
|
|
346
|
-
} );
|
|
347
|
-
|
|
348
|
-
// Make sure to eliminate any circular dependencies inside the data object (these should never be needed for an error description):
|
|
349
|
-
exception.data = tools.decycle( exception.data );
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
if ( httpCode && httpCodeEnum.contains( httpCode ) ) {
|
|
353
|
-
exception.httpCode = httpCode;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
return exception;
|
|
357
|
-
};
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* Verifies if the passed object is a {@link TiException}.
|
|
361
|
-
*
|
|
362
|
-
* @method
|
|
363
|
-
* @param {*} object
|
|
364
|
-
* @returns {boolean}
|
|
365
|
-
* @public
|
|
366
|
-
*/
|
|
367
|
-
module.exports.isException = ( object ) => {
|
|
368
|
-
return ( object instanceof TiException );
|
|
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
|
+
* Enum for listing all system-recognized exceptions.
|
|
14
|
+
*
|
|
15
|
+
* @readonly
|
|
16
|
+
* @enum {number}
|
|
17
|
+
* @typedef {number} TiExceptionCode
|
|
18
|
+
*/
|
|
19
|
+
const exceptionCodeEnum = tools.enum( {
|
|
20
|
+
E_UNKNOWN_ERROR: [ 0, "unknown error", "Unidentified error encountered or unrecognized exception code provided." ],
|
|
21
|
+
/** General exceptions - codes under 1xxx */
|
|
22
|
+
E_GEN_JS_INTERNAL_ERROR: [ 1000, "js internal error", "Error thrown by internal JS source." ],
|
|
23
|
+
E_GEN_ABSTRACT_CLASS_INIT: [ 1001, "abstract class init", "Attempt to construct an abstract class detected." ],
|
|
24
|
+
E_GEN_ABSTRACT_METHOD_CALL: [ 1002, "abstract method call", "Attempt to call an abstract method detected." ],
|
|
25
|
+
E_GEN_INVALID_SERVICE_DOMAIN_NAME: [ 1003, "invalid service domain name", "Invalid or no service domain name provided at microservice startup." ],
|
|
26
|
+
E_GEN_SYSTEM_CACHE_UNAVAILABLE: [ 1004, "system cache unavailable", "The system cache required for proper engine operation is unavailable." ],
|
|
27
|
+
E_GEN_BAD_SERVICE_HANDLER: [ 1005, "bad service handler", "The provided service handler is not a proper function." ],
|
|
28
|
+
E_GEN_FEATURE_UNSUPPORTED: [ 1006, "feature unsupported", "The requested feature is not supported by current configuration or version." ],
|
|
29
|
+
E_GEN_INVALID_ARGUMENT_TYPE: [ 1007, "invalid argument type", "The provided argument is not of the expected type." ],
|
|
30
|
+
E_GEN_NOT_INITIALIZED: [ 1008, "not initialized", "The invoked framework component is not initialized." ],
|
|
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." ],
|
|
33
|
+
/** Security & Administration exceptions - codes under 2xxx */
|
|
34
|
+
E_SEC_INVALID_AUTH_TOKEN: [ 2000, "invalid auth token", "Invalid authorization token provided." ],
|
|
35
|
+
E_SEC_INVALID_EXPIRED_SESSION: [ 2001, "invalid or expired session", "Invalid or expired session encountered." ],
|
|
36
|
+
E_SEC_UNAUTHORIZED_ACCESS: [ 2002, "unauthorized access", "Attempt for unauthorized access detected." ],
|
|
37
|
+
E_SEC_MESSAGE_TAMPERING_DETECTED: [ 2003, "message tampering detected", "The system detected tampering with the message received via message exchange." ],
|
|
38
|
+
E_SEC_UNRECOGNIZED_AUTH_METHOD: [ 2004, "unrecognized auth method", "The requested authentication method is not recognized or supported." ],
|
|
39
|
+
/** Cross-Application Communication exceptions - codes under 3xxx */
|
|
40
|
+
E_COM_GENERAL_ERROR: [ 3000, "general communication error", "General error during cross-application communication." ],
|
|
41
|
+
E_COM_MESSAGE_SENDER_UNAVAILABLE: [ 3001, "message sender unavailable", "The message sender instance is currently unavailable." ],
|
|
42
|
+
E_COM_SERVICE_EXEC_TIMEOUT: [ 3002, "service exec timeout", "The execution of a service could not complete within the allowed timeout." ],
|
|
43
|
+
E_COM_SERVICE_NOT_REGISTERED: [ 3003, "service not registered", "The specified service is not found in the service registry." ],
|
|
44
|
+
E_COM_SERVICE_NOT_FOUND: [ 3004, "service not found", "The specified service is not found in the service definition interface." ],
|
|
45
|
+
E_COM_SERVICE_HANDLER_NOT_FOUND: [ 3005, "service handler not found", "No handler found in the interface for the specified service or service version." ],
|
|
46
|
+
E_COM_MESSAGE_RECEIVER_UNAVAILABLE: [ 3006, "message receiver unavailable", "The message receiver instance is currently unavailable." ],
|
|
47
|
+
E_COM_MESSAGE_EXCHANGE_BROKEN: [ 3007, "message exchange broken", "The message exchange is irrevocably broken and cannot be used any longer." ],
|
|
48
|
+
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." ],
|
|
49
|
+
E_COM_RETRY_ATTEMPTS_EXCEEDED: [ 3010, "retry attempts exceeded", "Connection retry attempts exceeded the configured limit." ],
|
|
50
|
+
/** Web server exceptions - codes under 4xxx */
|
|
51
|
+
E_WEB_INVALID_REQUEST_METHOD: [ 4000, "invalid request method", "The request method is not recognized or not supported." ],
|
|
52
|
+
E_WEB_INVALID_REQUEST_URI: [ 4001, "invalid request uri", "The request URI is not recognized or not supported." ],
|
|
53
|
+
E_WEB_INVALID_REQUEST_BODY: [ 4002, "invalid request body", "The request body is not recognized or not supported." ],
|
|
54
|
+
E_WEB_INVALID_REQUEST_QUERY: [ 4003, "invalid request query", "The request query is not recognized or not supported." ],
|
|
55
|
+
E_WEB_INVALID_REQUEST_HEADERS: [ 4004, "invalid request headers", "The request headers are not recognized or not supported." ],
|
|
56
|
+
E_WEB_INVALID_REQUEST_PARAMETERS: [ 4005, "invalid request parameters", "The request parameters are not recognized or not supported." ],
|
|
57
|
+
E_WEB_INVALID_REQUEST_FORMAT: [ 4006, "invalid request format", "The request format is not recognized or not supported." ],
|
|
58
|
+
E_WEB_INVALID_REQUEST_CONTENT_TYPE: [ 4007, "invalid request content type", "The request content type is not recognized or not supported." ],
|
|
59
|
+
E_WEB_INVALID_REQUEST_CONTENT_LENGTH: [ 4008, "invalid request content length", "The request content length 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." ],
|
|
64
|
+
E_APP_RESOURCE_ALREADY_EXISTS: [ 5006, "resource already exists", "The resource cannot be created because it already exists. See details for more information." ]
|
|
65
|
+
} );
|
|
66
|
+
module.exports.exceptionCode = exceptionCodeEnum;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Enum for listing all HTTP codes.
|
|
70
|
+
*
|
|
71
|
+
* @readonly
|
|
72
|
+
* @enum {number}
|
|
73
|
+
* @typedef {number} TiHttpCode
|
|
74
|
+
*/
|
|
75
|
+
const httpCodeEnum = tools.enum( {
|
|
76
|
+
/** 1xx informational response */
|
|
77
|
+
C_100: [ 100, "Continue", "The server has received the request headers and the client should proceed to send the request body." ],
|
|
78
|
+
C_101: [ 101, "Switching Protocols", "The requester has asked the server to switch protocols and the server has agreed to do so." ],
|
|
79
|
+
C_102: [ 102, "Processing", "This code indicates that the server has received and is processing the request, but no response is available yet." ],
|
|
80
|
+
C_103: [ 103, "Early Hints", "Used to return some response headers before final HTTP message." ],
|
|
81
|
+
/** 2xx success */
|
|
82
|
+
C_200: [ 200, "OK", "Standard response for successful HTTP requests." ],
|
|
83
|
+
C_201: [ 201, "Created", "The request has been fulfilled, resulting in the creation of a new resource." ],
|
|
84
|
+
C_202: [ 202, "Accepted", "The request has been accepted for processing, but the processing has not been completed." ],
|
|
85
|
+
C_203: [ 203, "Non-Authoritative Information", "The server is a transforming proxy that received a 200 OK from its origin, but is returning a modified version of the origin's response." ],
|
|
86
|
+
C_204: [ 204, "No Content", "The server successfully processed the request, and is not returning any content." ],
|
|
87
|
+
C_205: [ 205, "Reset Content", "The server successfully processed the request, asks that the requester reset its document view, and is not returning any content." ],
|
|
88
|
+
C_206: [ 206, "Partial Content", "The server is delivering only part of the resource (byte serving) due to a range header sent by the client." ],
|
|
89
|
+
C_207: [ 207, "Multi-Status", "The message body that follows is by default an XML message and can contain a number of separate response codes, depending on how many sub-requests were made." ],
|
|
90
|
+
C_208: [ 208, "Already Reported", "The members of a DAV binding have already been enumerated in a preceding part of the (multistatus) response, and are not being included again." ],
|
|
91
|
+
C_226: [ 226, "IM Used", "The server has fulfilled a request for the resource, and the response is a representation of the result of one or more instance-manipulations applied to the current instance." ],
|
|
92
|
+
/** 3xx redirection */
|
|
93
|
+
C_300: [ 300, "Multiple Choices", "Indicates multiple options for the resource from which the client may choose." ],
|
|
94
|
+
C_301: [ 301, "Moved Permanently", "This and all future requests should be directed to the given URI." ],
|
|
95
|
+
C_302: [ 302, "Found", "Tells the client to look at (browse to) another URL." ],
|
|
96
|
+
C_303: [ 303, "See Other", "The response to the request can be found under another URI using the GET method." ],
|
|
97
|
+
C_304: [ 304, "Not Modified", "Indicates that the resource has not been modified since the version specified by the request headers If-Modified-Since or If-None-Match." ],
|
|
98
|
+
C_307: [ 307, "Temporary Redirect", "In this case, the request should be repeated with another URI; however, future requests should still use the original URI." ],
|
|
99
|
+
C_308: [ 308, "Permanent Redirect", "This and all future requests should be directed to the given URI. 308 parallels the behavior of 301, but does not allow the HTTP method to change." ],
|
|
100
|
+
/** 4xx client errors */
|
|
101
|
+
C_400: [ 400, "Bad Request", "The server cannot or will not process the request due to an apparent client error." ],
|
|
102
|
+
C_401: [ 401, "Unauthorized", "Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet been provided." ],
|
|
103
|
+
C_403: [ 403, "Forbidden", "The request contained valid data and was understood by the server, but the server is refusing action. This may be due to the user not having the necessary permissions for a resource or needing an account of some sort, or attempting a prohibited action." ],
|
|
104
|
+
C_404: [ 404, "Not Found", "The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible." ],
|
|
105
|
+
C_405: [ 405, "Method Not Allowed", "A request method is not supported for the requested resource; for example, a GET request on a form that requires data to be presented via POST, or a PUT request on a read-only resource." ],
|
|
106
|
+
C_406: [ 406, "Not Acceptable", "The requested resource is capable of generating only content not acceptable according to the Accept headers sent in the request." ],
|
|
107
|
+
C_407: [ 407, "Proxy Authentication Required", "The client must first authenticate itself with the proxy." ],
|
|
108
|
+
C_408: [ 408, "Request Timeout", "The server timed out waiting for the request." ],
|
|
109
|
+
C_409: [ 409, "Conflict", "Indicates that the request could not be processed because of conflict in the current state of the resource, such as an edit conflict between multiple simultaneous updates." ],
|
|
110
|
+
C_410: [ 410, "Gone", "Indicates that the resource requested was previously in use but is no longer available and will not be available again." ],
|
|
111
|
+
C_411: [ 411, "Length Required", "The request did not specify the length of its content, which is required by the requested resource." ],
|
|
112
|
+
C_412: [ 412, "Precondition Failed", "The server does not meet one of the preconditions that the requester put on the request header fields." ],
|
|
113
|
+
C_413: [ 413, "Payload Too Large", "The request is larger than the server is willing or able to process." ],
|
|
114
|
+
C_414: [ 414, "URI Too Long", "The URI provided was too long for the server to process." ],
|
|
115
|
+
C_415: [ 415, "Unsupported Media Type", "The request entity has a media type which the server or resource does not support." ],
|
|
116
|
+
C_416: [ 416, "Range Not Satisfiable", "The client has asked for a portion of the file (byte serving), but the server cannot supply that portion." ],
|
|
117
|
+
C_417: [ 417, "Expectation Failed", "The server cannot meet the requirements of the Expect request-header field." ],
|
|
118
|
+
C_421: [ 421, "Misdirected Request", "The request was directed at a server that is not able to produce a response (for example because of connection reuse)." ],
|
|
119
|
+
C_422: [ 422, "Unprocessable Content", "The request was well-formed (i.e., syntactically correct) but could not be processed." ],
|
|
120
|
+
C_423: [ 423, "Locked", "The resource that is being accessed is locked." ],
|
|
121
|
+
C_424: [ 424, "Failed Dependency", "The request failed because it depended on another request and that request failed." ],
|
|
122
|
+
C_425: [ 425, "Too Early", "Indicates that the server is unwilling to risk processing a request that might be replayed." ],
|
|
123
|
+
C_426: [ 426, "Upgrade Required", "The client should switch to a different protocol such as TLS/1.3, given in the Upgrade header field." ],
|
|
124
|
+
C_428: [ 428, "Precondition Required", "The origin server requires the request to be conditional." ],
|
|
125
|
+
C_429: [ 429, "Too Many Requests", "The user has sent too many requests in a given amount of time. Intended for use with rate-limiting schemes." ],
|
|
126
|
+
C_431: [ 431, "Request Header Fields Too Large", "The server is unwilling to process the request because either an individual header field, or all the header fields collectively, are too large." ],
|
|
127
|
+
C_451: [ 451, "Unavailable For Legal Reasons", "A server operator has received a legal demand to deny access to a resource or to a set of resources that includes the requested resource." ],
|
|
128
|
+
/** 5xx server errors */
|
|
129
|
+
C_500: [ 500, "Internal Server Error", "A generic error message, given when an unexpected condition was encountered and no more specific message is suitable." ],
|
|
130
|
+
C_501: [ 501, "Not Implemented", "The server either does not recognize the request method, or it lacks the ability to fulfil the request." ],
|
|
131
|
+
C_502: [ 502, "Bad Gateway", "The server was acting as a gateway or proxy and received an invalid response from the upstream server." ],
|
|
132
|
+
C_503: [ 503, "Service Unavailable", "The server cannot handle the request (because it is overloaded or down for maintenance)." ],
|
|
133
|
+
C_504: [ 504, "Gateway Timeout", "The server was acting as a gateway or proxy and did not receive a timely response from the upstream server." ],
|
|
134
|
+
C_505: [ 505, "HTTP Version Not Supported", "The server does not support the HTTP version used in the request." ],
|
|
135
|
+
C_506: [ 506, "Variant Also Negotiates", "Transparent content negotiation for the request results in a circular reference." ],
|
|
136
|
+
C_507: [ 507, "Insufficient Storage", "The server is unable to store the representation needed to complete the request." ],
|
|
137
|
+
C_508: [ 508, "Loop Detected", "The server detected an infinite loop while processing the request." ],
|
|
138
|
+
C_510: [ 510, "Not Extended", "Further extensions to the request are required for the server to fulfil it." ],
|
|
139
|
+
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." ]
|
|
140
|
+
} );
|
|
141
|
+
module.exports.httpCode = httpCodeEnum;
|
|
142
|
+
|
|
143
|
+
const labelPath = "system.exceptions.";
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Represents an any-purpose exception.
|
|
147
|
+
*
|
|
148
|
+
* @class TiException
|
|
149
|
+
* @public
|
|
150
|
+
*/
|
|
151
|
+
class TiException {
|
|
152
|
+
|
|
153
|
+
#id;
|
|
154
|
+
#code;
|
|
155
|
+
#httpCode;
|
|
156
|
+
#label;
|
|
157
|
+
#description;
|
|
158
|
+
#data;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* @constructor
|
|
162
|
+
* @param {string} id The unique ID to be assigned to this exception.
|
|
163
|
+
* @param {TiExceptionCode} exceptionCode An unique exception identifier. If this is not recognized, the default error code will be used instead.
|
|
164
|
+
* @param {Object} [data={}] Any additional data to insert into the exception.
|
|
165
|
+
* @param {string} [description=undefined] Description of the exception.
|
|
166
|
+
*/
|
|
167
|
+
constructor( id, exceptionCode, data, description ) {
|
|
168
|
+
exceptionCode = exceptionCodeEnum.contains( exceptionCode ) ? exceptionCode : exceptionCodeEnum.E_UNKNOWN_ERROR;
|
|
169
|
+
|
|
170
|
+
this.#id = id;
|
|
171
|
+
this.#code = exceptionCode;
|
|
172
|
+
this.#label = labelPath + String( exceptionCode );
|
|
173
|
+
this.#description = description || exceptionCodeEnum.description( exceptionCode );
|
|
174
|
+
this.#data = data || {};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/* Public interface */
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Unique identifier of the exception instance. Can be used for tracing problems with customer support cases.
|
|
181
|
+
*
|
|
182
|
+
* @property
|
|
183
|
+
* @returns {string}
|
|
184
|
+
* @public
|
|
185
|
+
*/
|
|
186
|
+
get id() {
|
|
187
|
+
return this.#id;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Identifier code of the exception type.
|
|
192
|
+
*
|
|
193
|
+
* @property
|
|
194
|
+
* @returns {TiExceptionCode}
|
|
195
|
+
* @public
|
|
196
|
+
*/
|
|
197
|
+
get code() {
|
|
198
|
+
return this.#code;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* HTTP error code if relevant.
|
|
203
|
+
*
|
|
204
|
+
* @property
|
|
205
|
+
* @returns {TiHttpCode}
|
|
206
|
+
* @public
|
|
207
|
+
*/
|
|
208
|
+
get httpCode() {
|
|
209
|
+
return this.#httpCode;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* HTTP error code if relevant.
|
|
214
|
+
*
|
|
215
|
+
* @property
|
|
216
|
+
* @param {TiHttpCode} httpCode
|
|
217
|
+
* @public
|
|
218
|
+
*/
|
|
219
|
+
set httpCode( httpCode ) {
|
|
220
|
+
if ( httpCodeEnum.contains( httpCode ) ) {
|
|
221
|
+
this.#httpCode = httpCode;
|
|
222
|
+
} else {
|
|
223
|
+
this.#httpCode = undefined;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Localized label identifier.
|
|
229
|
+
*
|
|
230
|
+
* @property
|
|
231
|
+
* @returns {string}
|
|
232
|
+
* @public
|
|
233
|
+
*/
|
|
234
|
+
get label() {
|
|
235
|
+
return this.#label;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Description or additional technical information that is NOT localized.
|
|
240
|
+
*
|
|
241
|
+
* @property
|
|
242
|
+
* @returns {string}
|
|
243
|
+
* @public
|
|
244
|
+
*/
|
|
245
|
+
get description() {
|
|
246
|
+
return this.#description;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* JSON containing any additional data that has relevance for the exception. Can be converted JavaScript {@link Error} object as well.
|
|
251
|
+
*
|
|
252
|
+
* @property
|
|
253
|
+
* @returns {Object}
|
|
254
|
+
* @public
|
|
255
|
+
*/
|
|
256
|
+
get data() {
|
|
257
|
+
return this.#data;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* JSON containing any additional data that has relevance for the exception. Can be converted JavaScript {@link Error} object as well.
|
|
262
|
+
*
|
|
263
|
+
* @property
|
|
264
|
+
* @param {Object} data
|
|
265
|
+
* @public
|
|
266
|
+
*/
|
|
267
|
+
set data( data ) {
|
|
268
|
+
this.#data = data;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Extracts the essential information about the {@link TiException} and returns it as JSON.
|
|
273
|
+
*
|
|
274
|
+
* @method
|
|
275
|
+
* @param {boolean} [includeData=true] Whether to include the data property in the output.
|
|
276
|
+
* @returns {Object}
|
|
277
|
+
* @public
|
|
278
|
+
*/
|
|
279
|
+
asJSON( includeData = true ) {
|
|
280
|
+
let json = {
|
|
281
|
+
id: this.id,
|
|
282
|
+
code: this.code,
|
|
283
|
+
label: this.label,
|
|
284
|
+
description: this.description
|
|
285
|
+
};
|
|
286
|
+
if ( this.#httpCode !== undefined ) {
|
|
287
|
+
json.httpCode = this.#httpCode;
|
|
288
|
+
}
|
|
289
|
+
if ( includeData === true ) {
|
|
290
|
+
json.data = this.#data;
|
|
291
|
+
}
|
|
292
|
+
return json;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Used to raise an exception from the provided source.
|
|
298
|
+
* <br/>
|
|
299
|
+
* NOTE: Custom numeric exception IDs are not supported when 'httpCode' is omitted!
|
|
300
|
+
*
|
|
301
|
+
* @method
|
|
302
|
+
* @param {Error|TiExceptionCode|TiException} source Could be a standard JS Error, an ExceptionCode, or another TiException (in which case it will be raised further).
|
|
303
|
+
* @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.
|
|
304
|
+
* @param {string} [exceptionID=undefined] Should be used only in cases when we have a recognizable exception ID beforehand. Should not be entered otherwise!
|
|
305
|
+
* @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
|
|
306
|
+
* override any preexisting HTTP code in 'source'!
|
|
307
|
+
* @returns {TiException}
|
|
308
|
+
* @public
|
|
309
|
+
*/
|
|
310
|
+
module.exports.raise = ( source, data, exceptionID = undefined, httpCode = undefined ) => {
|
|
311
|
+
/** @type TiException */
|
|
312
|
+
let exception;
|
|
313
|
+
|
|
314
|
+
// Support flexible argument passing: if exceptionID is a number (likely an HTTP code) and httpCode is missing, swap them:
|
|
315
|
+
if ( typeof exceptionID === "number" && httpCode === undefined ) {
|
|
316
|
+
httpCode = exceptionID;
|
|
317
|
+
exceptionID = undefined;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if ( source instanceof Error ) {
|
|
321
|
+
exception = new TiException( exceptionID || tools.getUUID(), exceptionCodeEnum.E_GEN_JS_INTERNAL_ERROR, tools.errorToJSON( source ) );
|
|
322
|
+
} else if ( source instanceof TiException ) {
|
|
323
|
+
exception = source;
|
|
324
|
+
} else if ( _.isString( source ) ) {
|
|
325
|
+
exception = new TiException( exceptionID || tools.getUUID(), exceptionCodeEnum.E_GEN_JS_INTERNAL_ERROR, {
|
|
326
|
+
message: source
|
|
327
|
+
} );
|
|
328
|
+
} else if ( _.isObjectLike( source ) ) {
|
|
329
|
+
exception = new TiException(
|
|
330
|
+
exceptionID || ( source.id || tools.getUUID() ),
|
|
331
|
+
source.code || exceptionCodeEnum.E_GEN_JS_INTERNAL_ERROR,
|
|
332
|
+
source.data,
|
|
333
|
+
source.description
|
|
334
|
+
);
|
|
335
|
+
if ( source.httpCode && httpCodeEnum.contains( source.httpCode ) ) {
|
|
336
|
+
exception.httpCode = source.httpCode;
|
|
337
|
+
}
|
|
338
|
+
} else {
|
|
339
|
+
exception = new TiException( exceptionID || tools.getUUID(), ( exceptionCodeEnum.contains( source ) ) ? source : exceptionCodeEnum.E_UNKNOWN_ERROR );
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Merge the default exception data with the additional one if it's provided:
|
|
343
|
+
if ( data ) {
|
|
344
|
+
exception.data = _.mergeWith( ( exception.data || {} ), _.cloneDeep( data ), ( objValue, srcValue ) => {
|
|
345
|
+
return ( _.isArray( objValue ) ) ? objValue.concat( srcValue ) : undefined;
|
|
346
|
+
} );
|
|
347
|
+
|
|
348
|
+
// Make sure to eliminate any circular dependencies inside the data object (these should never be needed for an error description):
|
|
349
|
+
exception.data = tools.decycle( exception.data );
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if ( httpCode && httpCodeEnum.contains( httpCode ) ) {
|
|
353
|
+
exception.httpCode = httpCode;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return exception;
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Verifies if the passed object is a {@link TiException}.
|
|
361
|
+
*
|
|
362
|
+
* @method
|
|
363
|
+
* @param {*} object
|
|
364
|
+
* @returns {boolean}
|
|
365
|
+
* @public
|
|
366
|
+
*/
|
|
367
|
+
module.exports.isException = ( object ) => {
|
|
368
|
+
return ( object instanceof TiException );
|
|
369
369
|
};
|