@cacheable/node-cache 0.5.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/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ MIT License
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to
5
+ deal in the Software without restriction, including without limitation the
6
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ sell copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19
+ DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,262 @@
1
+ [<img align="center" src="https://cacheable.org/logo.svg" alt="Cacheable" />](https://github.com/jaredwray/cacheable)
2
+
3
+ # Node-Cache
4
+
5
+ > Simple and Maintained fast Node.js caching
6
+
7
+ [![codecov](https://codecov.io/gh/jaredwray/cacheable/branch/master/graph/badge.svg?token=LDLaqe4PsI)](https://codecov.io/gh/jaredwray/cacheable)
8
+ [![tests](https://github.com/jaredwray/cacheable/actions/workflows/tests.yml/badge.svg)](https://github.com/jaredwray/cacheable/actions/workflows/tests.yml)
9
+ [![npm](https://img.shields.io/npm/dm/cacheable.svg)](https://www.npmjs.com/package/cacheable)
10
+ [![npm](https://img.shields.io/npm/v/cacheable)](https://www.npmjs.com/package/cacheable)
11
+
12
+ `@cacheable/node-cache` is compatible with the [node-cache](https://www.npmjs.com/package/node-cache) package with regular maintenance and additional functionality (async/await and storage adapters). The only thing not implemented is the `enableLegacyCallbacks` option and functions. If you need them we are happy to take a PR to add them.
13
+
14
+ * Fully Compatible with `node-cache` using `{NodeCache}`
15
+ * Async/Await functionality with `{NodeCacheStore}`
16
+ * Storage Adapters via [Keyv](https://keyv.org) with `{NodeCacheStore}`
17
+ * Maintained and Updated Regularly! 🎉
18
+
19
+ Note: `NodeCache` is ready and available for use. `NodeCacheStore` is in progress and will be available soon. Please do not use it until it is released.
20
+
21
+ ## Table of Contents
22
+ * [Getting Started](#getting-started)
23
+ * [Basic Usage](#basic-usage)
24
+ * [Advanced Usage](#advanced-usage)
25
+ * [API](#api)
26
+ * [How to Contribute](#how-to-contribute)
27
+ * [License and Copyright](#license-and-copyright)
28
+
29
+ ## Getting Started
30
+
31
+ ```bash
32
+ npm install @cacheable/node-cache --save
33
+ ```
34
+
35
+ ## Basic Usage
36
+
37
+ ```javascript
38
+ import {NodeCache} from '@cacheable/node-cache';
39
+
40
+ const cache = new NodeCache();
41
+ cache.set('foo', 'bar');
42
+ cache.get('foo'); // 'bar'
43
+ ```
44
+
45
+ ## Advanced Usage
46
+
47
+ ```javascript
48
+ import {NodeStorageCache} from '@cacheable/node-cache';
49
+ import {Keyv} from 'keyv';
50
+ import {KeyvRedis} from '@keyv/redis';
51
+
52
+ const storage = new Keyv({store: new KeyvRedis('redis://user:pass@localhost:6379')});
53
+ const cache = new NodeStorageCache(storage);
54
+
55
+ // with storage you have the same functionality as the NodeCache but will be using async/await
56
+ await cache.set('foo', 'bar');
57
+ await cache.get('foo'); // 'bar'
58
+
59
+ // if you call getStats() this will now only be for the single instance of the adapter as it is in memory
60
+ cache.getStats(); // {hits: 1, misses: 1, keys: 1, ksize: 2, vsize: 3}
61
+ ```
62
+
63
+ ## API
64
+
65
+ ### `constructor(options?: NodeCacheOptions)`
66
+
67
+ Create a new cache instance. You can pass in options to set the configuration:
68
+
69
+ ```javascript
70
+ export type NodeCacheOptions = {
71
+ stdTTL?: number; // The standard ttl as number in seconds for every generated cache element. 0 = unlimited
72
+ checkperiod?: number; // Default is 600, 0 means no periodic check
73
+ useClones?: boolean; // Default is true
74
+ deleteOnExpire?: boolean; // Default is true, if this is set to true it will delete the key when it expires.
75
+ maxKeys?: number; // Default is -1 (unlimited). If this is set it will throw and error if you try to set more keys than the max.
76
+ };
77
+ ```
78
+
79
+ When initializing the cache you can pass in the options to set the configuration like the example below where we set the `stdTTL` to 10 seconds and `checkperiod` to 5 seconds.:
80
+
81
+ ```javascript
82
+ const cache = new NodeCache({stdTTL: 10, checkperiod: 5});
83
+ ```
84
+
85
+ When setting `deleteOnExpire` to `true` it will delete the key when it expires. If you set it to `false` it will keep the key but the value on `get()` will be `undefined`. You can manage the key with `on('expired')` event.
86
+
87
+ ```javascript
88
+ const cache = new NodeCache({deleteOnExpire: false});
89
+ cache.on('expired', (key, value) => {
90
+ console.log(`Key ${key} has expired with value ${value}`);
91
+ });
92
+ ```
93
+
94
+ ### `.set(key: string | number, value: any, ttl?: number): boolean`
95
+
96
+ Set a key value pair with an optional ttl (in seconds). Will return true on success. If the ttl is not set it will default to 0 (no ttl).
97
+
98
+ ```javascript
99
+ cache.set('foo', 'bar', 10); // true
100
+ ```
101
+
102
+ ### `.mset(data: Array<NodeCacheItem>): boolean`
103
+
104
+ Set multiple key value pairs at once. This will take an array of objects with the key, value, and optional ttl.
105
+
106
+ ```javascript
107
+ cache.mset([{key: 'foo', value: 'bar', ttl: 10}, {key: 'bar', value: 'baz'}]); // true
108
+ ```
109
+
110
+ the `NodeCacheItem` is defined as:
111
+
112
+ ```javascript
113
+ export type NodeCacheItem = {
114
+ key: string;
115
+ value: any;
116
+ ttl?: number;
117
+ };
118
+ ```
119
+
120
+ ### `.get(key: string | number): any`
121
+
122
+ Get a value from the cache by key. If the key does not exist it will return `undefined`.
123
+
124
+ ```javascript
125
+ cache.get('foo'); // 'bar'
126
+ ```
127
+
128
+ ### `mget(keys: Array<string | number>): Record<string, unknown>`
129
+
130
+ Get multiple values from the cache by keys. This will return an object with the keys and values.
131
+
132
+ ```javascript
133
+ const obj = { my: 'value', my2: 'value2' };
134
+ const obj2 = { special: 'value3', life: 'value4' };
135
+ cache.set('my', obj);
136
+ cache.set('my2', obj2);
137
+ cache.mget(['my', 'my2']); // { my: { my: 'value', my2: 'value2' }, my2: { special: 'value3', life: 'value4' } }
138
+ ```
139
+
140
+ ### `take(key: string | number): any`
141
+
142
+ Get a value from the cache by key and delete it. If the key does not exist it will return `undefined`.
143
+
144
+ ```javascript
145
+ cache.set('foo', 'bar');
146
+ cache.take('foo'); // 'bar'
147
+ cache.get('foo'); // undefined
148
+ ```
149
+
150
+ ### `del(key: string | number | Array<string | number>): number`
151
+
152
+ Delete a key from the cache. Will return the number of deleted entries and never fail. You can also pass in an array of keys to delete multiple keys. All examples assume that you have initialized the cache like `const cache = new NodeCache();`.
153
+
154
+ ```javascript
155
+ cache.del('foo'); // true
156
+ ```
157
+
158
+ passing in an array of keys:
159
+
160
+ ```javascript
161
+ cache.del(['foo', 'bar']); // true
162
+ ```
163
+
164
+ ### `.mdel(keys: Array<string | number>): number`
165
+
166
+ Delete multiple keys from the cache. Will return the number of deleted entries and never fail.
167
+
168
+ ```javascript
169
+ cache.mdel(['foo', 'bar']); // true
170
+ ```
171
+
172
+ ### `.ttl(key: string | number, ttl?: number): boolean`
173
+
174
+ Redefine the ttl of a key. Returns true if the key has been found and changed. Otherwise returns false. If the ttl-argument isn't passed the default-TTL will be used.
175
+
176
+ ```javascript
177
+ cache.ttl('foo', 10); // true
178
+ ```
179
+
180
+ ### `getTtl(key: string | number): number | undefined`
181
+
182
+ Get the ttl expiration from `Date.now()` of a key. If the key does not exist it will return `undefined`.
183
+
184
+ ```javascript
185
+ cache.getTtl('foo'); // 1725993344859
186
+ ```
187
+
188
+ ### `has(key: string | number): boolean`
189
+
190
+ Check if a key exists in the cache.
191
+
192
+ ```javascript
193
+ cache.set('foo', 'bar');
194
+ cache.has('foo'); // true
195
+ ```
196
+
197
+ ### `keys(): Array<string>`
198
+
199
+ Get all keys from the cache.
200
+
201
+ ```javascript
202
+ cache.keys(); // ['foo', 'bar']
203
+ ```
204
+
205
+ ### `getStats(): NodeCacheStats`
206
+
207
+ Get the stats of the cache.
208
+
209
+ ```javascript
210
+ cache.getStats(); // {hits: 1, misses: 1, keys: 1, ksize: 2, vsize: 3}
211
+ ```
212
+
213
+ ### `flushAll(): void`
214
+
215
+ Flush the cache. Will remove all keys and reset the stats.
216
+
217
+ ```javascript
218
+ cache.flushAll();
219
+ cache.keys(); // []
220
+ cache.getStats(); // {hits: 0, misses: 0, keys: 0, ksize: 0, vsize: 0}
221
+ ```
222
+
223
+ ### `flushStats(): void`
224
+
225
+ Flush the stats. Will reset the stats but keep the keys.
226
+
227
+ ```javascript
228
+ cache.set('foo', 'bar');
229
+ cache.flushStats();
230
+ cache.getStats(); // {hits: 0, misses: 0, keys: 0, ksize: 0, vsize: 0}
231
+ cache.keys(); // ['foo']
232
+ ```
233
+
234
+ ### `close(): void`
235
+
236
+ this will stop the interval that is running for the `checkperiod` and `deleteOnExpire` options.
237
+
238
+ ```javascript
239
+ cache.close();
240
+ ```
241
+
242
+ ### `on(event: string, callback: Function): void`
243
+
244
+ Listen to events. Here are the events that you can listen to:
245
+ * `set` - when a key is set and it will pass in the `key` and `value`.
246
+ * `expired` - when a key is expired and it will pass in the `key` and `value`.
247
+ * `flush` - when the cache is flushed
248
+ * `flush_stats` - when the stats are flushed
249
+ * `del` - when a key is deleted and it will pass in the `key` and `value`.
250
+
251
+ ```javascript
252
+ cache.on('set', (key, value) => {
253
+ console.log(`Key ${key} has been set with value ${value}`);
254
+ });
255
+ ```
256
+
257
+ ## How to Contribute
258
+
259
+ You can contribute by forking the repo and submitting a pull request. Please make sure to add tests and update the documentation. To learn more about how to contribute go to our main README [https://github.com/jaredwray/cacheable](https://github.com/jaredwray/cacheable). This will talk about how to `Open a Pull Request`, `Ask a Question`, or `Post an Issue`.
260
+
261
+ ## License and Copyright
262
+ [MIT © Jared Wray](https://github.com/jaredwray/cacheable/blob/main/LICENSE)
@@ -0,0 +1,62 @@
1
+ import eventemitter from 'eventemitter3';
2
+ export type NodeCacheOptions = {
3
+ stdTTL?: number;
4
+ checkperiod?: number;
5
+ useClones?: boolean;
6
+ deleteOnExpire?: boolean;
7
+ maxKeys?: number;
8
+ };
9
+ export type NodeCacheItem = {
10
+ key: string | number;
11
+ value: any;
12
+ ttl?: number;
13
+ };
14
+ export declare enum NodeCacheErrors {
15
+ ECACHEFULL = "Cache max keys amount exceeded",
16
+ EKEYTYPE = "The key argument has to be of type `string` or `number`. Found: `__key`",
17
+ EKEYSTYPE = "The keys argument has to be an array.",
18
+ ETTLTYPE = "The ttl argument has to be a number."
19
+ }
20
+ export type NodeCacheStats = {
21
+ keys: number;
22
+ hits: number;
23
+ misses: number;
24
+ ksize: number;
25
+ vsize: number;
26
+ };
27
+ export default class NodeCache extends eventemitter {
28
+ readonly options: NodeCacheOptions;
29
+ readonly store: Map<string, any>;
30
+ private _stats;
31
+ private intervalId;
32
+ constructor(options?: NodeCacheOptions);
33
+ set(key: string | number, value: any, ttl?: number): boolean;
34
+ mset(data: NodeCacheItem[]): boolean;
35
+ get(key: string | number): any;
36
+ mget(keys: Array<string | number>): Record<string, unknown>;
37
+ take(key: string | number): any;
38
+ del(key: string | number | Array<string | number>): number;
39
+ mdel(keys: Array<string | number>): number;
40
+ ttl(key: string | number, ttl?: number): boolean;
41
+ getTtl(key: string | number): number | undefined;
42
+ keys(): string[];
43
+ has(key: string | number): boolean;
44
+ getStats(): NodeCacheStats;
45
+ flushAll(): void;
46
+ flushStats(): void;
47
+ close(): void;
48
+ getIntervalId(): number | NodeJS.Timeout;
49
+ private formatKey;
50
+ private getExpirationTimestamp;
51
+ private addHit;
52
+ private addMiss;
53
+ private roughSizeOfKey;
54
+ private roughSizeOfObject;
55
+ private startInterval;
56
+ private checkData;
57
+ private stopInterval;
58
+ private createError;
59
+ private isPrimitive;
60
+ private clone;
61
+ }
62
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,YAAY,MAAM,eAAe,CAAC;AAEzC,MAAM,MAAM,gBAAgB,GAAG;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC3B,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,KAAK,EAAE,GAAG,CAAC;IACX,GAAG,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,oBAAY,eAAe;IAC1B,UAAU,mCAAmC;IAC7C,QAAQ,4EAA4E;IACpF,SAAS,0CAA0C;IACnD,QAAQ,yCAAyC;CACjD;AAED,MAAM,MAAM,cAAc,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,CAAC,OAAO,OAAO,SAAU,SAAQ,YAAY;IAClD,SAAgB,OAAO,EAAE,gBAAgB,CAOvC;IAEF,SAAgB,KAAK,mBAA0B;IAE/C,OAAO,CAAC,MAAM,CAMZ;IAEF,OAAO,CAAC,UAAU,CAA8B;gBAEpC,OAAO,CAAC,EAAE,gBAAgB;IAW/B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO;IAyC5D,IAAI,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,OAAO;IAepC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,GAAG;IAuC9B,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAkB3D,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,GAAG;IAgB/B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM;IAwB1D,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM;IAW1C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO;IAoBhD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS;IAiBhD,IAAI,IAAI,MAAM,EAAE;IAWhB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO;IAKlC,QAAQ,IAAI,cAAc;IAK1B,QAAQ,IAAI,IAAI;IAQhB,UAAU,IAAI,IAAI;IAclB,KAAK,IAAI,IAAI;IAKb,aAAa,IAAI,MAAM,GAAG,MAAM,CAAC,OAAO;IAI/C,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,sBAAsB;IAO9B,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,iBAAiB;IA6BzB,OAAO,CAAC,aAAa;IAarB,OAAO,CAAC,SAAS;IAQjB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,WAAW;IAenB,OAAO,CAAC,KAAK;CAOb"}
package/dist/index.js ADDED
@@ -0,0 +1,344 @@
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.NodeCacheErrors = void 0;
7
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
8
+ const eventemitter3_1 = __importDefault(require("eventemitter3"));
9
+ var NodeCacheErrors;
10
+ (function (NodeCacheErrors) {
11
+ NodeCacheErrors["ECACHEFULL"] = "Cache max keys amount exceeded";
12
+ NodeCacheErrors["EKEYTYPE"] = "The key argument has to be of type `string` or `number`. Found: `__key`";
13
+ NodeCacheErrors["EKEYSTYPE"] = "The keys argument has to be an array.";
14
+ NodeCacheErrors["ETTLTYPE"] = "The ttl argument has to be a number.";
15
+ })(NodeCacheErrors || (exports.NodeCacheErrors = NodeCacheErrors = {}));
16
+ class NodeCache extends eventemitter3_1.default {
17
+ constructor(options) {
18
+ super();
19
+ this.options = {
20
+ // eslint-disable-next-line @typescript-eslint/naming-convention
21
+ stdTTL: 0,
22
+ checkperiod: 600,
23
+ useClones: true,
24
+ deleteOnExpire: true,
25
+ maxKeys: -1,
26
+ };
27
+ this.store = new Map();
28
+ this._stats = {
29
+ keys: 0,
30
+ hits: 0,
31
+ misses: 0,
32
+ ksize: 0,
33
+ vsize: 0,
34
+ };
35
+ this.intervalId = 0;
36
+ if (options) {
37
+ this.options = Object.assign(Object.assign({}, this.options), options);
38
+ }
39
+ this.startInterval();
40
+ }
41
+ // Sets a key value pair. It is possible to define a ttl (in seconds). Returns true on success.
42
+ set(key, value, ttl) {
43
+ // Check on key type
44
+ /* c8 ignore next 3 */
45
+ if (typeof key !== 'string' && typeof key !== 'number') {
46
+ throw this.createError(NodeCacheErrors.EKEYTYPE, key);
47
+ }
48
+ // Check on ttl type
49
+ /* c8 ignore next 3 */
50
+ if (ttl && typeof ttl !== 'number') {
51
+ throw this.createError(NodeCacheErrors.ETTLTYPE, this.formatKey(key));
52
+ }
53
+ const keyValue = this.formatKey(key);
54
+ const ttlValue = ttl !== null && ttl !== void 0 ? ttl : this.options.stdTTL;
55
+ let expirationTimestamp = 0; // Never delete
56
+ if (ttlValue && ttlValue > 0) {
57
+ expirationTimestamp = this.getExpirationTimestamp(ttlValue);
58
+ }
59
+ // Check on max key size
60
+ if (this.options.maxKeys) {
61
+ const maxKeys = this.options.maxKeys;
62
+ if (maxKeys > -1 && this.store.size >= maxKeys) {
63
+ throw this.createError(NodeCacheErrors.ECACHEFULL, this.formatKey(key));
64
+ }
65
+ }
66
+ this.store.set(keyValue, { key: keyValue, value, ttl: expirationTimestamp });
67
+ // Event
68
+ this.emit('set', keyValue, value, ttlValue);
69
+ // Add the bytes to the stats
70
+ this._stats.ksize += this.roughSizeOfKey(keyValue);
71
+ this._stats.vsize += this.roughSizeOfObject(value);
72
+ this._stats.keys = this.store.size;
73
+ return true;
74
+ }
75
+ // Sets multiple key val pairs. It is possible to define a ttl (seconds). Returns true on success.
76
+ mset(data) {
77
+ // Check on keys type
78
+ /* c8 ignore next 3 */
79
+ if (!Array.isArray(data)) {
80
+ throw this.createError(NodeCacheErrors.EKEYSTYPE);
81
+ }
82
+ for (const item of data) {
83
+ this.set(item.key, item.value, item.ttl);
84
+ }
85
+ return true;
86
+ }
87
+ // Gets a saved value from the cache. Returns a undefined if not found or expired. If the value was found it returns the value.
88
+ get(key) {
89
+ const result = this.store.get(this.formatKey(key));
90
+ if (result) {
91
+ if (result.ttl > 0) {
92
+ if (result.ttl < Date.now()) {
93
+ if (this.options.deleteOnExpire) {
94
+ this.del(key);
95
+ }
96
+ this.addMiss();
97
+ // Event
98
+ this.emit('expired', this.formatKey(key), result.value);
99
+ return undefined;
100
+ }
101
+ this.addHit();
102
+ if (this.options.useClones) {
103
+ return this.clone(result.value);
104
+ }
105
+ return result.value;
106
+ }
107
+ this.addHit();
108
+ if (this.options.useClones) {
109
+ return this.clone(result.value);
110
+ }
111
+ return result.value;
112
+ }
113
+ this.addMiss();
114
+ return undefined;
115
+ }
116
+ /*
117
+ Gets multiple saved values from the cache. Returns an empty object {} if not found or expired.
118
+ If the value was found it returns an object with the key value pair.
119
+ */
120
+ mget(keys) {
121
+ const result = {};
122
+ for (const key of keys) {
123
+ const value = this.get(key);
124
+ if (value) {
125
+ result[this.formatKey(key)] = value;
126
+ }
127
+ }
128
+ return result;
129
+ }
130
+ /*
131
+ Get the cached value and remove the key from the cache.
132
+ Equivalent to calling get(key) + del(key).
133
+ Useful for implementing single use mechanism such as OTP, where once a value is read it will become obsolete.
134
+ */
135
+ take(key) {
136
+ const result = this.get(key);
137
+ if (result) {
138
+ this.del(key);
139
+ if (this.options.useClones) {
140
+ return this.clone(result);
141
+ }
142
+ return result;
143
+ }
144
+ return undefined;
145
+ }
146
+ // Delete a key. Returns the number of deleted entries. A delete will never fail.
147
+ del(key) {
148
+ if (Array.isArray(key)) {
149
+ return this.mdel(key);
150
+ }
151
+ const result = this.store.get(this.formatKey(key));
152
+ if (result) {
153
+ const keyValue = this.formatKey(key);
154
+ this.store.delete(keyValue);
155
+ // Event
156
+ this.emit('del', keyValue, result.value);
157
+ // Remove the bytes from the stats
158
+ this._stats.ksize -= this.roughSizeOfKey(keyValue);
159
+ this._stats.vsize -= this.roughSizeOfObject(result.value);
160
+ this._stats.keys = this.store.size;
161
+ return 1;
162
+ }
163
+ return 0;
164
+ }
165
+ // Delete all keys in Array that exist. Returns the number of deleted entries.
166
+ mdel(keys) {
167
+ let result = 0;
168
+ for (const key of keys) {
169
+ result += this.del(key);
170
+ }
171
+ return result;
172
+ }
173
+ // Redefine the ttl of a key. Returns true if the key has been found and changed.
174
+ // Otherwise returns false. If the ttl-argument isn't passed the default-TTL will be used.
175
+ ttl(key, ttl) {
176
+ const result = this.store.get(this.formatKey(key));
177
+ if (result) {
178
+ const ttlValue = ttl !== null && ttl !== void 0 ? ttl : this.options.stdTTL;
179
+ result.ttl = this.getExpirationTimestamp(ttlValue);
180
+ this.store.set(this.formatKey(key), result);
181
+ return true;
182
+ }
183
+ return false;
184
+ }
185
+ /*
186
+ Receive the ttl of a key. You will get:
187
+
188
+ undefined if the key does not exist
189
+ 0 if this key has no ttl
190
+ a timestamp in ms representing the time at which the key will expire
191
+ */
192
+ getTtl(key) {
193
+ const result = this.store.get(this.formatKey(key));
194
+ if (result) {
195
+ if (result.ttl === 0) {
196
+ return 0;
197
+ }
198
+ return result.ttl;
199
+ }
200
+ return undefined;
201
+ }
202
+ /*
203
+ Returns an array of all existing keys.
204
+ [ "all", "my", "keys", "foo", "bar" ]
205
+ */
206
+ keys() {
207
+ const result = [];
208
+ for (const key of this.store.keys()) {
209
+ result.push(key);
210
+ }
211
+ return result;
212
+ }
213
+ // Returns boolean indicating if the key is cached.
214
+ has(key) {
215
+ return this.store.has(this.formatKey(key));
216
+ }
217
+ // Gets the stats of the cache.
218
+ getStats() {
219
+ return this._stats;
220
+ }
221
+ // Flush the whole data.
222
+ flushAll() {
223
+ this.store.clear();
224
+ this.flushStats();
225
+ // Event
226
+ this.emit('flush');
227
+ }
228
+ // Flush the stats
229
+ flushStats() {
230
+ this._stats = {
231
+ keys: 0,
232
+ hits: 0,
233
+ misses: 0,
234
+ ksize: 0,
235
+ vsize: 0,
236
+ };
237
+ // Event
238
+ this.emit('flush_stats');
239
+ }
240
+ // Close the cache. This will clear the interval timeout which is set on check period option.
241
+ close() {
242
+ this.stopInterval();
243
+ }
244
+ // Get the interval id
245
+ getIntervalId() {
246
+ return this.intervalId;
247
+ }
248
+ formatKey(key) {
249
+ return key.toString();
250
+ }
251
+ getExpirationTimestamp(ttlInSeconds) {
252
+ const currentTimestamp = Date.now(); // Current time in milliseconds
253
+ const ttlInMilliseconds = ttlInSeconds * 1000; // Convert TTL to milliseconds
254
+ const expirationTimestamp = currentTimestamp + ttlInMilliseconds;
255
+ return expirationTimestamp;
256
+ }
257
+ addHit() {
258
+ this._stats.hits++;
259
+ }
260
+ addMiss() {
261
+ this._stats.misses++;
262
+ }
263
+ roughSizeOfKey(key) {
264
+ // Keys are strings (UTF-16)
265
+ return this.formatKey(key).toString().length * 2;
266
+ }
267
+ roughSizeOfObject(object) {
268
+ const objectList = [];
269
+ const stack = [object];
270
+ let bytes = 0;
271
+ while (stack.length > 0) {
272
+ const value = stack.pop();
273
+ if (typeof value === 'boolean') {
274
+ bytes += 4; // Booleans are 4 bytes
275
+ }
276
+ else if (typeof value === 'string') {
277
+ bytes += value.length * 2; // Each character is 2 bytes (UTF-16 encoding)
278
+ }
279
+ else if (typeof value === 'number') {
280
+ bytes += 8; // Numbers are 8 bytes (IEEE 754 format)
281
+ }
282
+ else if (typeof value === 'object' && value !== null && !objectList.includes(value)) {
283
+ objectList.push(value);
284
+ // Estimate object overhead, and then recursively estimate the size of properties
285
+ // eslint-disable-next-line guard-for-in
286
+ for (const key in value) {
287
+ bytes += key.length * 2; // Keys are strings (UTF-16)
288
+ stack.push(value[key]); // Add values to the stack to compute their size
289
+ }
290
+ }
291
+ }
292
+ return bytes;
293
+ }
294
+ startInterval() {
295
+ if (this.options.checkperiod && this.options.checkperiod > 0) {
296
+ const checkPeriodinSeconds = this.options.checkperiod * 1000;
297
+ this.intervalId = setInterval(() => {
298
+ this.checkData();
299
+ }, checkPeriodinSeconds);
300
+ return;
301
+ }
302
+ this.intervalId = 0;
303
+ }
304
+ checkData() {
305
+ for (const [key, value] of this.store.entries()) {
306
+ if (value.ttl > 0 && value.ttl < Date.now()) {
307
+ this.del(key);
308
+ }
309
+ }
310
+ }
311
+ stopInterval() {
312
+ if (this.intervalId !== 0) {
313
+ clearInterval(this.intervalId);
314
+ this.intervalId = 0;
315
+ }
316
+ }
317
+ createError(errorCode, key) {
318
+ let error = errorCode;
319
+ /* c8 ignore next 3 */
320
+ if (key) {
321
+ error = error.replace('__key', key);
322
+ }
323
+ return new Error(error);
324
+ }
325
+ isPrimitive(value) {
326
+ const result = false;
327
+ /* c8 ignore next 3 */
328
+ if (value === null || value === undefined) {
329
+ return true;
330
+ }
331
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
332
+ return true;
333
+ }
334
+ return result;
335
+ }
336
+ clone(value) {
337
+ if (this.isPrimitive(value)) {
338
+ return value;
339
+ }
340
+ return structuredClone(value);
341
+ }
342
+ }
343
+ exports.default = NodeCache;
344
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-assignment */\nimport eventemitter from 'eventemitter3';\n\nexport type NodeCacheOptions = {\n\tstdTTL?: number; // The standard ttl as number in seconds for every generated cache element. 0 = unlimited\n\tcheckperiod?: number; // Default is 600\n\tuseClones?: boolean; // Default is true\n\tdeleteOnExpire?: boolean; // Default is true\n\tmaxKeys?: number; // Default is -1\n};\n\nexport type NodeCacheItem = {\n\tkey: string | number;\n\tvalue: any;\n\tttl?: number;\n};\n\nexport enum NodeCacheErrors {\n\tECACHEFULL = 'Cache max keys amount exceeded',\n\tEKEYTYPE = 'The key argument has to be of type `string` or `number`. Found: `__key`',\n\tEKEYSTYPE = 'The keys argument has to be an array.',\n\tETTLTYPE = 'The ttl argument has to be a number.',\n}\n\nexport type NodeCacheStats = {\n\tkeys: number; // global key count\n\thits: number; // global hit count\n\tmisses: number; // global miss count\n\tksize: number; // global key size count in approximately bytes\n\tvsize: number; // global value size count in approximately bytes\n};\n\nexport default class NodeCache extends eventemitter {\n\tpublic readonly options: NodeCacheOptions = {\n\t\t// eslint-disable-next-line @typescript-eslint/naming-convention\n\t\tstdTTL: 0,\n\t\tcheckperiod: 600,\n\t\tuseClones: true,\n\t\tdeleteOnExpire: true,\n\t\tmaxKeys: -1,\n\t};\n\n\tpublic readonly store = new Map<string, any>();\n\n\tprivate _stats: NodeCacheStats = {\n\t\tkeys: 0,\n\t\thits: 0,\n\t\tmisses: 0,\n\t\tksize: 0,\n\t\tvsize: 0,\n\t};\n\n\tprivate intervalId: number | NodeJS.Timeout = 0;\n\n\tconstructor(options?: NodeCacheOptions) {\n\t\tsuper();\n\n\t\tif (options) {\n\t\t\tthis.options = {...this.options, ...options};\n\t\t}\n\n\t\tthis.startInterval();\n\t}\n\n\t// Sets a key value pair. It is possible to define a ttl (in seconds). Returns true on success.\n\tpublic set(key: string | number, value: any, ttl?: number): boolean {\n\t\t// Check on key type\n\t\t/* c8 ignore next 3 */\n\t\tif (typeof key !== 'string' && typeof key !== 'number') {\n\t\t\tthrow this.createError(NodeCacheErrors.EKEYTYPE, key);\n\t\t}\n\n\t\t// Check on ttl type\n\t\t/* c8 ignore next 3 */\n\t\tif (ttl && typeof ttl !== 'number') {\n\t\t\tthrow this.createError(NodeCacheErrors.ETTLTYPE, this.formatKey(key));\n\t\t}\n\n\t\tconst keyValue = this.formatKey(key);\n\t\tconst ttlValue = ttl ?? this.options.stdTTL;\n\t\tlet expirationTimestamp = 0; // Never delete\n\t\tif (ttlValue && ttlValue > 0) {\n\t\t\texpirationTimestamp = this.getExpirationTimestamp(ttlValue);\n\t\t}\n\n\t\t// Check on max key size\n\t\tif (this.options.maxKeys) {\n\t\t\tconst maxKeys = this.options.maxKeys;\n\t\t\tif (maxKeys > -1 && this.store.size >= maxKeys) {\n\t\t\t\tthrow this.createError(NodeCacheErrors.ECACHEFULL, this.formatKey(key));\n\t\t\t}\n\t\t}\n\n\t\tthis.store.set(keyValue, {key: keyValue, value, ttl: expirationTimestamp});\n\n\t\t// Event\n\t\tthis.emit('set', keyValue, value, ttlValue);\n\n\t\t// Add the bytes to the stats\n\t\tthis._stats.ksize += this.roughSizeOfKey(keyValue);\n\t\tthis._stats.vsize += this.roughSizeOfObject(value);\n\t\tthis._stats.keys = this.store.size;\n\t\treturn true;\n\t}\n\n\t// Sets multiple key val pairs. It is possible to define a ttl (seconds). Returns true on success.\n\tpublic mset(data: NodeCacheItem[]): boolean {\n\t\t// Check on keys type\n\t\t/* c8 ignore next 3 */\n\t\tif (!Array.isArray(data)) {\n\t\t\tthrow this.createError(NodeCacheErrors.EKEYSTYPE);\n\t\t}\n\n\t\tfor (const item of data) {\n\t\t\tthis.set(item.key, item.value, item.ttl);\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t// Gets a saved value from the cache. Returns a undefined if not found or expired. If the value was found it returns the value.\n\tpublic get(key: string | number): any {\n\t\tconst result = this.store.get(this.formatKey(key));\n\t\tif (result) {\n\t\t\tif (result.ttl > 0) {\n\t\t\t\tif (result.ttl < Date.now()) {\n\t\t\t\t\tif (this.options.deleteOnExpire) {\n\t\t\t\t\t\tthis.del(key);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.addMiss();\n\t\t\t\t\t// Event\n\t\t\t\t\tthis.emit('expired', this.formatKey(key), result.value);\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\n\t\t\t\tthis.addHit();\n\t\t\t\tif (this.options.useClones) {\n\t\t\t\t\treturn this.clone(result.value);\n\t\t\t\t}\n\n\t\t\t\treturn result.value;\n\t\t\t}\n\n\t\t\tthis.addHit();\n\t\t\tif (this.options.useClones) {\n\t\t\t\treturn this.clone(result.value);\n\t\t\t}\n\n\t\t\treturn result.value;\n\t\t}\n\n\t\tthis.addMiss();\n\t\treturn undefined;\n\t}\n\n\t/*\n\t\tGets multiple saved values from the cache. Returns an empty object {} if not found or expired.\n\t\tIf the value was found it returns an object with the key value pair.\n\t*/\n\tpublic mget(keys: Array<string | number>): Record<string, unknown> {\n\t\tconst result: Record<string, unknown> = {};\n\n\t\tfor (const key of keys) {\n\t\t\tconst value = this.get(key);\n\t\t\tif (value) {\n\t\t\t\tresult[this.formatKey(key)] = value;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/*\n\t\tGet the cached value and remove the key from the cache.\n\t\tEquivalent to calling get(key) + del(key).\n\t\tUseful for implementing single use mechanism such as OTP, where once a value is read it will become obsolete.\n\t*/\n\tpublic take(key: string | number): any {\n\t\tconst result = this.get(key);\n\n\t\tif (result) {\n\t\t\tthis.del(key);\n\t\t\tif (this.options.useClones) {\n\t\t\t\treturn this.clone(result);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t// Delete a key. Returns the number of deleted entries. A delete will never fail.\n\tpublic del(key: string | number | Array<string | number>): number {\n\t\tif (Array.isArray(key)) {\n\t\t\treturn this.mdel(key);\n\t\t}\n\n\t\tconst result = this.store.get(this.formatKey(key));\n\t\tif (result) {\n\t\t\tconst keyValue = this.formatKey(key);\n\t\t\tthis.store.delete(keyValue);\n\n\t\t\t// Event\n\t\t\tthis.emit('del', keyValue, result.value);\n\n\t\t\t// Remove the bytes from the stats\n\t\t\tthis._stats.ksize -= this.roughSizeOfKey(keyValue);\n\t\t\tthis._stats.vsize -= this.roughSizeOfObject(result.value);\n\t\t\tthis._stats.keys = this.store.size;\n\t\t\treturn 1;\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\t// Delete all keys in Array that exist. Returns the number of deleted entries.\n\tpublic mdel(keys: Array<string | number>): number {\n\t\tlet result = 0;\n\t\tfor (const key of keys) {\n\t\t\tresult += this.del(key);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t// Redefine the ttl of a key. Returns true if the key has been found and changed.\n\t// Otherwise returns false. If the ttl-argument isn't passed the default-TTL will be used.\n\tpublic ttl(key: string | number, ttl?: number): boolean {\n\t\tconst result = this.store.get(this.formatKey(key));\n\t\tif (result) {\n\t\t\tconst ttlValue = ttl ?? this.options.stdTTL!;\n\t\t\tresult.ttl = this.getExpirationTimestamp(ttlValue);\n\t\t\tthis.store.set(this.formatKey(key), result);\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/*\n\t\tReceive the ttl of a key. You will get:\n\n\t\tundefined if the key does not exist\n\t\t0 if this key has no ttl\n\t\ta timestamp in ms representing the time at which the key will expire\n\t*/\n\n\tpublic getTtl(key: string | number): number | undefined {\n\t\tconst result = this.store.get(this.formatKey(key));\n\t\tif (result) {\n\t\t\tif (result.ttl === 0) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\treturn result.ttl as number;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/*\n\t\tReturns an array of all existing keys.\n\t\t[ \"all\", \"my\", \"keys\", \"foo\", \"bar\" ]\n\t*/\n\tpublic keys(): string[] {\n\t\tconst result: string[] = [];\n\n\t\tfor (const key of this.store.keys()) {\n\t\t\tresult.push(key);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t// Returns boolean indicating if the key is cached.\n\tpublic has(key: string | number): boolean {\n\t\treturn this.store.has(this.formatKey(key));\n\t}\n\n\t// Gets the stats of the cache.\n\tpublic getStats(): NodeCacheStats {\n\t\treturn this._stats;\n\t}\n\n\t// Flush the whole data.\n\tpublic flushAll(): void {\n\t\tthis.store.clear();\n\t\tthis.flushStats();\n\t\t// Event\n\t\tthis.emit('flush');\n\t}\n\n\t// Flush the stats\n\tpublic flushStats(): void {\n\t\tthis._stats = {\n\t\t\tkeys: 0,\n\t\t\thits: 0,\n\t\t\tmisses: 0,\n\t\t\tksize: 0,\n\t\t\tvsize: 0,\n\t\t};\n\n\t\t// Event\n\t\tthis.emit('flush_stats');\n\t}\n\n\t// Close the cache. This will clear the interval timeout which is set on check period option.\n\tpublic close(): void {\n\t\tthis.stopInterval();\n\t}\n\n\t// Get the interval id\n\tpublic getIntervalId(): number | NodeJS.Timeout {\n\t\treturn this.intervalId;\n\t}\n\n\tprivate formatKey(key: string | number): string {\n\t\treturn key.toString();\n\t}\n\n\tprivate getExpirationTimestamp(ttlInSeconds: number): number {\n\t\tconst currentTimestamp = Date.now(); // Current time in milliseconds\n\t\tconst ttlInMilliseconds = ttlInSeconds * 1000; // Convert TTL to milliseconds\n\t\tconst expirationTimestamp = currentTimestamp + ttlInMilliseconds;\n\t\treturn expirationTimestamp;\n\t}\n\n\tprivate addHit(): void {\n\t\tthis._stats.hits++;\n\t}\n\n\tprivate addMiss(): void {\n\t\tthis._stats.misses++;\n\t}\n\n\tprivate roughSizeOfKey(key: string): number {\n\t\t// Keys are strings (UTF-16)\n\t\treturn this.formatKey(key).toString().length * 2;\n\t}\n\n\tprivate roughSizeOfObject(object: any): number {\n\t\tconst objectList: any[] = [];\n\t\tconst stack: any[] = [object];\n\t\tlet bytes = 0;\n\n\t\twhile (stack.length > 0) {\n\t\t\tconst value = stack.pop();\n\n\t\t\tif (typeof value === 'boolean') {\n\t\t\t\tbytes += 4; // Booleans are 4 bytes\n\t\t\t} else if (typeof value === 'string') {\n\t\t\t\tbytes += value.length * 2; // Each character is 2 bytes (UTF-16 encoding)\n\t\t\t} else if (typeof value === 'number') {\n\t\t\t\tbytes += 8; // Numbers are 8 bytes (IEEE 754 format)\n\t\t\t} else if (typeof value === 'object' && value !== null && !objectList.includes(value)) {\n\t\t\t\tobjectList.push(value);\n\n\t\t\t\t// Estimate object overhead, and then recursively estimate the size of properties\n\t\t\t\t// eslint-disable-next-line guard-for-in\n\t\t\t\tfor (const key in value) {\n\t\t\t\t\tbytes += key.length * 2; // Keys are strings (UTF-16)\n\t\t\t\t\tstack.push(value[key]); // Add values to the stack to compute their size\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn bytes;\n\t}\n\n\tprivate startInterval(): void {\n\t\tif (this.options.checkperiod && this.options.checkperiod > 0) {\n\t\t\tconst checkPeriodinSeconds = this.options.checkperiod * 1000;\n\t\t\tthis.intervalId = setInterval(() => {\n\t\t\t\tthis.checkData();\n\t\t\t}, checkPeriodinSeconds);\n\n\t\t\treturn;\n\t\t}\n\n\t\tthis.intervalId = 0;\n\t}\n\n\tprivate checkData(): void {\n\t\tfor (const [key, value] of this.store.entries()) {\n\t\t\tif (value.ttl > 0 && value.ttl < Date.now()) {\n\t\t\t\tthis.del(key);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate stopInterval(): void {\n\t\tif (this.intervalId !== 0) {\n\t\t\tclearInterval(this.intervalId);\n\t\t\tthis.intervalId = 0;\n\t\t}\n\t}\n\n\tprivate createError(errorCode: string, key?: string): Error {\n\t\tlet error = errorCode;\n\t\t/* c8 ignore next 3 */\n\t\tif (key) {\n\t\t\terror = error.replace('__key', key);\n\t\t}\n\n\t\treturn new Error(error);\n\t}\n\n\tprivate isPrimitive(value: any): boolean {\n\t\tconst result = false;\n\n\t\t/* c8 ignore next 3 */\n\t\tif (value === null || value === undefined) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate clone(value: any): any {\n\t\tif (this.isPrimitive(value)) {\n\t\t\treturn value;\n\t\t}\n\n\t\treturn structuredClone(value);\n\t}\n}\n\n"]}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@cacheable/node-cache",
3
+ "version": "0.5.0",
4
+ "description": "Simple and Maintained fast NodeJS internal caching",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "repository": "https://github.com/jaredwray/cacheable.git",
8
+ "author": "Jared Wray <me@jaredwray.com>",
9
+ "license": "MIT",
10
+ "private": false,
11
+ "keywords": [
12
+ "cache",
13
+ "caching",
14
+ "node",
15
+ "nodejs",
16
+ "cacheable",
17
+ "cacheable-node-cache",
18
+ "node-cache",
19
+ "cacheable-node"
20
+ ],
21
+ "devDependencies": {
22
+ "@types/node": "^22.5.4",
23
+ "@vitest/coverage-v8": "^2.0.5",
24
+ "rimraf": "^6.0.1",
25
+ "typescript": "^5.5.4",
26
+ "vitest": "^2.0.5",
27
+ "xo": "^0.59.3"
28
+ },
29
+ "dependencies": {
30
+ "cacheable": "^0.3.0",
31
+ "eventemitter3": "^5.0.1"
32
+ },
33
+ "files": [
34
+ "dist",
35
+ "license"
36
+ ],
37
+ "scripts": {
38
+ "build": "rimraf ./dist && tsc -p tsconfig.build.json",
39
+ "test": "xo --fix && vitest run --coverage",
40
+ "test:ci": "xo && vitest run",
41
+ "clean": "rimraf ./dist ./coverage ./node_modules"
42
+ }
43
+ }