@zuplo/cli 6.71.22 → 6.71.23

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.
Files changed (89) hide show
  1. package/node_modules/@posthog/core/dist/posthog-core-stateless.d.ts +5 -0
  2. package/node_modules/@posthog/core/dist/posthog-core-stateless.d.ts.map +1 -1
  3. package/node_modules/@posthog/core/dist/posthog-core-stateless.js +50 -10
  4. package/node_modules/@posthog/core/dist/posthog-core-stateless.mjs +47 -10
  5. package/node_modules/@posthog/core/dist/posthog-core.d.ts +2 -2
  6. package/node_modules/@posthog/core/dist/posthog-core.d.ts.map +1 -1
  7. package/node_modules/@posthog/core/dist/posthog-core.js +10 -6
  8. package/node_modules/@posthog/core/dist/posthog-core.mjs +11 -7
  9. package/node_modules/@posthog/core/dist/testing/PostHogCoreTestClient.d.ts +1 -0
  10. package/node_modules/@posthog/core/dist/testing/PostHogCoreTestClient.d.ts.map +1 -1
  11. package/node_modules/@posthog/core/dist/testing/PostHogCoreTestClient.js +3 -0
  12. package/node_modules/@posthog/core/dist/testing/PostHogCoreTestClient.mjs +3 -0
  13. package/node_modules/@posthog/core/dist/utils/promise-queue.d.ts +3 -0
  14. package/node_modules/@posthog/core/dist/utils/promise-queue.d.ts.map +1 -1
  15. package/node_modules/@posthog/core/dist/utils/promise-queue.js +15 -3
  16. package/node_modules/@posthog/core/dist/utils/promise-queue.mjs +15 -3
  17. package/node_modules/@posthog/core/package.json +1 -1
  18. package/node_modules/@posthog/core/src/posthog-core-stateless.ts +80 -14
  19. package/node_modules/@posthog/core/src/posthog-core.ts +18 -7
  20. package/node_modules/@posthog/core/src/testing/PostHogCoreTestClient.ts +4 -0
  21. package/node_modules/@posthog/core/src/utils/promise-queue.ts +17 -4
  22. package/node_modules/@posthog/types/dist/posthog.d.ts +12 -0
  23. package/node_modules/@posthog/types/dist/posthog.d.ts.map +1 -1
  24. package/node_modules/@posthog/types/package.json +1 -1
  25. package/node_modules/@posthog/types/src/posthog.ts +13 -0
  26. package/node_modules/@types/node/README.md +1 -1
  27. package/node_modules/@types/node/buffer.d.ts +64 -25
  28. package/node_modules/@types/node/crypto.d.ts +18 -5
  29. package/node_modules/@types/node/diagnostics_channel.d.ts +237 -3
  30. package/node_modules/@types/node/dns.d.ts +1 -1
  31. package/node_modules/@types/node/ffi.d.ts +486 -0
  32. package/node_modules/@types/node/fs/promises.d.ts +3 -0
  33. package/node_modules/@types/node/fs.d.ts +21 -6
  34. package/node_modules/@types/node/http.d.ts +25 -0
  35. package/node_modules/@types/node/index.d.ts +1 -0
  36. package/node_modules/@types/node/package.json +2 -2
  37. package/node_modules/@types/node/process.d.ts +14 -1
  38. package/node_modules/@types/node/quic.d.ts +92 -11
  39. package/node_modules/@types/node/sqlite.d.ts +55 -0
  40. package/node_modules/@types/node/stream/iter.d.ts +150 -0
  41. package/node_modules/@types/node/stream.d.ts +32 -0
  42. package/node_modules/@types/node/test.d.ts +112 -2
  43. package/node_modules/@types/node/ts5.6/index.d.ts +1 -0
  44. package/node_modules/@types/node/ts5.7/index.d.ts +1 -0
  45. package/node_modules/@types/node/util.d.ts +19 -2
  46. package/node_modules/@types/node/v8.d.ts +84 -2
  47. package/node_modules/@types/node/worker_threads.d.ts +8 -7
  48. package/node_modules/@zuplo/core/package.json +1 -1
  49. package/node_modules/@zuplo/graphql/out/esm/index.js +11 -11
  50. package/node_modules/@zuplo/graphql/out/esm/index.js.map +1 -1
  51. package/node_modules/@zuplo/graphql/package.json +1 -1
  52. package/node_modules/@zuplo/openapi-tools/package.json +1 -1
  53. package/node_modules/@zuplo/otel/package.json +1 -1
  54. package/node_modules/@zuplo/runtime/out/esm/{chunk-54PA7VDV.js → chunk-4QJJMELB.js} +1 -1
  55. package/node_modules/@zuplo/runtime/out/esm/{chunk-54PA7VDV.js.map → chunk-4QJJMELB.js.map} +1 -1
  56. package/node_modules/@zuplo/runtime/out/esm/chunk-5CYWMN74.js +402 -0
  57. package/node_modules/@zuplo/runtime/out/esm/chunk-5CYWMN74.js.map +1 -0
  58. package/node_modules/@zuplo/runtime/out/esm/index.js +1 -1
  59. package/node_modules/@zuplo/runtime/out/esm/index.js.map +1 -1
  60. package/node_modules/@zuplo/runtime/out/esm/mcp-gateway/index.js +7 -7
  61. package/node_modules/@zuplo/runtime/out/esm/mcp-gateway/index.js.map +1 -1
  62. package/node_modules/@zuplo/runtime/out/esm/mocks/index.js +1 -1
  63. package/node_modules/@zuplo/runtime/out/types/index.d.ts +109 -19
  64. package/node_modules/@zuplo/runtime/out/types/mcp-gateway/index.d.ts +33 -7
  65. package/node_modules/@zuplo/runtime/package.json +1 -1
  66. package/node_modules/iconv-lite/encodings/sbcs-data.js +2 -0
  67. package/node_modules/iconv-lite/encodings/utf32.js +10 -3
  68. package/node_modules/iconv-lite/package.json +2 -2
  69. package/node_modules/iconv-lite/types/encodings.d.ts +2 -0
  70. package/node_modules/protobufjs/dist/light/protobuf.js +2 -2
  71. package/node_modules/protobufjs/dist/light/protobuf.min.js +2 -2
  72. package/node_modules/protobufjs/dist/minimal/protobuf.js +2 -2
  73. package/node_modules/protobufjs/dist/minimal/protobuf.min.js +2 -2
  74. package/node_modules/protobufjs/dist/protobuf.js +5 -2
  75. package/node_modules/protobufjs/dist/protobuf.js.map +1 -1
  76. package/node_modules/protobufjs/dist/protobuf.min.js +3 -3
  77. package/node_modules/protobufjs/dist/protobuf.min.js.map +1 -1
  78. package/node_modules/protobufjs/package.json +1 -1
  79. package/node_modules/protobufjs/src/parse.js +3 -0
  80. package/node_modules/toad-cache/README.md +10 -9
  81. package/node_modules/toad-cache/dist/toad-cache.cjs +139 -139
  82. package/node_modules/toad-cache/dist/toad-cache.mjs +136 -140
  83. package/node_modules/toad-cache/package.json +8 -8
  84. package/node_modules/toad-cache/toad-cache.d.cts +20 -14
  85. package/node_modules/toad-cache/toad-cache.d.ts +18 -14
  86. package/package.json +6 -6
  87. package/node_modules/@zuplo/runtime/out/esm/chunk-36XLJ4X6.js +0 -389
  88. package/node_modules/@zuplo/runtime/out/esm/chunk-36XLJ4X6.js.map +0 -1
  89. /package/node_modules/@zuplo/runtime/out/esm/{chunk-36XLJ4X6.js.LEGAL.txt → chunk-5CYWMN74.js.LEGAL.txt} +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "protobufjs",
