@ti-engine/core 1.10.0 → 1.11.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/CHANGELOG.md +69 -0
- package/LICENSE.md +204 -322
- package/README.md +2 -2
- package/bin/start-instance.js +12 -3
- package/components/auditing.js +12 -3
- package/components/connection-observer.js +12 -3
- package/components/definitions.types.js +12 -3
- package/components/exchange/default/default-message-exchange.js +12 -3
- package/components/exchange/default/default-message-receiver.js +12 -3
- package/components/exchange/default/default-message-sender.js +12 -3
- package/components/exchange/message-dispatcher.js +12 -3
- package/components/exchange/message-exchange.js +12 -3
- package/components/exchange/message-handler.js +12 -3
- package/components/exchange/message-memory-cache.js +12 -3
- package/components/exchange/message-observer.js +12 -3
- package/components/exchange/message-receiver.js +12 -3
- package/components/exchange/message-sender.js +12 -3
- package/components/exchange/message-tracer.js +12 -3
- package/components/service-caller.js +12 -3
- package/components/service-consumer.js +12 -3
- package/components/service-executor.js +12 -3
- package/components/service-instance.js +12 -3
- package/components/service-provider.js +12 -3
- package/integrations/redis-integration.js +12 -3
- package/package.json +3 -3
- package/types/utils/cache.d.ts +36 -0
- package/utils/cache.js +69 -11
- package/utils/config.js +12 -3
- package/utils/exceptions.js +12 -3
- package/utils/localization.js +12 -3
- package/utils/logger.js +12 -3
- package/utils/tools.js +30 -5
package/utils/cache.js
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
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
3
|
* Copyright © 2021-2026 Boris Kostadinov <kostadinov.boris@gmail.com>
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
7
16
|
*/
|
|
8
17
|
|
|
9
18
|
const ConnectionObserver = require( "#connection-observer" );
|
|
@@ -13,6 +22,55 @@ const tools = require( "#tools" );
|
|
|
13
22
|
const redis = require( "#redis-integration" );
|
|
14
23
|
const exceptions = require( "#exceptions" );
|
|
15
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Decodes one entry of a `multi(...).exec()` result into the value it carries.
|
|
27
|
+
* <br/>
|
|
28
|
+
* Each entry is an ioredis `[ error, value ]` pair, so the value sits at index 1 and is a string when the key existed.
|
|
29
|
+
* Returns `undefined` for a miss, an error entry, or a malformed entry.
|
|
30
|
+
* <br/>
|
|
31
|
+
* This lives outside the class, and is shared by {@link CommonMemoryCache#getValue} and
|
|
32
|
+
* {@link CommonMemoryCache#getValues}, because it previously existed as two near-identical inline expressions and one
|
|
33
|
+
* of them drifted: `getValues` inspected its own accumulator instead of the per-key entry, so `.length` was
|
|
34
|
+
* `undefined`, the comparison was always false, and **every key resolved to `null`** whatever Redis returned.
|
|
35
|
+
*
|
|
36
|
+
* @method
|
|
37
|
+
* @param {Array} [result] One `[ error, value ]` entry.
|
|
38
|
+
* @returns {*} The parsed value, or `undefined` when there is none.
|
|
39
|
+
* @private
|
|
40
|
+
*/
|
|
41
|
+
function decodeCommandValue( result ) {
|
|
42
|
+
// `Array.isArray` rather than a bare truthy-and-length test: a string also has a `length` and an indexable
|
|
43
|
+
// character at 1, so a malformed non-array entry would otherwise be parsed as if it were a value.
|
|
44
|
+
return ( Array.isArray( result ) && result.length > 1 && _.isString( result[ 1 ] ) ) ? tools.parseJSON( result[ 1 ] ) : undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Maps a set of requested keys onto the values a `multi(...).exec()` returned for them, using `null` for a miss.
|
|
49
|
+
* <br/>
|
|
50
|
+
* Iterates the requested `keys` rather than the raw results, so a short or absent response still yields one entry per
|
|
51
|
+
* requested key instead of silently omitting some — the caller's map always has the shape it asked for.
|
|
52
|
+
* <br/>
|
|
53
|
+
* The accumulator has no prototype on purpose: the key names come from the caller, and a cache key named `__proto__`
|
|
54
|
+
* written by bracket assignment onto an ordinary `{}` would repoint the accumulator's prototype instead of creating
|
|
55
|
+
* the entry. Same class as the `decycle` defect fixed in `tools.js`; see the 1.11.0 changelog entry.
|
|
56
|
+
*
|
|
57
|
+
* @method
|
|
58
|
+
* @param {string[]} keys The keys that were requested, in command order.
|
|
59
|
+
* @param {Array} [rawResults] The `multi(...).exec()` result.
|
|
60
|
+
* @returns {Object} A null-prototype map of key to value, `null` where the key was absent.
|
|
61
|
+
* @private
|
|
62
|
+
*/
|
|
63
|
+
function mapCommandValues( keys, rawResults ) {
|
|
64
|
+
let values = Object.create( null );
|
|
65
|
+
|
|
66
|
+
_.forEach( keys, ( key, idx ) => {
|
|
67
|
+
let decoded = decodeCommandValue( rawResults ? rawResults[ idx ] : undefined );
|
|
68
|
+
values[ key ] = ( decoded === undefined ) ? null : decoded;
|
|
69
|
+
} );
|
|
70
|
+
|
|
71
|
+
return values;
|
|
72
|
+
}
|
|
73
|
+
|
|
16
74
|
/**
|
|
17
75
|
* Used to create and/or return a Common Memory Cache singleton instance.
|
|
18
76
|
*
|
|
@@ -260,8 +318,7 @@ class CommonMemoryCache extends ConnectionObserver {
|
|
|
260
318
|
if ( this.#isOperational === true ) {
|
|
261
319
|
let commandGetValue = [ redis.cacheCommands.GET_VALUE, key ];
|
|
262
320
|
this.#redisClient.executeCommands( [ commandGetValue ] ).then( ( results ) => {
|
|
263
|
-
results
|
|
264
|
-
resolve( ( results && results.length > 1 && _.isString( results[ 1 ] ) ) ? tools.parseJSON( results[ 1 ] ) : undefined );
|
|
321
|
+
resolve( decodeCommandValue( results ? results[ 0 ] : undefined ) );
|
|
265
322
|
} ).catch( ( error ) => {
|
|
266
323
|
reject( error );
|
|
267
324
|
} );
|
|
@@ -288,11 +345,7 @@ class CommonMemoryCache extends ConnectionObserver {
|
|
|
288
345
|
commands.push( [ redis.cacheCommands.GET_VALUE, ( ( prefix ) ? prefix : "" ) + key ] );
|
|
289
346
|
} );
|
|
290
347
|
this.#redisClient.executeCommands( commands ).then( ( rawResults ) => {
|
|
291
|
-
|
|
292
|
-
_.forEach( rawResults, ( result, idx ) => {
|
|
293
|
-
results[ keys[ idx ] ] = ( results && results.length > 1 && _.isString( results[ 1 ] ) ) ? tools.parseJSON( results[ 1 ] ) : null;
|
|
294
|
-
} );
|
|
295
|
-
resolve( results );
|
|
348
|
+
resolve( mapCommandValues( keys, rawResults ) );
|
|
296
349
|
} ).catch( ( error ) => {
|
|
297
350
|
reject( error );
|
|
298
351
|
} );
|
|
@@ -769,4 +822,9 @@ class CommonMemoryCache extends ConnectionObserver {
|
|
|
769
822
|
}
|
|
770
823
|
|
|
771
824
|
const instance = new CommonMemoryCache();
|
|
772
|
-
module.exports.instance = Object.freeze( instance );
|
|
825
|
+
module.exports.instance = Object.freeze( instance );
|
|
826
|
+
|
|
827
|
+
// Exported for testing. The cache singleton builds its own Redis client in its constructor, so `getValues` cannot be
|
|
828
|
+
// driven without a live server — these are the pure halves of it, and they are where the defect was.
|
|
829
|
+
module.exports.decodeCommandValue = decodeCommandValue;
|
|
830
|
+
module.exports.mapCommandValues = mapCommandValues;
|
package/utils/config.js
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
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
3
|
* Copyright © 2021-2026 Boris Kostadinov <kostadinov.boris@gmail.com>
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
7
16
|
*/
|
|
8
17
|
|
|
9
18
|
const _ = require( "lodash" );
|
package/utils/exceptions.js
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
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
3
|
* Copyright © 2021-2025 Boris Kostadinov <kostadinov.boris@gmail.com>
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
7
16
|
*/
|
|
8
17
|
|
|
9
18
|
const _ = require( "lodash" );
|
package/utils/localization.js
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
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
3
|
* Copyright © 2021-2026 Boris Kostadinov <kostadinov.boris@gmail.com>
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
7
16
|
*/
|
|
8
17
|
|
|
9
18
|
const path = require( "node:path" );
|
package/utils/logger.js
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
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
3
|
* Copyright © 2021-2025 Boris Kostadinov <kostadinov.boris@gmail.com>
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
7
16
|
*/
|
|
8
17
|
|
|
9
18
|
const _ = require( "lodash" );
|
package/utils/tools.js
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
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
3
|
* Copyright © 2021-2026 Boris Kostadinov <kostadinov.boris@gmail.com>
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
7
16
|
*/
|
|
8
17
|
|
|
9
18
|
const _ = require( "lodash" );
|
|
@@ -182,7 +191,11 @@ module.exports.getEnumName = ( enumList, enumValue, placeholder = undefined ) =>
|
|
|
182
191
|
* @public
|
|
183
192
|
*/
|
|
184
193
|
module.exports.errorToJSON = ( value ) => {
|
|
185
|
-
|
|
194
|
+
// Null prototype for the same reason as in `decycle`: the keys come from the error's own property names, and a
|
|
195
|
+
// key named `__proto__` written by bracket assignment onto an ordinary `{}` would repoint the prototype rather
|
|
196
|
+
// than be copied. An error carrying such a property is exotic — it takes a deliberate `defineProperty` — but the
|
|
197
|
+
// pattern is identical and the guard costs nothing.
|
|
198
|
+
let error = Object.create( null );
|
|
186
199
|
|
|
187
200
|
if ( value instanceof Error ) {
|
|
188
201
|
Object.getOwnPropertyNames( value ).forEach( ( key ) => {
|
|
@@ -337,7 +350,19 @@ module.exports.decycle = ( object, replacer ) => {
|
|
|
337
350
|
} );
|
|
338
351
|
} else {
|
|
339
352
|
// If it is an object, replicate the object.
|
|
340
|
-
|
|
353
|
+
// The replica has NO prototype on purpose. A key is copied in by bracket assignment, and on an
|
|
354
|
+
// ordinary `{}` a key named `__proto__` would hit the inherited setter instead of creating an own
|
|
355
|
+
// property: the key vanished from the replica and its value silently became the replica's prototype.
|
|
356
|
+
// `stringifyJSON` then ran `_.toPlainObject` over that, flattening the lost value's own fields back
|
|
357
|
+
// in as unrelated top-level keys, so the key vanished and its contents surfaced as siblings. Silent
|
|
358
|
+
// corruption, not a crash, and it reached Redis through `cache.setJSON`. With a null prototype there
|
|
359
|
+
// is no setter to hit, so `__proto__` is an ordinary key.
|
|
360
|
+
// Both consumers of this output are safe: `_.isPlainObject` accepts a null-prototype object, so
|
|
361
|
+
// `decomposeJSON` behaves identically, and `_.toPlainObject` preserves the key — but only because
|
|
362
|
+
// lodash's own `baseAssignValue` special-cases `__proto__` with `defineProperty`. That is a dependency
|
|
363
|
+
// this fix leans on, so `test/tools-proto-keys.test.js` asserts the whole chain end to end rather than
|
|
364
|
+
// just this function.
|
|
365
|
+
newItem = Object.create( null );
|
|
341
366
|
Object.keys( value ).forEach( ( name ) => {
|
|
342
367
|
newItem[ name ] = derez(
|
|
343
368
|
value[ name ],
|