@vicinae/api 0.19.8 → 0.20.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/dist/api/cache.d.ts +18 -1
- package/dist/api/cache.js +35 -4
- package/package.json +1 -1
package/dist/api/cache.d.ts
CHANGED
|
@@ -17,6 +17,20 @@ export declare namespace Cache {
|
|
|
17
17
|
* The default capacity is 10 MB.
|
|
18
18
|
*/
|
|
19
19
|
capacity?: number;
|
|
20
|
+
/**
|
|
21
|
+
* Default time-to-live in milliseconds for all keys.
|
|
22
|
+
* Individual keys can override this via the `ttl` option in {@link Cache.set}.
|
|
23
|
+
* If not set, keys do not expire, but are still subject to LRU eviction when the cache exceeds its capacity.
|
|
24
|
+
*/
|
|
25
|
+
ttl?: number;
|
|
26
|
+
}
|
|
27
|
+
interface SetOptions {
|
|
28
|
+
/**
|
|
29
|
+
* Time-to-live in milliseconds for this key.
|
|
30
|
+
* Overrides the cache-level {@link Cache.Options.ttl}.
|
|
31
|
+
* If not set, the cache-level default is used. In both cases, keys are still subject to LRU eviction when the cache exceeds its capacity.
|
|
32
|
+
*/
|
|
33
|
+
ttl?: number;
|
|
20
34
|
}
|
|
21
35
|
type Subscriber = (key: string | undefined, data: string | undefined) => void;
|
|
22
36
|
type Subscription = () => void;
|
|
@@ -63,7 +77,7 @@ export declare class Cache {
|
|
|
63
77
|
* This also notifies registered subscribers (see {@link subscribe}).
|
|
64
78
|
* @remarks An individual cache entry cannot be bigger than the configured capacity. If this happens, an error will be thrown.
|
|
65
79
|
*/
|
|
66
|
-
set: (key: string, data: string) => void;
|
|
80
|
+
set: (key: string, data: string, options?: Cache.SetOptions) => void;
|
|
67
81
|
/**
|
|
68
82
|
* Removes the data for the given key.
|
|
69
83
|
* This also notifies registered subscribers (see {@link subscribe}).
|
|
@@ -96,6 +110,8 @@ export declare class Cache {
|
|
|
96
110
|
private loadIndex;
|
|
97
111
|
private removeCacheDirectory;
|
|
98
112
|
private syncIndex;
|
|
113
|
+
private isExpired;
|
|
114
|
+
private sweepExpired;
|
|
99
115
|
private emptyIndex;
|
|
100
116
|
/**
|
|
101
117
|
* We store this inside the cache index file in order to know
|
|
@@ -105,6 +121,7 @@ export declare class Cache {
|
|
|
105
121
|
*/
|
|
106
122
|
private revision;
|
|
107
123
|
private capacity;
|
|
124
|
+
private defaultTtl?;
|
|
108
125
|
private subscribers;
|
|
109
126
|
private storageDir;
|
|
110
127
|
private index;
|
package/dist/api/cache.js
CHANGED
|
@@ -25,6 +25,7 @@ class Cache {
|
|
|
25
25
|
constructor(options) {
|
|
26
26
|
this.storageDir = node_path_1.default.join(environment_1.environment.supportPath, Cache.CACHE_DIR_NAME);
|
|
27
27
|
this.capacity = options?.capacity ?? Cache.DEFAULT_CACHE_SIZE;
|
|
28
|
+
this.defaultTtl = options?.ttl;
|
|
28
29
|
if (options?.namespace) {
|
|
29
30
|
this.storageDir = node_path_1.default.join(this.storageDir, options.namespace);
|
|
30
31
|
}
|
|
@@ -33,6 +34,7 @@ class Cache {
|
|
|
33
34
|
if (this.index.revision !== this.revision) {
|
|
34
35
|
this.clear();
|
|
35
36
|
}
|
|
37
|
+
this.sweepExpired();
|
|
36
38
|
}
|
|
37
39
|
/**
|
|
38
40
|
* @returns the full path to the directory where the data is stored on disk.
|
|
@@ -51,6 +53,10 @@ class Cache {
|
|
|
51
53
|
const info = this.index.keys[key];
|
|
52
54
|
if (!info)
|
|
53
55
|
return undefined;
|
|
56
|
+
if (this.isExpired(info)) {
|
|
57
|
+
this.remove(key);
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
54
60
|
this.updateLRU(key);
|
|
55
61
|
this.syncIndex();
|
|
56
62
|
return this.readKeyData(key);
|
|
@@ -60,7 +66,14 @@ class Cache {
|
|
|
60
66
|
* @remarks You can use this method to check for entries without affecting the LRU access.
|
|
61
67
|
*/
|
|
62
68
|
has = (key) => {
|
|
63
|
-
|
|
69
|
+
const info = this.index.keys[key];
|
|
70
|
+
if (!info)
|
|
71
|
+
return false;
|
|
72
|
+
if (this.isExpired(info)) {
|
|
73
|
+
this.remove(key);
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
return true;
|
|
64
77
|
};
|
|
65
78
|
/**
|
|
66
79
|
* @returns whether the cache is empty.
|
|
@@ -74,7 +87,7 @@ class Cache {
|
|
|
74
87
|
* This also notifies registered subscribers (see {@link subscribe}).
|
|
75
88
|
* @remarks An individual cache entry cannot be bigger than the configured capacity. If this happens, an error will be thrown.
|
|
76
89
|
*/
|
|
77
|
-
set = (key, data) => {
|
|
90
|
+
set = (key, data, options) => {
|
|
78
91
|
if (data.length > this.capacity) {
|
|
79
92
|
throw new Error(`A single cache entry cannot be bigger than the total capacity of the cache. The data for key ${key} is ${data.length} bytes long while the capacity is set to ${this.capacity}. You should either reduce the amount of data stored or increase the cache's capacity.`);
|
|
80
93
|
}
|
|
@@ -82,11 +95,13 @@ class Cache {
|
|
|
82
95
|
const newTotalSize = this.index.size + data.length - (info?.size ?? 0);
|
|
83
96
|
if (newTotalSize > this.capacity) {
|
|
84
97
|
this.popLRU();
|
|
85
|
-
this.set(key, data); // FIXME: get rid of recursion
|
|
98
|
+
this.set(key, data, options); // FIXME: get rid of recursion
|
|
86
99
|
return;
|
|
87
100
|
}
|
|
101
|
+
const ttl = options?.ttl ?? this.defaultTtl;
|
|
102
|
+
const expiresAt = ttl !== undefined ? Date.now() + ttl : undefined;
|
|
88
103
|
this.index.size = newTotalSize;
|
|
89
|
-
this.index.keys[key] = { size: data.length };
|
|
104
|
+
this.index.keys[key] = { size: data.length, expiresAt };
|
|
90
105
|
this.updateLRU(key);
|
|
91
106
|
this.writeKeyData(key, data);
|
|
92
107
|
this.syncIndex();
|
|
@@ -198,6 +213,21 @@ class Cache {
|
|
|
198
213
|
syncIndex() {
|
|
199
214
|
(0, node_fs_1.writeFileSync)(this.indexPath, JSON.stringify(this.index, null, 2));
|
|
200
215
|
}
|
|
216
|
+
isExpired(info) {
|
|
217
|
+
return info.expiresAt !== undefined && Date.now() > info.expiresAt;
|
|
218
|
+
}
|
|
219
|
+
sweepExpired() {
|
|
220
|
+
const expiredKeys = Object.entries(this.index.keys)
|
|
221
|
+
.filter(([, info]) => this.isExpired(info))
|
|
222
|
+
.map(([key]) => key);
|
|
223
|
+
for (const key of expiredKeys) {
|
|
224
|
+
this.removeImpl(key);
|
|
225
|
+
}
|
|
226
|
+
if (expiredKeys.length > 0) {
|
|
227
|
+
this.index.lru = this.index.lru.filter((entry) => !expiredKeys.includes(entry.key));
|
|
228
|
+
this.syncIndex();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
201
231
|
emptyIndex() {
|
|
202
232
|
return { revision: this.revision, keys: {}, lru: [], size: 0 };
|
|
203
233
|
}
|
|
@@ -209,6 +239,7 @@ class Cache {
|
|
|
209
239
|
*/
|
|
210
240
|
revision = "1";
|
|
211
241
|
capacity;
|
|
242
|
+
defaultTtl;
|
|
212
243
|
subscribers = [];
|
|
213
244
|
storageDir;
|
|
214
245
|
index;
|