@ti-engine/core 1.12.3 → 1.14.0

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 CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  This document contains the list of changes made to the framework. The format is based on the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification.
4
4
 
5
+ ## Version 1.14.0
6
+
7
+ * feat(cache): select the backend through the new `memoryCache.provider` setting (`TI_MEMORY_CACHE_PROVIDER`). `"redis"` selects the built-in provider and remains the default; any other value is a module path resolved against the working directory and must export a `CacheProvider` subclass. Without this the provider contract added in 1.13.0 could not actually be pointed at anything else.
8
+ * feat(service-instance): make the message exchange optional through `messageExchange.enabled` (`TI_MESSAGE_EXCHANGE_ENABLED`), defaulting to `true`. When off, neither the exchange nor the dispatcher is initialized or shut down — and the exchange is the only remaining user of the cache primitives a non-Redis backend cannot reasonably provide (`blockingCommand`, pub/sub).
9
+ * feat(service-instance): make health reporting optional through `serviceConfig.healthCheckEnabled`, defaulting to `true`. The default interval is a six-field cron, so this writes once per second for the life of the instance; that is what an orchestrator watching a mesh wants and pure cost for a single instance with nothing reading the key.
10
+ * fix(cache): validate the configured provider class before constructing it. `typeof === "function"` accepts an arrow function, which is not a constructor — `new` on one threw a raw `TypeError` instead of the documented `E_GEN_INVALID_ARGUMENT_TYPE` — and asking `instanceof` after construction meant an unrelated class had its constructor run, executing arbitrary code from a misconfigured path, before anything rejected it. Both now fail the same declared way, without constructing anything.
11
+ * test(cache): cover backend selection and, with a stub backend that reproduces the Redis client's notify-then-resolve ordering, the rollback on a refused start — the 1.13.0 fix that shipped untested because it needed a live server. Verified to fail without the rollback. Core 53 to 60 tests.
12
+
13
+ ## Version 1.13.0
14
+
15
+ * feat(cache): introduce `CacheProvider`, an abstract backend contract, and move every Redis-specific detail behind it into `RedisCacheProvider`. `CommonMemoryCache` keeps its public API and now owns only the operational state, the connection observation and one guard shared by all twenty-one data methods.
16
+ * feat(cache): declare backend capabilities (`TiCacheCapability`) and reconcile them at startup against the new `memoryCache.requiredCapabilities` setting (`TI_MEMORY_CACHE_REQUIRED_CAPABILITIES`), so a backend that cannot do what the application needs fails where somebody is watching. `ATOMIC_JSON_EDIT` is declared separately from `JSON_DOCUMENTS` because a backend can store JSON while applying a path edit as a read-modify-write, which loses one of two concurrent writes silently.
17
+ * fix(cache): roll the cache back to non-operational and shut the backend down when capability reconciliation fails. The Redis client notifies its connection observers from inside its `ready` handler, before `initialize()` resolves, so the cache is already operational by the time the check runs; rejecting without undoing that left a live connection behind a cache reporting itself usable, while the caller had been told startup failed.
18
+ * test(cache): cover the provider contract and the startup reconciliation — 11 new tests, core 42 to 53.
19
+
5
20
  ## Version 1.12.3
6
21
 
7
22
  * chore(package): update `package.json` structure
package/bin/settings.json CHANGED
@@ -17,12 +17,15 @@
17
17
  },
18
18
  "memoryCache": {
19
19
  "authKey": null,
20
+ "provider": "redis",
20
21
  "redisDB": 0,
21
22
  "redisHost": "127.0.0.1",
22
23
  "redisPort": 6379,
24
+ "requiredCapabilities": [],
23
25
  "user": "default"
24
26
  },
