btn-cache 1.0.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.
@@ -0,0 +1,242 @@
1
+ import EventEmitter from "events";
2
+ type BaseCacheOptions = {
3
+ evictionPolicy: "LRU" | "LFU" | "FIFO" | "RANDOM";
4
+ deleteOnExpire: boolean;
5
+ maxKeys: number;
6
+ useClones: boolean;
7
+ checkPeriod: number;
8
+ };
9
+ type invalidationPolicyOptions<T> = {
10
+ invalidationPolicy: "NONE";
11
+ } | {
12
+ invalidationPolicy: "TTL";
13
+ stdTTL: number;
14
+ } | {
15
+ invalidationPolicy: "EVENT";
16
+ predicate: (data: StoredData<T>) => boolean;
17
+ };
18
+ export type CacheOptions<T> = BaseCacheOptions & invalidationPolicyOptions<T>;
19
+ export type CacheOptionsInput<T> = Partial<BaseCacheOptions> & ({
20
+ invalidationPolicy?: "NONE";
21
+ } | {
22
+ invalidationPolicy?: "TTL";
23
+ stdTTL?: number;
24
+ } | {
25
+ invalidationPolicy?: "EVENT";
26
+ predicate?: (data: StoredData<T>) => boolean;
27
+ });
28
+ export type CacheStats = {
29
+ keys: number;
30
+ hits: number;
31
+ misses: number;
32
+ evictions: number;
33
+ ksize: number;
34
+ vsize: number;
35
+ };
36
+ export type StoredData<T> = {
37
+ value: T;
38
+ ttl?: number;
39
+ numberOfAccess: number;
40
+ lastAccessTimeStamp: number;
41
+ };
42
+ export type CacheEventMap<T> = {
43
+ set: [key: string | number, data: T];
44
+ get: [key: string | number, data: T];
45
+ del: [key: string | number, data?: T];
46
+ miss: [key: string | number];
47
+ expired: [key: string | number, cachedData: StoredData<T>];
48
+ error: [message: string];
49
+ evicted: [key: string | number, data?: T];
50
+ flush: [];
51
+ "flush-stats": [];
52
+ };
53
+ export declare class BTNCache<T = any> extends EventEmitter<CacheEventMap<T>> {
54
+ private data;
55
+ private options;
56
+ private stats;
57
+ private checkTimeout;
58
+ private queue;
59
+ /**
60
+ * Creates a new in memory cache using the options given to the constructor
61
+ * @param options the options object: \
62
+ * **evictionPolicy**: the type of eviction policy, one of RANDOM, LRU, LFU. (default: RANDOM)\
63
+ * **deleteOnExpire**: if the data gets deleted when it expires. \
64
+ * **maxKeys**: maximum amount of keys that can be stored in the cache, defaults to -1 (unlimited) \
65
+ * **useClones**: if the get and set operators copy the entered/received data or return a reference \
66
+ * **checkPeriod**: how often the cache runs an invalidation check. \
67
+ *
68
+ * **invalidationPolicy**: the type of invalidation policy, one of NONE, TTL or EVENT. (default: TTL) \
69
+ *
70
+ * When *invalidationPolicy == "TTL"*:
71
+ * **stdTTL**: the standard time to live on any data point unless specified other wise.
72
+ *
73
+ * When *invalidationPolicy == "EVENT"*:
74
+ * **predicate**: function that given a data point's state, returns if it should be considered invalid or not.
75
+ */
76
+ constructor(options?: CacheOptionsInput<T>);
77
+ /**
78
+ * Retrieves a data point from the cache
79
+ * @emits "miss" Indicates that a cache miss happened
80
+ * @emits "get" Indicates that a cache hit happened
81
+ * @param key Key of the data to retrieve
82
+ */
83
+ get(key: string | number): T | undefined;
84
+ /**
85
+ * Method to get many keys at once
86
+ * @emits "miss" Indicates that a cache miss happened
87
+ * @emits "get" Indicates that a cache hit happened
88
+ * @param keys Array of keys
89
+ * @returns
90
+ */
91
+ many_get(keys: (string | number)[]): {
92
+ [key: string]: T;
93
+ [key: number]: T;
94
+ };
95
+ /**
96
+ * Function to set a certain key in the cache.
97
+ * @param key Key of the data to be set.
98
+ * @param data The data to be entered into the cache.
99
+ * @param ttl The TTL of the new data point, will be ignored if the invalidation policy isn't set to TTL
100
+ * @emits "set" Indicates that the data has been set successfully
101
+ * @returns
102
+ */
103
+ set(key: string | number, data: T, ttl?: number): boolean;
104
+ /**
105
+ * Function to add multiple data points to the cache
106
+ * @param keyValueSet All of the keys that will be added, optional ttl argument will be ignored if not in TTL invalidation mode.
107
+ * @emits "set" Indicates that a value has been set correctly.
108
+ */
109
+ many_set(keyValueSet: {
110
+ [key: string | number]: {
111
+ ttl?: number;
112
+ data: T;
113
+ };
114
+ }): void;
115
+ /**
116
+ * Function to get a key while removing it from the cache
117
+ * @param key Key to be taken out of the cache
118
+ * @returns value that was stored to that key
119
+ */
120
+ take(key: string | number): T | undefined;
121
+ /**
122
+ * Function to check if a key is present in the cache
123
+ * @param key key for the lookup
124
+ * @returns a boolean value specifying if the value is present.
125
+ */
126
+ has(key: string | number): boolean;
127
+ /**
128
+ * Function to delete a certain set of keys from the cache
129
+ * @emits "del" Indicates that the data has been deleted successfully
130
+ * @param keys The array of keys to be deleted.
131
+ * @returns Number of elements deleted from the cache.
132
+ */
133
+ del(keys: (string | number)[]): number;
134
+ /**
135
+ * Function to change the TTL of a given key in TTL mode
136
+ * @param key key to be changed
137
+ * @param newTTL the new TTL that will be assigned, if less than 0 key will be deleted.
138
+ * @returns boolean value representing if the change was successful
139
+ */
140
+ ttl(key: string | number, newTTL?: number): boolean;
141
+ /**
142
+ * Function to get metadata about the key, such as TTL, time since last accessed, number of accesses
143
+ * @param key key for the lookup
144
+ * @returns metadata information about the key.
145
+ */
146
+ getMeta(key: string | number): {
147
+ lastAccessTime: number;
148
+ numberOfAccesses: number;
149
+ ttl: number | undefined;
150
+ } | undefined;
151
+ /**
152
+ * Function to get the data of the cache
153
+ * @returns the statistics of the cache
154
+ */
155
+ getStats(): CacheStats;
156
+ /**
157
+ * Function to flush all the data and the statistics of the cache
158
+ */
159
+ flushAll(): void;
160
+ /**
161
+ * Function to flush the statistics of the cache
162
+ */
163
+ flushStats(): void;
164
+ /**
165
+ * Function to change some of the settings of the cache
166
+ * @param newOptions
167
+ */
168
+ setSettings(newOptions: CacheOptionsInput<T>): void;
169
+ /**
170
+ * Function to close the cache.
171
+ */
172
+ close(): void;
173
+ /**
174
+ * Function that returns all the present keys in the cache
175
+ * @returns List of keys present in the cache.
176
+ */
177
+ keys(): (string | number)[];
178
+ /**
179
+ * Internal function to check the keys for expiration
180
+ * @param start decides if the next check will happen
181
+ */
182
+ private _checkClock;
183
+ /**
184
+ * This function will evict a data point based on the set options
185
+ * @param numberOfEvictions number of keys that will get evicted, defaults to 1
186
+ * @emits "error" will emit an error if an undefined key is trying to be evicted.
187
+ */
188
+ private _evictData;
189
+ /**
190
+ * Internal function that implements the RANDOM eviction policy
191
+ * @returns the key to be removed
192
+ */
193
+ private _evictRandom;
194
+ /**
195
+ * Internal function that implements the LRU eviction policy
196
+ * @returns the key to be removed
197
+ */
198
+ private _evictLRU;
199
+ /**
200
+ * Internal function that implements the LFU eviction policy
201
+ * @returns the key to be removed
202
+ */
203
+ private _evictLFU;
204
+ /**
205
+ * Internal function that implements the FIFO eviction policy
206
+ * @returns the key to be removed
207
+ */
208
+ private _evictFIFO;
209
+ /**
210
+ * Internal function to check if the cache is full, if so evict data according to the eviction policy
211
+ * @param [padding=0] How big the empty space should be.
212
+ */
213
+ private _checkAndEvict;
214
+ /**
215
+ * Internal method to roughly calculate the size of the value
216
+ * @param value Value to process its size
217
+ */
218
+ private _getDataLength;
219
+ /**
220
+ * Internal method to check if a data point is invalidated or not.
221
+ * @emits "expired" Indicates that some data has been invalidated.
222
+ * @param key The key of the checked data
223
+ * @param data The Stored data
224
+ * @returns If the data is invalidated or not
225
+ */
226
+ private _checkData;
227
+ /**
228
+ * Internal method to standardize the returns of getters.
229
+ * @param data The data to be unwrapped
230
+ * @param asClone Option if to return a copy of the data or a reference
231
+ */
232
+ private _unwrap;
233
+ /**
234
+ * Internal method to wrap any value into the stored value type.
235
+ * @param value Value that will be wrapped
236
+ * @param ttl Time to live, will be ignored if the invalidation policy is not set to "TTL"
237
+ * @param asClone If the wrapped value is a clone or a reference to the original
238
+ */
239
+ private _wrap;
240
+ }
241
+ export {};
242
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,507 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.BTNCache = void 0;
7
+ const events_1 = __importDefault(require("events"));
8
+ const clone_1 = __importDefault(require("clone"));
9
+ const DEFAULT_OPTIONS = {
10
+ evictionPolicy: "RANDOM",
11
+ deleteOnExpire: true,
12
+ maxKeys: -1,
13
+ invalidationPolicy: "TTL",
14
+ stdTTL: 500 * 1000,
15
+ useClones: true,
16
+ checkPeriod: 300 * 1000,
17
+ };
18
+ class BTNCache extends events_1.default {
19
+ /**
20
+ * Creates a new in memory cache using the options given to the constructor
21
+ * @param options the options object: \
22
+ * **evictionPolicy**: the type of eviction policy, one of RANDOM, LRU, LFU. (default: RANDOM)\
23
+ * **deleteOnExpire**: if the data gets deleted when it expires. \
24
+ * **maxKeys**: maximum amount of keys that can be stored in the cache, defaults to -1 (unlimited) \
25
+ * **useClones**: if the get and set operators copy the entered/received data or return a reference \
26
+ * **checkPeriod**: how often the cache runs an invalidation check. \
27
+ *
28
+ * **invalidationPolicy**: the type of invalidation policy, one of NONE, TTL or EVENT. (default: TTL) \
29
+ *
30
+ * When *invalidationPolicy == "TTL"*:
31
+ * **stdTTL**: the standard time to live on any data point unless specified other wise.
32
+ *
33
+ * When *invalidationPolicy == "EVENT"*:
34
+ * **predicate**: function that given a data point's state, returns if it should be considered invalid or not.
35
+ */
36
+ constructor(options = {}) {
37
+ super();
38
+ this.data = new Map();
39
+ this.queue = null;
40
+ this.options = {
41
+ ...DEFAULT_OPTIONS,
42
+ ...options,
43
+ };
44
+ if (this.options.invalidationPolicy == "EVENT" &&
45
+ typeof this.options.predicate !== "function") {
46
+ throw new Error("EVENT invalidation requires a predicate");
47
+ }
48
+ if (this.options.evictionPolicy == "FIFO") {
49
+ this.queue = [];
50
+ }
51
+ this.stats = {
52
+ keys: 0,
53
+ hits: 0,
54
+ misses: 0,
55
+ evictions: 0,
56
+ ksize: 0,
57
+ vsize: 0,
58
+ };
59
+ this._checkClock();
60
+ }
61
+ /**
62
+ * Retrieves a data point from the cache
63
+ * @emits "miss" Indicates that a cache miss happened
64
+ * @emits "get" Indicates that a cache hit happened
65
+ * @param key Key of the data to retrieve
66
+ */
67
+ get(key) {
68
+ const found = this.data.get(key);
69
+ if (found && this._checkData(key, found)) {
70
+ this.stats.hits++;
71
+ found.numberOfAccess++;
72
+ found.lastAccessTimeStamp = Date.now();
73
+ this.emit("get", key, this._unwrap(found));
74
+ return this._unwrap(found);
75
+ }
76
+ else {
77
+ this.stats.misses++;
78
+ this.emit("miss", key);
79
+ return undefined;
80
+ }
81
+ }
82
+ /**
83
+ * Method to get many keys at once
84
+ * @emits "miss" Indicates that a cache miss happened
85
+ * @emits "get" Indicates that a cache hit happened
86
+ * @param keys Array of keys
87
+ * @returns
88
+ */
89
+ many_get(keys) {
90
+ let all_found = {};
91
+ for (const key of keys) {
92
+ const found = this.data.get(key);
93
+ if (found && this._checkData(key, found)) {
94
+ this.stats.hits++;
95
+ found.numberOfAccess++;
96
+ found.lastAccessTimeStamp = Date.now();
97
+ all_found[key] = this._unwrap(found);
98
+ this.emit("get", key, this._unwrap(found));
99
+ }
100
+ else {
101
+ this.stats.misses++;
102
+ this.emit("miss", key);
103
+ }
104
+ }
105
+ return all_found;
106
+ }
107
+ /**
108
+ * Function to set a certain key in the cache.
109
+ * @param key Key of the data to be set.
110
+ * @param data The data to be entered into the cache.
111
+ * @param ttl The TTL of the new data point, will be ignored if the invalidation policy isn't set to TTL
112
+ * @emits "set" Indicates that the data has been set successfully
113
+ * @returns
114
+ */
115
+ set(key, data, ttl) {
116
+ this._checkAndEvict();
117
+ if (this.options.invalidationPolicy == "TTL" && !ttl) {
118
+ ttl = this.options.stdTTL;
119
+ }
120
+ let existent = false;
121
+ if (this.data.has(key)) {
122
+ existent = true;
123
+ this.stats.vsize -= this._getDataLength(data);
124
+ }
125
+ this.data.set(key, this._wrap(data, ttl));
126
+ this.stats.vsize += this._getDataLength(data);
127
+ if (this.options.evictionPolicy == "FIFO" && this.queue) {
128
+ this.queue.push(key);
129
+ }
130
+ if (!existent) {
131
+ this.stats.ksize += this._getDataLength(key);
132
+ this.stats.keys++;
133
+ }
134
+ this.emit("set", key, data);
135
+ return true;
136
+ }
137
+ /**
138
+ * Function to add multiple data points to the cache
139
+ * @param keyValueSet All of the keys that will be added, optional ttl argument will be ignored if not in TTL invalidation mode.
140
+ * @emits "set" Indicates that a value has been set correctly.
141
+ */
142
+ many_set(keyValueSet) {
143
+ this._checkAndEvict(Object.keys(keyValueSet).length);
144
+ for (const keyValuePair of Object.entries(keyValueSet)) {
145
+ const [key, { ttl, data }] = keyValuePair;
146
+ this.set(key, data, ttl);
147
+ this.emit("set", key, data);
148
+ }
149
+ }
150
+ /**
151
+ * Function to get a key while removing it from the cache
152
+ * @param key Key to be taken out of the cache
153
+ * @returns value that was stored to that key
154
+ */
155
+ take(key) {
156
+ const found = this.get(key);
157
+ if (found) {
158
+ this.del([key]);
159
+ }
160
+ return found;
161
+ }
162
+ /**
163
+ * Function to check if a key is present in the cache
164
+ * @param key key for the lookup
165
+ * @returns a boolean value specifying if the value is present.
166
+ */
167
+ has(key) {
168
+ const found = this.data.get(key);
169
+ if (!found)
170
+ return false;
171
+ return this._checkData(key, found);
172
+ }
173
+ /**
174
+ * Function to delete a certain set of keys from the cache
175
+ * @emits "del" Indicates that the data has been deleted successfully
176
+ * @param keys The array of keys to be deleted.
177
+ * @returns Number of elements deleted from the cache.
178
+ */
179
+ del(keys) {
180
+ let delCount = 0;
181
+ for (const key of keys) {
182
+ if (this.data.has(key)) {
183
+ const found = this.data.get(key);
184
+ this.stats.vsize -= this._getDataLength(found);
185
+ this.stats.ksize -= this._getDataLength(key);
186
+ this.stats.keys--;
187
+ delCount++;
188
+ this.data.delete(key);
189
+ if (this.options.evictionPolicy == "FIFO" && this.queue) {
190
+ this.queue = this.queue.filter((k) => key !== k);
191
+ }
192
+ this.emit("del", key, found?.value);
193
+ }
194
+ }
195
+ return delCount;
196
+ }
197
+ /**
198
+ * Function to change the TTL of a given key in TTL mode
199
+ * @param key key to be changed
200
+ * @param newTTL the new TTL that will be assigned, if less than 0 key will be deleted.
201
+ * @returns boolean value representing if the change was successful
202
+ */
203
+ ttl(key, newTTL) {
204
+ if (this.options.invalidationPolicy !== "TTL")
205
+ return false;
206
+ if (!newTTL) {
207
+ newTTL = this.options.stdTTL;
208
+ }
209
+ const found = this.data.get(key);
210
+ if (found && this._checkData(key, found)) {
211
+ if (newTTL >= 0) {
212
+ this.data.set(key, this._wrap(found.value, newTTL, false));
213
+ }
214
+ else {
215
+ this.del([key]);
216
+ }
217
+ return true;
218
+ }
219
+ else {
220
+ return false;
221
+ }
222
+ }
223
+ /**
224
+ * Function to get metadata about the key, such as TTL, time since last accessed, number of accesses
225
+ * @param key key for the lookup
226
+ * @returns metadata information about the key.
227
+ */
228
+ getMeta(key) {
229
+ const found = this.data.get(key);
230
+ if (found && this._checkData(key, found)) {
231
+ return {
232
+ lastAccessTime: found.lastAccessTimeStamp,
233
+ numberOfAccesses: found.numberOfAccess,
234
+ ttl: found.ttl,
235
+ };
236
+ }
237
+ }
238
+ /**
239
+ * Function to get the data of the cache
240
+ * @returns the statistics of the cache
241
+ */
242
+ getStats() {
243
+ return this.stats;
244
+ }
245
+ /**
246
+ * Function to flush all the data and the statistics of the cache
247
+ */
248
+ flushAll() {
249
+ this.data = new Map();
250
+ this.stats = {
251
+ keys: 0,
252
+ vsize: 0,
253
+ evictions: 0,
254
+ ksize: 0,
255
+ hits: 0,
256
+ misses: 0,
257
+ };
258
+ this.emit("flush");
259
+ }
260
+ /**
261
+ * Function to flush the statistics of the cache
262
+ */
263
+ flushStats() {
264
+ this.stats = {
265
+ keys: 0,
266
+ vsize: 0,
267
+ ksize: 0,
268
+ evictions: 0,
269
+ hits: 0,
270
+ misses: 0,
271
+ };
272
+ this.emit("flush-stats");
273
+ }
274
+ /**
275
+ * Function to change some of the settings of the cache
276
+ * @param newOptions
277
+ */
278
+ setSettings(newOptions) {
279
+ this.options = {
280
+ ...this.options,
281
+ ...newOptions,
282
+ };
283
+ this.emit("settings-change", this.options);
284
+ }
285
+ /**
286
+ * Function to close the cache.
287
+ */
288
+ close() {
289
+ if (this.checkTimeout)
290
+ clearTimeout(this.checkTimeout);
291
+ }
292
+ /**
293
+ * Function that returns all the present keys in the cache
294
+ * @returns List of keys present in the cache.
295
+ */
296
+ keys() {
297
+ const keys = [];
298
+ for (const key of this.data.keys()) {
299
+ keys.push(key);
300
+ }
301
+ return keys;
302
+ }
303
+ /**
304
+ * Internal function to check the keys for expiration
305
+ * @param start decides if the next check will happen
306
+ */
307
+ _checkClock(start = true) {
308
+ for (const [key, value] of this.data.entries()) {
309
+ this._checkData(key, value);
310
+ }
311
+ if (start && this.options.checkPeriod) {
312
+ this.checkTimeout = setTimeout(() => this._checkClock(start), this.options.checkPeriod);
313
+ this.checkTimeout.unref();
314
+ }
315
+ return;
316
+ }
317
+ /**
318
+ * This function will evict a data point based on the set options
319
+ * @param numberOfEvictions number of keys that will get evicted, defaults to 1
320
+ * @emits "error" will emit an error if an undefined key is trying to be evicted.
321
+ */
322
+ _evictData(numberOfEvictions = 1) {
323
+ const evictors = {
324
+ FIFO: () => this._evictFIFO(),
325
+ LRU: () => this._evictLRU(),
326
+ LFU: () => this._evictLFU(),
327
+ RANDOM: () => this._evictRandom(),
328
+ };
329
+ let evicted = undefined;
330
+ for (let i = 0; i < numberOfEvictions; i++) {
331
+ evicted = evictors[this.options.evictionPolicy]();
332
+ if (evicted === undefined) {
333
+ this.emit("error", "ERROR_UNDEFINED_EVICTION");
334
+ break;
335
+ }
336
+ this.emit("evicted", evicted, this.get(evicted));
337
+ this.del([evicted]);
338
+ this.stats.evictions++;
339
+ }
340
+ }
341
+ /**
342
+ * Internal function that implements the RANDOM eviction policy
343
+ * @returns the key to be removed
344
+ */
345
+ _evictRandom() {
346
+ const keys = this.keys();
347
+ if (keys.length === 0)
348
+ return undefined;
349
+ const evictedIndex = Math.floor(Math.random() * keys.length);
350
+ return keys[evictedIndex];
351
+ }
352
+ /**
353
+ * Internal function that implements the LRU eviction policy
354
+ * @returns the key to be removed
355
+ */
356
+ _evictLRU() {
357
+ const now = Date.now();
358
+ return this.keys().reduce((accumulator, current) => {
359
+ const meta = this.getMeta(current);
360
+ if (!meta)
361
+ return accumulator;
362
+ const difference = now - meta.lastAccessTime;
363
+ if (!accumulator || difference >= accumulator.difference) {
364
+ return {
365
+ key: current,
366
+ difference,
367
+ };
368
+ }
369
+ return accumulator;
370
+ }, undefined)?.key;
371
+ }
372
+ /**
373
+ * Internal function that implements the LFU eviction policy
374
+ * @returns the key to be removed
375
+ */
376
+ _evictLFU() {
377
+ return this.keys().reduce((accumulator, current) => {
378
+ const meta = this.getMeta(current);
379
+ if (!meta)
380
+ return accumulator;
381
+ if (!accumulator || meta.numberOfAccesses <= accumulator.minimum) {
382
+ return {
383
+ key: current,
384
+ minimum: meta.numberOfAccesses,
385
+ };
386
+ }
387
+ return accumulator;
388
+ }, undefined)?.key;
389
+ }
390
+ /**
391
+ * Internal function that implements the FIFO eviction policy
392
+ * @returns the key to be removed
393
+ */
394
+ _evictFIFO() {
395
+ if (this.queue) {
396
+ return this.queue.shift();
397
+ }
398
+ }
399
+ /**
400
+ * Internal function to check if the cache is full, if so evict data according to the eviction policy
401
+ * @param [padding=0] How big the empty space should be.
402
+ */
403
+ _checkAndEvict(padding = 1) {
404
+ if (this.options.maxKeys < 0)
405
+ return;
406
+ const overflow = this.stats.keys + padding - this.options.maxKeys;
407
+ if (overflow > 0) {
408
+ this._evictData(overflow);
409
+ }
410
+ }
411
+ /**
412
+ * Internal method to roughly calculate the size of the value
413
+ * @param value Value to process its size
414
+ */
415
+ _getDataLength(value) {
416
+ if (typeof value === "string") {
417
+ return value.length;
418
+ }
419
+ else if (typeof value === "number") {
420
+ return 8;
421
+ }
422
+ else {
423
+ return JSON.stringify(value).length;
424
+ }
425
+ }
426
+ /**
427
+ * Internal method to check if a data point is invalidated or not.
428
+ * @emits "expired" Indicates that some data has been invalidated.
429
+ * @param key The key of the checked data
430
+ * @param data The Stored data
431
+ * @returns If the data is invalidated or not
432
+ */
433
+ _checkData(key, data) {
434
+ let returnValue = true;
435
+ const deleteAndEmit = () => {
436
+ if (this.options.deleteOnExpire) {
437
+ returnValue = false;
438
+ this.del([key]);
439
+ }
440
+ this.emit("expired", key, data);
441
+ };
442
+ if (this.options.invalidationPolicy === "TTL") {
443
+ if (data.ttl && data.ttl < Date.now()) {
444
+ deleteAndEmit();
445
+ }
446
+ }
447
+ else if (this.options.invalidationPolicy === "EVENT") {
448
+ const predicateResult = this.options.predicate(data);
449
+ if (predicateResult) {
450
+ deleteAndEmit();
451
+ }
452
+ }
453
+ return returnValue;
454
+ }
455
+ /**
456
+ * Internal method to standardize the returns of getters.
457
+ * @param data The data to be unwrapped
458
+ * @param asClone Option if to return a copy of the data or a reference
459
+ */
460
+ _unwrap(data, asClone = true) {
461
+ if (!this.options.useClones) {
462
+ asClone = false;
463
+ }
464
+ if (asClone)
465
+ return (0, clone_1.default)(data.value);
466
+ else
467
+ return data.value;
468
+ }
469
+ /**
470
+ * Internal method to wrap any value into the stored value type.
471
+ * @param value Value that will be wrapped
472
+ * @param ttl Time to live, will be ignored if the invalidation policy is not set to "TTL"
473
+ * @param asClone If the wrapped value is a clone or a reference to the original
474
+ */
475
+ _wrap(value, ttl, asClone = true) {
476
+ if (!this.options.useClones) {
477
+ asClone = false;
478
+ }
479
+ const now = Date.now();
480
+ let lifetime = -1;
481
+ if (this.options.invalidationPolicy === "TTL") {
482
+ const TTLMultiplication = 1;
483
+ if (ttl == 0) {
484
+ lifetime = 0;
485
+ }
486
+ else if (ttl) {
487
+ lifetime = now + ttl * TTLMultiplication;
488
+ }
489
+ else {
490
+ if (this.options.stdTTL == 0) {
491
+ lifetime = 0;
492
+ }
493
+ else {
494
+ lifetime = now + this.options.stdTTL * TTLMultiplication;
495
+ }
496
+ }
497
+ }
498
+ const returned = {
499
+ value: asClone ? (0, clone_1.default)(value) : value,
500
+ ttl: lifetime,
501
+ numberOfAccess: 0,
502
+ lastAccessTimeStamp: now,
503
+ };
504
+ return returned;
505
+ }
506
+ }
507
+ exports.BTNCache = BTNCache;
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "btn-cache",
3
+ "version": "1.0.0",
4
+ "private": false,
5
+ "description": "Type safe implementation of in-memory caching inspired by node-cache",
6
+ "keywords": [
7
+ "caching",
8
+ "in-memory",
9
+ "backend",
10
+ "server-side",
11
+ "server",
12
+ "library",
13
+ "lightweight",
14
+ "light",
15
+ "simple"
16
+ ],
17
+ "author": "imaaann",
18
+ "license": "MIT",
19
+ "main": "dist/index.js",
20
+ "types": "dist/index.d.ts",
21
+ "exports": {
22
+ ".": {
23
+ "import": "./dist/index.js",
24
+ "require": "./dist/index.js",
25
+ "types": "./dist/index.d.ts"
26
+ }
27
+ },
28
+ "files": [
29
+ "dist"
30
+ ],
31
+ "scripts": {
32
+ "build": "tsc -p tsconfig.json",
33
+ "test": "vitest",
34
+ "test:run": "vitest run",
35
+ "test:watch": "vitest --watch",
36
+ "test:coverage": "vitest run --coverage"
37
+ },
38
+ "devDependencies": {
39
+ "@types/clone": "^2.1.4",
40
+ "@types/node": "^25.0.3",
41
+ "typescript": "^5.9.3",
42
+ "vitest": "^4.0.16"
43
+ },
44
+ "dependencies": {
45
+ "clone": "^2.1.2"
46
+ }
47
+ }