3
- "version": "7.6.4",
3
+ "version": "7.6.5",
4
4
  "versionScheme": "~",
5
5
  "description": "Protocol Buffers for JavaScript (& TypeScript).",
6
6
  "author": "Daniel Wirtz <dcode+protobufjs@dcode.io>",
@@ -678,6 +678,9 @@ function parse(source, root, options) {
678
678
  }
679
679
 
680
680
  while (token !== "=") {
681
+ if (token === null) {
682
+ throw illegal(token, "end of input");
683
+ }
681
684
  if (token === "(") {
682
685
  var parensValue = next();
683
686
  skip(")");
@@ -144,7 +144,7 @@ console.log(cache.keys())
144
144
 
145
145
  ### Property
146
146
 
147
- Max items to hold in cache (1000)
147
+ Max items to hold in cache (1000). Must be a non-negative integer; `0` means no size limit.
148
148
 
149
149
  **Example**
150
150
 
@@ -201,7 +201,7 @@ cache.size // 0 - it's a new cache!
201
201
 
202
202
  ### Property
203
203
 
204
- Milliseconds an item will remain in cache; lazy expiration upon next `get()` of an item
204
+ Milliseconds an item will remain in cache; lazy expiration upon next `get()` of an item. Must be a non-negative integer; `0` disables expiration.
205
205
 
206
206
  **Example**
207
207
 
@@ -211,6 +211,8 @@ const cache = new Lru()
211
211
  cache.ttl = 3e4
212
212
  ```
213
213
 
214
+ Note: entries stored while `ttl` was `0` have no expiry timestamp, so enabling a TTL at runtime immediately expires them on their next `get()`. Prefer setting the TTL via the constructor.
215
+
214
216
  ## Hit/miss/expiration tracking
215
217
 
216
218
  In case you want to gather information on cache hit/miss/expiration ratio, as well as cache size and eviction statistics, you can use LruHitStatistics class:
@@ -218,13 +220,12 @@ In case you want to gather information on cache hit/miss/expiration ratio, as we
218
220
  ```js
219
221
  const sharedRecord = new HitStatisticsRecord() // if you want to use single record object for all of caches, create it manually and pass to each cache
220
222
 
221
- const cache = new LruHitStatistics({
222
- cacheId: 'some-cache-id',
223
- globalStatisticsRecord: sharedRecord,
224
- statisticTtlInHours: 24, // how often to reset statistics. On every rotation previously accumulated data is removed
225
- max: 1000,
226
- ttlInMsecs: 0,
227
- })
223
+ const max = 1000
224
+ const ttlInMsecs = 0
225
+ const cacheId = 'some-cache-id'
226
+ const statisticTtlInHours = 24 // how often to reset statistics. On every rotation previously accumulated data is removed
227
+
228
+ const cache = new LruHitStatistics(max, ttlInMsecs, cacheId, sharedRecord, statisticTtlInHours)
228
229
  ```
229
230
 
230
231
  You can retrieve accumulated statistics from the cache, or from the record directly:
@@ -3,19 +3,30 @@
3
3
  *
4
4
  * @copyright 2026 Igor Savin <kibertoad@gmail.com>
5
5
  * @license MIT
6
- * @version 3.7.0
6
+ * @version 3.7.3
7
7
  */
8
8
  'use strict';
9
9
 
10
+ /**
11
+ * Validates the shared cache constructor parameters.
12
+ * Both values must be non-negative integers.
13
+ *
14
+ * @param {number} max
15
+ * @param {number} ttlInMsecs
16
+ */
17
+ function validateCacheParams(max, ttlInMsecs) {
18
+ if (typeof max !== 'number' || !Number.isInteger(max) || max < 0) {
19
+ throw new Error('Invalid max value')
20
+ }
21
+
22
+ if (typeof ttlInMsecs !== 'number' || !Number.isInteger(ttlInMsecs) || ttlInMsecs < 0) {
23
+ throw new Error('Invalid ttl value')
24
+ }
25
+ }
26
+
10
27
  class FifoMap {
11
28
  constructor(max = 1000, ttlInMsecs = 0) {
12
- if (isNaN(max) || max < 0) {
13
- throw new Error('Invalid max value')
14
- }
15
-
16
- if (isNaN(ttlInMsecs) || ttlInMsecs < 0) {
17
- throw new Error('Invalid ttl value')
18
- }
29
+ validateCacheParams(max, ttlInMsecs);
19
30
 
20
31
  this.first = null;
21
32
  this.items = new Map();
@@ -29,15 +40,15 @@ class FifoMap {
29
40
  }
30
41
 
31
42
  clear() {
32
- this.items = new Map();
43
+ this.items.clear();
33
44
  this.first = null;
34
45
  this.last = null;
35
46
  }
36
47
 
37
48
  delete(key) {
38
- if (this.items.has(key)) {
39
- const deletedItem = this.items.get(key);
49
+ const deletedItem = this.items.get(key);
40
50
 
51
+ if (deletedItem !== undefined) {
41
52
  this.items.delete(key);
42
53
 
43
54
  if (deletedItem.prev !== null) {
@@ -81,15 +92,17 @@ class FifoMap {
81
92
  }
82
93
 
83
94
  expiresAt(key) {
84
- if (this.items.has(key)) {
85
- return this.items.get(key).expiry
95
+ const item = this.items.get(key);
96
+
97
+ if (item !== undefined) {
98
+ return item.expiry
86
99
  }
87
100
  }
88
101
 
89
102
  get(key) {
90
- if (this.items.has(key)) {
91
- const item = this.items.get(key);
103
+ const item = this.items.get(key);
92
104
 
105
+ if (item !== undefined) {
93
106
  if (this.ttl > 0 && item.expiry <= Date.now()) {
94
107
  this.delete(key);
95
108
  return
@@ -100,10 +113,10 @@ class FifoMap {
100
113
  }
101
114
 
102
115
  getMany(keys) {
103
- const result = [];
116
+ const result = new Array(keys.length);
104
117
 
105
118
  for (var i = 0; i < keys.length; i++) {
106
- result.push(this.get(keys[i]));
119
+ result[i] = this.get(keys[i]);
107
120
  }
108
121
 
109
122
  return result
@@ -115,17 +128,17 @@ class FifoMap {
115
128
 
116
129
  set(key, value) {
117
130
  // Replace existing item
118
- if (this.items.has(key)) {
119
- const item = this.items.get(key);
120
- item.value = value;
131
+ const existing = this.items.get(key);
121
132
 
122
- item.expiry = this.ttl > 0 ? Date.now() + this.ttl : this.ttl;
133
+ if (existing !== undefined) {
134
+ existing.value = value;
135
+ existing.expiry = this.ttl > 0 ? Date.now() + this.ttl : this.ttl;
123
136
 
124
137
  return
125
138
  }
126
139
 
127
140
  // Add new item
128
- if (this.max > 0 && this.size === this.max) {
141
+ if (this.max > 0 && this.size >= this.max) {
129
142
  this.evict();
130
143
  }
131
144
 
@@ -150,13 +163,7 @@ class FifoMap {
150
163
 
151
164
  class FifoObject {
152
165
  constructor(max = 1000, ttlInMsecs = 0) {
153
- if (isNaN(max) || max < 0) {
154
- throw new Error('Invalid max value')
155
- }
156
-
157
- if (isNaN(ttlInMsecs) || ttlInMsecs < 0) {
158
- throw new Error('Invalid ttl value')
159
- }
166
+ validateCacheParams(max, ttlInMsecs);
160
167
 
161
168
  this.first = null;
162
169
  this.items = Object.create(null);
@@ -174,9 +181,9 @@ class FifoObject {
174
181
  }
175
182
 
176
183
  delete(key) {
177
- if (Object.prototype.hasOwnProperty.call(this.items, key)) {
178
- const deletedItem = this.items[key];
184
+ const deletedItem = this.items[key];
179
185
 
186
+ if (deletedItem !== undefined) {
180
187
  delete this.items[key];
181
188
  this.size--;
182
189
 
@@ -221,15 +228,17 @@ class FifoObject {
221
228
  }
222
229
 
223
230
  expiresAt(key) {
224
- if (Object.prototype.hasOwnProperty.call(this.items, key)) {
225
- return this.items[key].expiry
231
+ const item = this.items[key];
232
+
233
+ if (item !== undefined) {
234
+ return item.expiry
226
235
  }
227
236
  }
228
237
 
229
238
  get(key) {
230
- if (Object.prototype.hasOwnProperty.call(this.items, key)) {
231
- const item = this.items[key];
239
+ const item = this.items[key];
232
240
 
241
+ if (item !== undefined) {
233
242
  if (this.ttl > 0 && item.expiry <= Date.now()) {
234
243
  this.delete(key);
235
244
  return
@@ -240,10 +249,10 @@ class FifoObject {
240
249
  }
241
250
 
242
251
  getMany(keys) {
243
- const result = [];
252
+ const result = new Array(keys.length);
244
253
 
245
254
  for (var i = 0; i < keys.length; i++) {
246
- result.push(this.get(keys[i]));
255
+ result[i] = this.get(keys[i]);
247
256
  }
248
257
 
249
258
  return result
@@ -255,17 +264,17 @@ class FifoObject {
255
264
 
256
265
  set(key, value) {
257
266
  // Replace existing item
258
- if (Object.prototype.hasOwnProperty.call(this.items, key)) {
259
- const item = this.items[key];
260
- item.value = value;
267
+ const existing = this.items[key];
261
268
 
262
- item.expiry = this.ttl > 0 ? Date.now() + this.ttl : this.ttl;
269
+ if (existing !== undefined) {
270
+ existing.value = value;
271
+ existing.expiry = this.ttl > 0 ? Date.now() + this.ttl : this.ttl;
263
272
 
264
273
  return
265
274
  }
266
275
 
267
276
  // Add new item
268
- if (this.max > 0 && this.size === this.max) {
277
+ if (this.max > 0 && this.size >= this.max) {
269
278
  this.evict();
270
279
  }
271
280
 
@@ -288,6 +297,26 @@ class FifoObject {
288
297
  }
289
298
  }
290
299
 
300
+ /**
301
+ * Creates a zeroed statistics record for a single collection window.
302
+ *
303
+ * @returns {object}
304
+ */
305
+ function createEmptyStatisticsRecord() {
306
+ return {
307
+ cacheSize: 0,
308
+ hits: 0,
309
+ falsyHits: 0,
310
+ emptyHits: 0,
311
+ misses: 0,
312
+ expirations: 0,
313
+ evictions: 0,
314
+ invalidateOne: 0,
315
+ invalidateAll: 0,
316
+ sets: 0,
317
+ }
318
+ }
319
+
291
320
  class HitStatisticsRecord {
292
321
  constructor() {
293
322
  this.records = {};
@@ -295,35 +324,17 @@ class HitStatisticsRecord {
295
324
 
296
325
  initForCache(cacheId, currentTimeStamp) {
297
326
  this.records[cacheId] = {
298
- [currentTimeStamp]: {
299
- cacheSize: 0,
300
- hits: 0,
301
- falsyHits: 0,
302
- emptyHits: 0,
303
- misses: 0,
304
- expirations: 0,
305
- evictions: 0,
306
- invalidateOne: 0,
307
- invalidateAll: 0,
308
- sets: 0,
309
- },
327
+ [currentTimeStamp]: createEmptyStatisticsRecord(),
310
328
  };
311
329
  }
312
330
 
313
331
  resetForCache(cacheId) {
332
+ if (!this.records[cacheId]) {
333
+ return
334
+ }
335
+
314
336
  for (let key of Object.keys(this.records[cacheId])) {
315
- this.records[cacheId][key] = {
316
- cacheSize: 0,
317
- hits: 0,
318
- falsyHits: 0,
319
- emptyHits: 0,
320
- misses: 0,
321
- expirations: 0,
322
- evictions: 0,
323
- invalidateOne: 0,
324
- invalidateAll: 0,
325
- sets: 0,
326
- };
337
+ this.records[cacheId][key] = createEmptyStatisticsRecord();
327
338
  }
328
339
  }
329
340
 
@@ -334,13 +345,7 @@ class HitStatisticsRecord {
334
345
 
335
346
  class LruMap {
336
347
  constructor(max = 1000, ttlInMsecs = 0) {
337
- if (isNaN(max) || max < 0) {
338
- throw new Error('Invalid max value')
339
- }
340
-
341
- if (isNaN(ttlInMsecs) || ttlInMsecs < 0) {
342
- throw new Error('Invalid ttl value')
343
- }
348
+ validateCacheParams(max, ttlInMsecs);
344
349
 
345
350
  this.first = null;
346
351
  this.items = new Map();
@@ -374,6 +379,7 @@ class LruMap {
374
379
  prev.next = next;
375
380
  }
376
381
 
382
+ /* v8 ignore next 3 -- next is always non-null here: the early return above guarantees item !== this.last in a well-formed list */
377
383
  if (next !== null) {
378
384
  next.prev = prev;
379
385
  }
@@ -382,15 +388,15 @@ class LruMap {
382
388
  }
383
389
 
384
390
  clear() {
385
- this.items = new Map();
391
+ this.items.clear();
386
392
  this.first = null;
387
393
  this.last = null;
388
394
  }
389
395
 
390
396
  delete(key) {
391
- if (this.items.has(key)) {
392
- const item = this.items.get(key);
397
+ const item = this.items.get(key);
393
398
 
399
+ if (item !== undefined) {
394
400
  this.items.delete(key);
395
401
 
396
402
  if (item.prev !== null) {
@@ -434,15 +440,17 @@ class LruMap {
434
440
  }
435
441
 
436
442
  expiresAt(key) {
437
- if (this.items.has(key)) {
438
- return this.items.get(key).expiry
443
+ const item = this.items.get(key);
444
+
445
+ if (item !== undefined) {
446
+ return item.expiry
439
447
  }
440
448
  }
441
449
 
442
450
  get(key) {
443
- if (this.items.has(key)) {
444
- const item = this.items.get(key);
451
+ const item = this.items.get(key);
445
452
 
453
+ if (item !== undefined) {
446
454
  // Item has already expired
447
455
  if (this.ttl > 0 && item.expiry <= Date.now()) {
448
456
  this.delete(key);
@@ -456,10 +464,10 @@ class LruMap {
456
464
  }
457
465
 
458
466
  getMany(keys) {
459
- const result = [];
467
+ const result = new Array(keys.length);
460
468
 
461
469
  for (var i = 0; i < keys.length; i++) {
462
- result.push(this.get(keys[i]));
470
+ result[i] = this.get(keys[i]);
463
471
  }
464
472
 
465
473
  return result
@@ -471,21 +479,18 @@ class LruMap {
471
479
 
472
480
  set(key, value) {
473
481
  // Replace existing item
474
- if (this.items.has(key)) {
475
- const item = this.items.get(key);
476
- item.value = value;
482
+ const existing = this.items.get(key);
477
483
 
478
- item.expiry = this.ttl > 0 ? Date.now() + this.ttl : this.ttl;
479
-
480
- if (this.last !== item) {
481
- this.bumpLru(item);
482
- }
484
+ if (existing !== undefined) {
485
+ existing.value = value;
486
+ existing.expiry = this.ttl > 0 ? Date.now() + this.ttl : this.ttl;
487
+ this.bumpLru(existing);
483
488
 
484
489
  return
485
490
  }
486
491
 
487
492
  // Add new item
488
- if (this.max > 0 && this.size === this.max) {
493
+ if (this.max > 0 && this.size >= this.max) {
489
494
  this.evict();
490
495
  }
491
496
 
@@ -510,13 +515,7 @@ class LruMap {
510
515
 
511
516
  class LruObject {
512
517
  constructor(max = 1000, ttlInMsecs = 0) {
513
- if (isNaN(max) || max < 0) {
514
- throw new Error('Invalid max value')
515
- }
516
-
517
- if (isNaN(ttlInMsecs) || ttlInMsecs < 0) {
518
- throw new Error('Invalid ttl value')
519
- }
518
+ validateCacheParams(max, ttlInMsecs);
520
519
 
521
520
  this.first = null;
522
521
  this.items = Object.create(null);
@@ -547,6 +546,7 @@ class LruObject {
547
546
  prev.next = next;
548
547
  }
549
548
 
549
+ /* v8 ignore next 3 -- next is always non-null here: the early return above guarantees item !== this.last in a well-formed list */
550
550
  if (next !== null) {
551
551
  next.prev = prev;
552
552
  }
@@ -562,9 +562,9 @@ class LruObject {
562
562
  }
563
563
 
564
564
  delete(key) {
565
- if (Object.prototype.hasOwnProperty.call(this.items, key)) {
566
- const item = this.items[key];
565
+ const item = this.items[key];
567
566
 
567
+ if (item !== undefined) {
568
568
  delete this.items[key];
569
569
  this.size--;
570
570
 
@@ -609,15 +609,17 @@ class LruObject {
609
609
  }
610
610
 
611
611
  expiresAt(key) {
612
- if (Object.prototype.hasOwnProperty.call(this.items, key)) {
613
- return this.items[key].expiry
612
+ const item = this.items[key];
613
+
614
+ if (item !== undefined) {
615
+ return item.expiry
614
616
  }
615
617
  }
616
618
 
617
619
  get(key) {
618
- if (Object.prototype.hasOwnProperty.call(this.items, key)) {
619
- const item = this.items[key];
620
+ const item = this.items[key];
620
621
 
622
+ if (item !== undefined) {
621
623
  // Item has already expired
622
624
  if (this.ttl > 0 && item.expiry <= Date.now()) {
623
625
  this.delete(key);
@@ -631,10 +633,10 @@ class LruObject {
631
633
  }
632
634
 
633
635
  getMany(keys) {
634
- const result = [];
636
+ const result = new Array(keys.length);
635
637
 
636
638
  for (var i = 0; i < keys.length; i++) {
637
- result.push(this.get(keys[i]));
639
+ result[i] = this.get(keys[i]);
638
640
  }
639
641
 
640
642
  return result
@@ -646,21 +648,18 @@ class LruObject {
646
648
 
647
649
  set(key, value) {
648
650
  // Replace existing item
649
- if (Object.prototype.hasOwnProperty.call(this.items, key)) {
650
- const item = this.items[key];
651
- item.value = value;
652
-
653
- item.expiry = this.ttl > 0 ? Date.now() + this.ttl : this.ttl;
651
+ const existing = this.items[key];
654
652
 
655
- if (this.last !== item) {
656
- this.bumpLru(item);
657
- }
653
+ if (existing !== undefined) {
654
+ existing.value = value;
655
+ existing.expiry = this.ttl > 0 ? Date.now() + this.ttl : this.ttl;
656
+ this.bumpLru(existing);
658
657
 
659
658
  return
660
659
  }
661
660
 
662
661
  // Add new item
663
- if (this.max > 0 && this.size === this.max) {
662
+ if (this.max > 0 && this.size >= this.max) {
664
663
  this.evict();
665
664
  }
666
665
 
@@ -702,32 +701,24 @@ class HitStatistics {
702
701
 
703
702
  this.collectionStart = new Date();
704
703
  this.currentTimeStamp = getTimestamp(this.collectionStart);
704
+ this.archiveAfter = this.collectionStart.getTime() + this.statisticTtlInHours * 3_600_000;
705
705
 
706
706
  this.records = globalStatisticsRecord || new HitStatisticsRecord();
707
707
  this.records.initForCache(this.cacheId, this.currentTimeStamp);
708
708
  }
709
709
 
710
710
  get currentRecord() {
711
+ const cacheRecords = this.records.records[this.cacheId];
711
712
  // safety net
712
- /* c8 ignore next 14 */
713
- if (!this.records.records[this.cacheId][this.currentTimeStamp]) {
714
- this.records.records[this.cacheId][this.currentTimeStamp] = {
715
- cacheSize: 0,
716
- hits: 0,
717
- falsyHits: 0,
718
- emptyHits: 0,
719
- misses: 0,
720
- expirations: 0,
721
- evictions: 0,
722
- sets: 0,
723
- invalidateOne: 0,
724
- invalidateAll: 0,
725
- };
713
+ /* c8 ignore next 3 */
714
+ if (!cacheRecords[this.currentTimeStamp]) {
715
+ cacheRecords[this.currentTimeStamp] = createEmptyStatisticsRecord();
726
716
  }
727
717
 
728
- return this.records.records[this.cacheId][this.currentTimeStamp]
718
+ return cacheRecords[this.currentTimeStamp]
729
719
  }
730
720
 
721
+ /* v8 ignore next 3 -- kept for compatibility, no longer used internally */
731
722
  hoursPassed() {
732
723
  return (Date.now() - this.collectionStart) / 1000 / 60 / 60
733
724
  }
@@ -786,9 +777,10 @@ class HitStatistics {
786
777
  }
787
778
 
788
779
  archiveIfNeeded() {
789
- if (this.hoursPassed() >= this.statisticTtlInHours) {
780
+ if (Date.now() >= this.archiveAfter) {
790
781
  this.collectionStart = new Date();
791
782
  this.currentTimeStamp = getTimestamp(this.collectionStart);
783
+ this.archiveAfter = this.collectionStart.getTime() + this.statisticTtlInHours * 3_600_000;
792
784
  this.records.initForCache(this.cacheId, this.currentTimeStamp);
793
785
  }
794
786
  }
@@ -796,7 +788,10 @@ class HitStatistics {
796
788
 
797
789
  class LruObjectHitStatistics extends LruObject {
798
790
  constructor(max, ttlInMsecs, cacheId, globalStatisticsRecord, statisticTtlInHours) {
799
- super(max || 1000, ttlInMsecs || 0);
791
+ // Pass through as-is: the base constructor applies the 1000/0 defaults for
792
+ // omitted (undefined) values and validates everything else, so explicit 0
793
+ // stays unlimited and null/NaN are rejected the same way as the base class.
794
+ super(max, ttlInMsecs);
800
795
 
801
796
  if (!cacheId) {
802
797
  throw new Error('Cache id is mandatory')
@@ -820,15 +815,19 @@ class LruObjectHitStatistics extends LruObject {
820
815
  }
821
816
 
822
817
  evict() {
818
+ const hadItems = this.size > 0;
823
819
  super.evict();
824
- this.hitStatistics.addEviction();
820
+ if (hadItems) {
821
+ this.hitStatistics.addEviction();
822
+ }
825
823
  this.hitStatistics.setCacheSize(this.size);
826
824
  }
827
825
 
828
826
  delete(key, isExpiration = false) {
827
+ const existed = this.items[key] !== undefined;
829
828
  super.delete(key);
830
829
 
831
- if (!isExpiration) {
830
+ if (existed && !isExpiration) {
832
831
  this.hitStatistics.addInvalidateOne();
833
832
  }
834
833
  this.hitStatistics.setCacheSize(this.size);
@@ -842,9 +841,9 @@ class LruObjectHitStatistics extends LruObject {
842
841
  }
843
842
 
844
843
  get(key) {
845
- if (Object.prototype.hasOwnProperty.call(this.items, key)) {
846
- const item = this.items[key];
844
+ const item = this.items[key];
847
845
 
846
+ if (item !== undefined) {
848
847
  // Item has already expired
849
848
  if (this.ttl > 0 && item.expiry <= Date.now()) {
850
849
  this.delete(key, true);
@@ -856,9 +855,10 @@ class LruObjectHitStatistics extends LruObject {
856
855
  this.bumpLru(item);
857
856
  if (!item.value) {
858
857
  this.hitStatistics.addFalsyHit();
859
- }
860
- if (item.value === undefined || item.value === null || item.value === '') {
861
- this.hitStatistics.addEmptyHit();
858
+ // Empty values are a subset of falsy values
859
+ if (item.value === undefined || item.value === null || item.value === '') {
860
+ this.hitStatistics.addEmptyHit();
861
+ }
862
862
  }
863
863
  this.hitStatistics.addHit();
864
864
  return item.value