25
27
  "messageExchange": {
28
+ "enabled": true,
26
29
  "messageQueuePrefix": "ti:messages:",
27
30
  "messageStore": "ti:messages:store",
28
31
  "securityHashEnabled": true,
@@ -34,6 +37,7 @@
34
37
  "serviceConfig": {
35
38
  "executionTimeout": 180000,
36
39
  "healthCheckAddress": "ti:services:registry:health:",
40
+ "healthCheckEnabled": true,
37
41
  "healthCheckInterval": "*/1 * * * * *",
38
42
  "healthCheckTimeout": 3,
39
43
  "serviceRegistryAddress": "ti:services:registry:catalog:"
@@ -0,0 +1,42 @@
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
+ *
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.
16
+ */
17
+
18
+ const tools = require( "#tools" );
19
+
20
+ /**
21
+ * Enum for listing the optional behaviors a cache backend may or may not provide.
22
+ * <br/>
23
+ * NOTE: A backend declares what it supports through {@link CacheProvider#capabilities}; an application declares what it
24
+ * requires through the 'memoryCache.requiredCapabilities' setting. The two are reconciled once, during startup, so that
25
+ * a backend which cannot do what the application needs fails where somebody is watching rather than inside a request
26
+ * weeks later.
27
+ *
28
+ * @readonly
29
+ * @enum {string}
30
+ * @typedef {string} TiCacheCapability
31
+ */
32
+ const cacheCapabilityEnum = tools.enum( {
33
+ KEY_EXPIRY: [ "key-expiry", "key expiry", "Per-key time-to-live." ],
34
+ KEY_PATTERN_MATCH: [ "key-pattern-match", "key pattern match", "Enumerating stored keys by glob pattern." ],
35
+ LISTS: [ "lists", "lists", "Ordered list values." ],
36
+ SETS: [ "sets", "sets", "Unordered set values, membership tests and unions." ],
37
+ HASH_FIELDS: [ "hash-fields", "hash fields", "Field-addressable hash values." ],
38
+ JSON_DOCUMENTS: [ "json-documents", "JSON documents", "JSON documents addressed by JSONPath." ],
39
+ ATOMIC_JSON_EDIT: [ "atomic-json-edit", "atomic JSON edit", "A JSONPath edit applied atomically by the backend rather than as a read-modify-write." ]
40
+ } );
41
+
42
+ module.exports.cacheCapability = cacheCapabilityEnum;
@@ -0,0 +1,432 @@
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
+ *
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.
16
+ */
17
+
18
+ const exceptions = require( "#exceptions" );
19
+
20
+ /** @import ConnectionObserver from "#connection-observer" */
21
+
22
+ /**
23
+ * An abstract class that defines the storage behavior required by the {@link CommonMemoryCache}.
24
+ * <br/>
25
+ * NOTE: This sets the contract between the cache and whatever actually holds the values. It has to be inherited and
26
+ * implemented with the specifics of a given backend. For a working example please see the {@link RedisCacheProvider} class.
27
+ * <br/>
28
+ * NOTE: Implementations must NOT check whether the cache is operational. {@link CommonMemoryCache} performs that check
29
+ * once, before it delegates, so every backend inherits the same guard instead of restating it in each of its methods.
30
+ *
31
+ * @class CacheProvider
32
+ * @abstract
33
+ * @public
34
+ */
35
+ class CacheProvider {
36
+
37
+ /**
38
+ * @constructor
39
+ * @throws {TiException.E_GEN_ABSTRACT_CLASS_INIT} If this class is instantiated directly.
40
+ */
41
+ constructor() {
42
+ // make sure this abstract class cannot be instantiated:
43
+ if ( new.target === CacheProvider ) {
44
+ throw exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_CLASS_INIT, { name: this.constructor.name } );
45
+ }
46
+ }
47
+
48
+ /* Public interface */
49
+
50
+ /**
51
+ * Property returning the optional behaviors this backend provides.
52
+ * <br/>
53
+ * NOTE: Some capabilities can only be established once a connection exists — RedisJSON, for example, is a server-side
54
+ * module that has to be probed. Read this after {@link CacheProvider#initialize} has resolved, never before.
55
+ *
56
+ * @property
57
+ * @returns {string[]} Values drawn from {@link TiCacheCapability}.
58
+ * @abstract
59
+ * @public
60
+ */
61
+ get capabilities() {
62
+ throw exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + ".capabilities" } );
63
+ }
64
+
65
+ /**
66
+ * Used to verify whether this backend provides a given capability.
67
+ *
68
+ * @method
69
+ * @param {string} capability A value from {@link TiCacheCapability}.
70
+ * @returns {boolean}
71
+ * @public
72
+ */
73
+ hasCapability( capability ) {
74
+ return this.capabilities.indexOf( capability ) !== -1;
75
+ }
76
+
77
+ /**
78
+ * Used to initialize the backend and establish whatever connection it requires.
79
+ *
80
+ * @method
81
+ * @returns {Promise}
82
+ * @abstract
83
+ * @public
84
+ */
85
+ initialize() {
86
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.initialize.name } ) );
87
+ }
88
+
89
+ /**
90
+ * Used to gracefully shut the backend down.
91
+ *
92
+ * @method
93
+ * @returns {Promise}
94
+ * @abstract
95
+ * @public
96
+ */
97
+ shutDown() {
98
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.shutDown.name } ) );
99
+ }
100
+
101
+ /**
102
+ * Used to register a new {@link ConnectionObserver} for events related to the backend connection state.
103
+ *
104
+ * @method
105
+ * @param {ConnectionObserver} connectionObserver The {@link ConnectionObserver} that will be notified of any changes.
106
+ * @abstract
107
+ * @public
108
+ */
109
+ addConnectionObserver( connectionObserver ) {
110
+ throw exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.addConnectionObserver.name } );
111
+ }
112
+
113
+ /**
114
+ * Used to search for keys by a given pattern.
115
+ *
116
+ * @method
117
+ * @param {string} pattern
118
+ * @returns {Promise<Array>}
119
+ * @requires {TiCacheCapability.KEY_PATTERN_MATCH}
120
+ * @abstract
121
+ * @public
122
+ */
123
+ matchKeys( pattern ) {
124
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.matchKeys.name } ) );
125
+ }
126
+
127
+ /**
128
+ * Used to set a specific string value.
129
+ *
130
+ * @method
131
+ * @param {string} key
132
+ * @param {string} value
133
+ * @param {number} [expiration] Expiration value is in seconds.
134
+ * @returns {Promise<string>}
135
+ * @abstract
136
+ * @public
137
+ */
138
+ setValue( key, value, expiration ) {
139
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.setValue.name } ) );
140
+ }
141
+
142
+ /**
143
+ * Used to set multiple string values.
144
+ *
145
+ * @method
146
+ * @param {Object} keyValues
147
+ * @param {string} [prefix]
148
+ * @param {number} [expiration] Expiration value is in seconds.
149
+ * @returns {Promise}
150
+ * @abstract
151
+ * @public
152
+ */
153
+ setValues( keyValues, prefix, expiration ) {
154
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.setValues.name } ) );
155
+ }
156
+
157
+ /**
158
+ * Used to get a string value.
159
+ *
160
+ * @method
161
+ * @param {string} key
162
+ * @returns {Promise}
163
+ * @abstract
164
+ * @public
165
+ */
166
+ getValue( key ) {
167
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.getValue.name } ) );
168
+ }
169
+
170
+ /**
171
+ * Used to get multiple string values.
172
+ *
173
+ * @method
174
+ * @param {string[]} keys
175
+ * @param {string} [prefix]
176
+ * @returns {Promise}
177
+ * @abstract
178
+ * @public
179
+ */
180
+ getValues( keys, prefix ) {
181
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.getValues.name } ) );
182
+ }
183
+
184
+ /**
185
+ * Used to delete a value / item.
186
+ *
187
+ * @method
188
+ * @param {string} key
189
+ * @returns {Promise<boolean>}
190
+ * @abstract
191
+ * @public
192
+ */
193
+ deleteValue( key ) {
194
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.deleteValue.name } ) );
195
+ }
196
+
197
+ /**
198
+ * Used to set expiration in seconds to an existing key.
199
+ *
200
+ * @method
201
+ * @param {string} key
202
+ * @param {number} seconds
203
+ * @param {string} [name] If a field in a hash set is to be expired instead, the name of that set.
204
+ * @returns {Promise<number>}
205
+ * @requires {TiCacheCapability.KEY_EXPIRY}
206
+ * @abstract
207
+ * @public
208
+ */
209
+ expireValue( key, seconds, name ) {
210
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.expireValue.name } ) );
211
+ }
212
+
213
+ /**
214
+ * Used to add the specified values to a list.
215
+ *
216
+ * @method
217
+ * @param {string} listName
218
+ * @param {Object[]} values
219
+ * @returns {Promise<number>}
220
+ * @requires {TiCacheCapability.LISTS}
221
+ * @abstract
222
+ * @public
223
+ */
224
+ listPushValue( listName, values ) {
225
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.listPushValue.name } ) );
226
+ }
227
+
228
+ /**
229
+ * Used to add the specified value to a set.
230
+ *
231
+ * @method
232
+ * @param {string} key
233
+ * @param {string|Object} value
234
+ * @returns {Promise}
235
+ * @requires {TiCacheCapability.SETS}
236
+ * @abstract
237
+ * @public
238
+ */
239
+ addToSet( key, value ) {
240
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.addToSet.name } ) );
241
+ }
242
+
243
+ /**
244
+ * Used to add multiple values to multiple sets in one transactional request.
245
+ *
246
+ * @method
247
+ * @param {string[]} keys
248
+ * @param {string[]} values
249
+ * @returns {Promise}
250
+ * @requires {TiCacheCapability.SETS}
251
+ * @abstract
252
+ * @public
253
+ */
254
+ addToSetMulti( keys, values ) {
255
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.addToSetMulti.name } ) );
256
+ }
257
+
258
+ /**
259
+ * Used to verify whether a value is a member of a set.
260
+ *
261
+ * @method
262
+ * @param {string} setName
263
+ * @param {string|Object} value
264
+ * @returns {Promise<boolean>}
265
+ * @requires {TiCacheCapability.SETS}
266
+ * @abstract
267
+ * @public
268
+ */
269
+ isSetMember( setName, value ) {
270
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.isSetMember.name } ) );
271
+ }
272
+
273
+ /**
274
+ * Used to fetch all members of a set.
275
+ *
276
+ * @method
277
+ * @param {string} key
278
+ * @returns {Promise<Array>}
279
+ * @requires {TiCacheCapability.SETS}
280
+ * @abstract
281
+ * @public
282
+ */
283
+ membersOfSet( key ) {
284
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.membersOfSet.name } ) );
285
+ }
286
+
287
+ /**
288
+ * Used to fetch the union of the provided sets.
289
+ *
290
+ * @method
291
+ * @param {string[]} keys
292
+ * @returns {Promise<Array>}
293
+ * @requires {TiCacheCapability.SETS}
294
+ * @abstract
295
+ * @public
296
+ */
297
+ unionOfSets( keys ) {
298
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.unionOfSets.name } ) );
299
+ }
300
+
301
+ /**
302
+ * Used to set a single field in a hash set.
303
+ *
304
+ * @method
305
+ * @param {string} key
306
+ * @param {string} name
307
+ * @param {string|Object} value
308
+ * @returns {Promise}
309
+ * @requires {TiCacheCapability.HASH_FIELDS}
310
+ * @abstract
311
+ * @public
312
+ */
313
+ hashSetField( key, name, value ) {
314
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.hashSetField.name } ) );
315
+ }
316
+
317
+ /**
318
+ * Used to set multiple fields in a hash set.
319
+ *
320
+ * @method
321
+ * @param {string} key
322
+ * @param {Object} fields
323
+ * @returns {Promise}
324
+ * @requires {TiCacheCapability.HASH_FIELDS}
325
+ * @abstract
326
+ * @public
327
+ */
328
+ hashSetFields( key, fields ) {
329
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.hashSetFields.name } ) );
330
+ }
331
+
332
+ /**
333
+ * Used to fetch a single field from a hash set.
334
+ *
335
+ * @method
336
+ * @param {string} key
337
+ * @param {string} field
338
+ * @returns {Promise}
339
+ * @requires {TiCacheCapability.HASH_FIELDS}
340
+ * @abstract
341
+ * @public
342
+ */
343
+ hashGetField( key, field ) {
344
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.hashGetField.name } ) );
345
+ }
346
+
347
+ /**
348
+ * Used to delete a single field from a hash set.
349
+ *
350
+ * @method
351
+ * @param {string} key
352
+ * @param {string} field
353
+ * @returns {Promise}
354
+ * @requires {TiCacheCapability.HASH_FIELDS}
355
+ * @abstract
356
+ * @public
357
+ */
358
+ hashDeleteField( key, field ) {
359
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.hashDeleteField.name } ) );
360
+ }
361
+
362
+ /**
363
+ * Used to store a JSON document, or a branch of one.
364
+ *
365
+ * @method
366
+ * @param {string} key
367
+ * @param {Object} value
368
+ * @param {string|string[]} [path="$"] A dot-separated JSONPath string, or an array of literal key segments.
369
+ * @param {number} [overrideMode=0] 0 allows full override; 1 sets only if absent; 2 sets only if present.
370
+ * @returns {Promise}
371
+ * @requires {TiCacheCapability.JSON_DOCUMENTS}
372
+ * @abstract
373
+ * @public
374
+ */
375
+ setJSON( key, value, path = "$", overrideMode = 0 ) {
376
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.setJSON.name } ) );
377
+ }
378
+
379
+ /**
380
+ * Used to fetch a JSON document, or a branch of one.
381
+ *
382
+ * @method
383
+ * @param {string} key
384
+ * @param {string|string[]} [path="$"] A dot-separated JSONPath string, or an array of literal key segments.
385
+ * @returns {Promise<Object>}
386
+ * @requires {TiCacheCapability.JSON_DOCUMENTS}
387
+ * @abstract
388
+ * @public
389
+ */
390
+ getJSON( key, path = "$" ) {
391
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.getJSON.name } ) );
392
+ }
393
+
394
+ /**
395
+ * Used to merge a value into an existing JSON document at the given path.
396
+ * <br/>
397
+ * NOTE: Callers rely on this being applied atomically by the backend when {@link TiCacheCapability.ATOMIC_JSON_EDIT}
398
+ * is declared — two concurrent edits to different paths of the same document must both survive. A backend that can
399
+ * only read-modify-write must NOT declare that capability, because the loss is silent: nothing throws, and one of
400
+ * the two writes is simply gone.
401
+ *
402
+ * @method
403
+ * @param {string} key
404
+ * @param {Object} value
405
+ * @param {string|string[]} [path="$"] A dot-separated JSONPath string, or an array of literal key segments.
406
+ * @returns {Promise}
407
+ * @requires {TiCacheCapability.JSON_DOCUMENTS}
408
+ * @abstract
409
+ * @public
410
+ */
411
+ editJSON( key, value, path = "$" ) {
412
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.editJSON.name } ) );
413
+ }
414
+
415
+ /**
416
+ * Used to append a value to an array inside a JSON document.
417
+ *
418
+ * @method
419
+ * @param {string} key
420
+ * @param {Object} value
421
+ * @param {string|string[]} [path="$"] A dot-separated JSONPath string, or an array of literal key segments.
422
+ * @returns {Promise}
423
+ * @requires {TiCacheCapability.JSON_DOCUMENTS}
424
+ * @abstract
425
+ * @public
426
+ */
427
+ arrayAppendJSON( key, value, path = "$" ) {
428
+ return Promise.reject( exceptions.raise( exceptions.exceptionCode.E_GEN_ABSTRACT_METHOD_CALL, { name: this.constructor.name + "." + this.arrayAppendJSON.name } ) );
429
+ }
430
+ }
431
+
432
+ module.exports = CacheProvider;