@twin.org/core 0.0.3-next.24 → 0.0.3-next.26
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.
|
@@ -16,84 +16,88 @@ export class AsyncCache {
|
|
|
16
16
|
*/
|
|
17
17
|
static exec(key, ttlMs, requestMethod, cacheFailures) {
|
|
18
18
|
const cacheEnabled = Is.integer(ttlMs) && ttlMs >= 0;
|
|
19
|
-
if (cacheEnabled) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
19
|
+
if (!cacheEnabled) {
|
|
20
|
+
// No caching, just execute the request method
|
|
21
|
+
return requestMethod();
|
|
22
|
+
}
|
|
23
|
+
AsyncCache.cleanupExpired();
|
|
24
|
+
const cache = AsyncCache.getSharedCache();
|
|
25
|
+
// Do we have a cache entry for the key
|
|
26
|
+
if (cache[key]) {
|
|
27
|
+
if (!Is.empty(cache[key].result)) {
|
|
28
|
+
// If the cache has already resulted in a value, resolve it
|
|
29
|
+
return Promise.resolve(cache[key].result);
|
|
30
|
+
}
|
|
31
|
+
else if (!Is.empty(cache[key].error)) {
|
|
32
|
+
// If the cache has already resulted in an error, reject it
|
|
33
|
+
return Promise.reject(cache[key].error);
|
|
34
|
+
}
|
|
35
|
+
// Otherwise create a promise to return and store the resolver
|
|
36
|
+
// and rejector in the cache entry, so that we can call then
|
|
37
|
+
// when the request is done
|
|
38
|
+
let storedResolve;
|
|
39
|
+
let storedReject;
|
|
40
|
+
const wait = new Promise((resolve, reject) => {
|
|
41
|
+
storedResolve = resolve;
|
|
42
|
+
storedReject = reject;
|
|
43
|
+
});
|
|
44
|
+
if (!Is.empty(storedResolve) && !Is.empty(storedReject)) {
|
|
45
|
+
cache[key].promiseQueue.push({
|
|
46
|
+
requestMethod,
|
|
47
|
+
resolve: storedResolve,
|
|
48
|
+
reject: storedReject
|
|
40
49
|
});
|
|
41
|
-
if (!Is.empty(storedResolve) && !Is.empty(storedReject)) {
|
|
42
|
-
cache[key].promiseQueue.push({
|
|
43
|
-
requestMethod,
|
|
44
|
-
resolve: storedResolve,
|
|
45
|
-
reject: storedReject
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
return wait;
|
|
49
50
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
51
|
+
return wait;
|
|
52
|
+
}
|
|
53
|
+
// If we don't have a cache entry, create a new one
|
|
54
|
+
cache[key] = {
|
|
55
|
+
promiseQueue: [],
|
|
56
|
+
expires: ttlMs === 0 ? 0 : Date.now() + ttlMs
|
|
57
|
+
};
|
|
58
|
+
// Return a promise that wraps the original request method
|
|
59
|
+
// so that we can store any results or errors in the cache
|
|
60
|
+
return new Promise((resolve, reject) => {
|
|
61
|
+
// Call the request method and store the result
|
|
62
|
+
requestMethod()
|
|
63
|
+
// eslint-disable-next-line promise/prefer-await-to-then
|
|
64
|
+
.then(res => {
|
|
65
|
+
// If the request was successful, store the result
|
|
66
|
+
cache[key].result = res;
|
|
67
|
+
// and resolve both this promise and all the waiters
|
|
68
|
+
resolve(res);
|
|
69
|
+
for (const wait of cache[key].promiseQueue) {
|
|
70
|
+
wait.resolve(res);
|
|
71
|
+
}
|
|
72
|
+
cache[key].promiseQueue = [];
|
|
73
|
+
return res;
|
|
74
|
+
})
|
|
75
|
+
// eslint-disable-next-line promise/prefer-await-to-then
|
|
76
|
+
.catch((err) => {
|
|
77
|
+
// Reject the promise
|
|
78
|
+
reject(err);
|
|
79
|
+
// Handle the waiters based on the cacheFailures flag
|
|
80
|
+
if (cacheFailures ?? false) {
|
|
81
|
+
// If we are caching failures, store the error and reject the waiters
|
|
82
|
+
cache[key].error = err;
|
|
66
83
|
for (const wait of cache[key].promiseQueue) {
|
|
67
|
-
wait.
|
|
68
|
-
}
|
|
69
|
-
return res;
|
|
70
|
-
})
|
|
71
|
-
// eslint-disable-next-line promise/prefer-await-to-then
|
|
72
|
-
.catch((err) => {
|
|
73
|
-
// Reject the promise
|
|
74
|
-
reject(err);
|
|
75
|
-
// Handle the waiters based on the cacheFailures flag
|
|
76
|
-
if (cacheFailures ?? false) {
|
|
77
|
-
// If we are caching failures, store the error and reject the waiters
|
|
78
|
-
cache[key].error = err;
|
|
79
|
-
for (const wait of cache[key].promiseQueue) {
|
|
80
|
-
wait.reject(err);
|
|
81
|
-
}
|
|
82
|
-
// Clear the waiters so we don't call them again
|
|
83
|
-
cache[key].promiseQueue = [];
|
|
84
|
+
wait.reject(err);
|
|
84
85
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
// Clear the waiters so we don't call them again
|
|
87
|
+
cache[key].promiseQueue = [];
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
// If not caching failures for any queued requests we
|
|
91
|
+
// have no value to either resolve or reject, so we
|
|
92
|
+
// just resolve with the original request method
|
|
93
|
+
for (const wait of cache[key].promiseQueue) {
|
|
94
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
95
|
+
AsyncCache.resolveWaiter(wait.requestMethod, wait.resolve, wait.reject);
|
|
93
96
|
}
|
|
94
|
-
|
|
97
|
+
delete cache[key];
|
|
98
|
+
}
|
|
95
99
|
});
|
|
96
|
-
}
|
|
100
|
+
});
|
|
97
101
|
}
|
|
98
102
|
/**
|
|
99
103
|
* Get an entry from the cache.
|
|
@@ -102,11 +106,11 @@ export class AsyncCache {
|
|
|
102
106
|
*/
|
|
103
107
|
static async get(key) {
|
|
104
108
|
const cache = AsyncCache.getSharedCache();
|
|
105
|
-
if (!Is.empty(cache[key]
|
|
109
|
+
if (!Is.empty(cache[key]?.result)) {
|
|
106
110
|
// If the cache has already resulted in a value, resolve it
|
|
107
111
|
return cache[key].result;
|
|
108
112
|
}
|
|
109
|
-
|
|
113
|
+
if (!Is.empty(cache[key]?.error)) {
|
|
110
114
|
// If the cache has already resulted in an error, reject it
|
|
111
115
|
throw cache[key].error;
|
|
112
116
|
}
|
|
@@ -175,5 +179,19 @@ export class AsyncCache {
|
|
|
175
179
|
}
|
|
176
180
|
return sharedCache;
|
|
177
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Resolve a waiter by re-running its request method safely.
|
|
184
|
+
* @param requestMethod The method to execute.
|
|
185
|
+
* @param resolve The resolver for the waiter.
|
|
186
|
+
* @param reject The rejector for the waiter.
|
|
187
|
+
*/
|
|
188
|
+
static async resolveWaiter(requestMethod, resolve, reject) {
|
|
189
|
+
try {
|
|
190
|
+
resolve(await requestMethod());
|
|
191
|
+
}
|
|
192
|
+
catch (waitErr) {
|
|
193
|
+
reject(waitErr);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
178
196
|
}
|
|
179
197
|
//# sourceMappingURL=asyncCache.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asyncCache.js","sourceRoot":"","sources":["../../../src/utils/asyncCache.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { Is } from \"./is.js\";\nimport { SharedStore } from \"./sharedStore.js\";\n\n/**\n * Cache the results from asynchronous requests.\n */\nexport class AsyncCache {\n\t/**\n\t * Execute an async request and cache the result.\n\t * @param key The key for the entry in the cache.\n\t * @param ttlMs The TTL of the entry in the cache.\n\t * @param requestMethod The method to call if not cached.\n\t * @param cacheFailures Cache failure results, defaults to false.\n\t * @returns The response.\n\t */\n\tpublic static exec<T = unknown>(\n\t\tkey: string,\n\t\tttlMs: number | undefined,\n\t\trequestMethod: () => Promise<T>,\n\t\tcacheFailures?: boolean\n\t): Promise<T> | undefined {\n\t\tconst cacheEnabled = Is.integer(ttlMs) && ttlMs >= 0;\n\t\tif (cacheEnabled) {\n\t\t\tAsyncCache.cleanupExpired();\n\n\t\t\tconst cache = AsyncCache.getSharedCache<T>();\n\n\t\t\t// Do we have a cache entry for the key\n\t\t\tif (cache[key]) {\n\t\t\t\tif (!Is.empty(cache[key].result)) {\n\t\t\t\t\t// If the cache has already resulted in a value, resolve it\n\t\t\t\t\treturn Promise.resolve(cache[key].result);\n\t\t\t\t} else if (!Is.empty(cache[key].error)) {\n\t\t\t\t\t// If the cache has already resulted in an error, reject it\n\t\t\t\t\treturn Promise.reject(cache[key].error);\n\t\t\t\t}\n\n\t\t\t\t// Otherwise create a promise to return and store the resolver\n\t\t\t\t// and rejector in the cache entry, so that we can call then\n\t\t\t\t// when the request is done\n\n\t\t\t\tlet storedResolve: ((value: T | PromiseLike<T>) => void) | undefined;\n\t\t\t\tlet storedReject: ((reason?: unknown) => void) | undefined;\n\t\t\t\tconst wait = new Promise<T>((resolve, reject) => {\n\t\t\t\t\tstoredResolve = resolve;\n\t\t\t\t\tstoredReject = reject;\n\t\t\t\t});\n\t\t\t\tif (!Is.empty(storedResolve) && !Is.empty(storedReject)) {\n\t\t\t\t\tcache[key].promiseQueue.push({\n\t\t\t\t\t\trequestMethod,\n\t\t\t\t\t\tresolve: storedResolve,\n\t\t\t\t\t\treject: storedReject\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn wait;\n\t\t\t}\n\n\t\t\t// If we don't have a cache entry, create a new one\n\t\t\tcache[key] = {\n\t\t\t\tpromiseQueue: [],\n\t\t\t\texpires: ttlMs === 0 ? 0 : Date.now() + ttlMs\n\t\t\t};\n\n\t\t\t// Return a promise that wraps the original request method\n\t\t\t// so that we can store any results or errors in the cache\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\t// Call the request method and store the result\n\t\t\t\trequestMethod()\n\t\t\t\t\t// eslint-disable-next-line promise/prefer-await-to-then\n\t\t\t\t\t.then(res => {\n\t\t\t\t\t\t// If the request was successful, store the result\n\t\t\t\t\t\tcache[key].result = res;\n\n\t\t\t\t\t\t// and resolve both this promise and all the waiters\n\t\t\t\t\t\tresolve(res);\n\t\t\t\t\t\tfor (const wait of cache[key].promiseQueue) {\n\t\t\t\t\t\t\twait.resolve(res);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn res;\n\t\t\t\t\t})\n\t\t\t\t\t// eslint-disable-next-line promise/prefer-await-to-then\n\t\t\t\t\t.catch((err: Error) => {\n\t\t\t\t\t\t// Reject the promise\n\t\t\t\t\t\treject(err);\n\n\t\t\t\t\t\t// Handle the waiters based on the cacheFailures flag\n\t\t\t\t\t\tif (cacheFailures ?? false) {\n\t\t\t\t\t\t\t// If we are caching failures, store the error and reject the waiters\n\t\t\t\t\t\t\tcache[key].error = err;\n\t\t\t\t\t\t\tfor (const wait of cache[key].promiseQueue) {\n\t\t\t\t\t\t\t\twait.reject(err);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Clear the waiters so we don't call them again\n\t\t\t\t\t\t\tcache[key].promiseQueue = [];\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// If not caching failures for any queued requests we\n\t\t\t\t\t\t\t// have no value to either resolve or reject, so we\n\t\t\t\t\t\t\t// just resolve with the original request method\n\t\t\t\t\t\t\tfor (const wait of cache[key].promiseQueue) {\n\t\t\t\t\t\t\t\twait.resolve(wait.requestMethod());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tdelete cache[key];\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Get an entry from the cache.\n\t * @param key The key to get from the cache.\n\t * @returns The item from the cache if it exists.\n\t */\n\tpublic static async get<T = unknown>(key: string): Promise<T | undefined> {\n\t\tconst cache = AsyncCache.getSharedCache<T>();\n\t\tif (!Is.empty(cache[key].result)) {\n\t\t\t// If the cache has already resulted in a value, resolve it\n\t\t\treturn cache[key].result;\n\t\t} else if (!Is.empty(cache[key].error)) {\n\t\t\t// If the cache has already resulted in an error, reject it\n\t\t\tthrow cache[key].error;\n\t\t}\n\t}\n\n\t/**\n\t * Set an entry into the cache.\n\t * @param key The key to set in the cache.\n\t * @param value The value to set in the cache.\n\t * @param ttlMs The TTL of the entry in the cache in ms, defaults to 1s.\n\t * @returns Nothing.\n\t */\n\tpublic static async set<T = unknown>(key: string, value: T, ttlMs?: number): Promise<void> {\n\t\tconst cache = AsyncCache.getSharedCache();\n\t\tcache[key] = {\n\t\t\tresult: value,\n\t\t\tpromiseQueue: [],\n\t\t\texpires: Date.now() + (ttlMs ?? 1000)\n\t\t};\n\t}\n\n\t/**\n\t * Remove an entry from the cache.\n\t * @param key The key to remove from the cache.\n\t */\n\tpublic static remove(key: string): void {\n\t\tconst cache = AsyncCache.getSharedCache();\n\t\tdelete cache[key];\n\t}\n\n\t/**\n\t * Clear the cache.\n\t * @param prefix Optional prefix to clear only entries with that prefix.\n\t */\n\tpublic static clearCache(prefix?: string): void {\n\t\tconst cache = AsyncCache.getSharedCache();\n\t\tif (Is.stringValue(prefix)) {\n\t\t\tfor (const entry in cache) {\n\t\t\t\tif (entry.startsWith(prefix)) {\n\t\t\t\t\tdelete cache[entry];\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tSharedStore.set(\"asyncCache\", {});\n\t\t}\n\t}\n\n\t/**\n\t * Perform a cleanup of the expired entries in the cache.\n\t */\n\tpublic static cleanupExpired(): void {\n\t\tconst cache = AsyncCache.getSharedCache();\n\t\tfor (const entry in cache) {\n\t\t\tif (cache[entry].expires > 0 && cache[entry].expires < Date.now()) {\n\t\t\t\tdelete cache[entry];\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Get the shared cache.\n\t * @returns The shared cache.\n\t * @internal\n\t */\n\tprivate static getSharedCache<T = unknown>(): {\n\t\t[url: string]: {\n\t\t\tresult?: T;\n\t\t\terror?: Error;\n\t\t\tpromiseQueue: {\n\t\t\t\trequestMethod: () => Promise<T>;\n\t\t\t\tresolve: (value: T | PromiseLike<T>) => void;\n\t\t\t\treject: (reason?: unknown) => void;\n\t\t\t}[];\n\t\t\texpires: number;\n\t\t};\n\t} {\n\t\tlet sharedCache = SharedStore.get<{\n\t\t\t[url: string]: {\n\t\t\t\tresult?: T;\n\t\t\t\terror?: Error;\n\t\t\t\tpromiseQueue: {\n\t\t\t\t\trequestMethod: () => Promise<T>;\n\t\t\t\t\tresolve: (value: T | PromiseLike<T>) => void;\n\t\t\t\t\treject: (reason?: unknown) => void;\n\t\t\t\t}[];\n\t\t\t\texpires: number;\n\t\t\t};\n\t\t}>(\"asyncCache\");\n\n\t\tif (Is.undefined(sharedCache)) {\n\t\t\tsharedCache = {};\n\t\t\tSharedStore.set(\"asyncCache\", sharedCache);\n\t\t}\n\n\t\treturn sharedCache;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"asyncCache.js","sourceRoot":"","sources":["../../../src/utils/asyncCache.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { Is } from \"./is.js\";\nimport { SharedStore } from \"./sharedStore.js\";\n\n/**\n * Cache the results from asynchronous requests.\n */\nexport class AsyncCache {\n\t/**\n\t * Execute an async request and cache the result.\n\t * @param key The key for the entry in the cache.\n\t * @param ttlMs The TTL of the entry in the cache.\n\t * @param requestMethod The method to call if not cached.\n\t * @param cacheFailures Cache failure results, defaults to false.\n\t * @returns The response.\n\t */\n\tpublic static exec<T = unknown>(\n\t\tkey: string,\n\t\tttlMs: number | undefined,\n\t\trequestMethod: () => Promise<T>,\n\t\tcacheFailures?: boolean\n\t): Promise<T> | undefined {\n\t\tconst cacheEnabled = Is.integer(ttlMs) && ttlMs >= 0;\n\t\tif (!cacheEnabled) {\n\t\t\t// No caching, just execute the request method\n\t\t\treturn requestMethod();\n\t\t}\n\n\t\tAsyncCache.cleanupExpired();\n\n\t\tconst cache = AsyncCache.getSharedCache<T>();\n\n\t\t// Do we have a cache entry for the key\n\t\tif (cache[key]) {\n\t\t\tif (!Is.empty(cache[key].result)) {\n\t\t\t\t// If the cache has already resulted in a value, resolve it\n\t\t\t\treturn Promise.resolve(cache[key].result);\n\t\t\t} else if (!Is.empty(cache[key].error)) {\n\t\t\t\t// If the cache has already resulted in an error, reject it\n\t\t\t\treturn Promise.reject(cache[key].error);\n\t\t\t}\n\n\t\t\t// Otherwise create a promise to return and store the resolver\n\t\t\t// and rejector in the cache entry, so that we can call then\n\t\t\t// when the request is done\n\n\t\t\tlet storedResolve: ((value: T | PromiseLike<T>) => void) | undefined;\n\t\t\tlet storedReject: ((reason?: unknown) => void) | undefined;\n\t\t\tconst wait = new Promise<T>((resolve, reject) => {\n\t\t\t\tstoredResolve = resolve;\n\t\t\t\tstoredReject = reject;\n\t\t\t});\n\t\t\tif (!Is.empty(storedResolve) && !Is.empty(storedReject)) {\n\t\t\t\tcache[key].promiseQueue.push({\n\t\t\t\t\trequestMethod,\n\t\t\t\t\tresolve: storedResolve,\n\t\t\t\t\treject: storedReject\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn wait;\n\t\t}\n\n\t\t// If we don't have a cache entry, create a new one\n\t\tcache[key] = {\n\t\t\tpromiseQueue: [],\n\t\t\texpires: ttlMs === 0 ? 0 : Date.now() + ttlMs\n\t\t};\n\n\t\t// Return a promise that wraps the original request method\n\t\t// so that we can store any results or errors in the cache\n\t\treturn new Promise((resolve, reject) => {\n\t\t\t// Call the request method and store the result\n\t\t\trequestMethod()\n\t\t\t\t// eslint-disable-next-line promise/prefer-await-to-then\n\t\t\t\t.then(res => {\n\t\t\t\t\t// If the request was successful, store the result\n\t\t\t\t\tcache[key].result = res;\n\n\t\t\t\t\t// and resolve both this promise and all the waiters\n\t\t\t\t\tresolve(res);\n\t\t\t\t\tfor (const wait of cache[key].promiseQueue) {\n\t\t\t\t\t\twait.resolve(res);\n\t\t\t\t\t}\n\t\t\t\t\tcache[key].promiseQueue = [];\n\t\t\t\t\treturn res;\n\t\t\t\t})\n\t\t\t\t// eslint-disable-next-line promise/prefer-await-to-then\n\t\t\t\t.catch((err: unknown) => {\n\t\t\t\t\t// Reject the promise\n\t\t\t\t\treject(err);\n\n\t\t\t\t\t// Handle the waiters based on the cacheFailures flag\n\t\t\t\t\tif (cacheFailures ?? false) {\n\t\t\t\t\t\t// If we are caching failures, store the error and reject the waiters\n\t\t\t\t\t\tcache[key].error = err;\n\t\t\t\t\t\tfor (const wait of cache[key].promiseQueue) {\n\t\t\t\t\t\t\twait.reject(err);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Clear the waiters so we don't call them again\n\t\t\t\t\t\tcache[key].promiseQueue = [];\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If not caching failures for any queued requests we\n\t\t\t\t\t\t// have no value to either resolve or reject, so we\n\t\t\t\t\t\t// just resolve with the original request method\n\t\t\t\t\t\tfor (const wait of cache[key].promiseQueue) {\n\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-floating-promises\n\t\t\t\t\t\t\tAsyncCache.resolveWaiter(wait.requestMethod, wait.resolve, wait.reject);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdelete cache[key];\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Get an entry from the cache.\n\t * @param key The key to get from the cache.\n\t * @returns The item from the cache if it exists.\n\t */\n\tpublic static async get<T = unknown>(key: string): Promise<T | undefined> {\n\t\tconst cache = AsyncCache.getSharedCache<T>();\n\t\tif (!Is.empty(cache[key]?.result)) {\n\t\t\t// If the cache has already resulted in a value, resolve it\n\t\t\treturn cache[key].result;\n\t\t}\n\n\t\tif (!Is.empty(cache[key]?.error)) {\n\t\t\t// If the cache has already resulted in an error, reject it\n\t\t\tthrow cache[key].error as Error;\n\t\t}\n\t}\n\n\t/**\n\t * Set an entry into the cache.\n\t * @param key The key to set in the cache.\n\t * @param value The value to set in the cache.\n\t * @param ttlMs The TTL of the entry in the cache in ms, defaults to 1s.\n\t * @returns Nothing.\n\t */\n\tpublic static async set<T = unknown>(key: string, value: T, ttlMs?: number): Promise<void> {\n\t\tconst cache = AsyncCache.getSharedCache();\n\t\tcache[key] = {\n\t\t\tresult: value,\n\t\t\tpromiseQueue: [],\n\t\t\texpires: Date.now() + (ttlMs ?? 1000)\n\t\t};\n\t}\n\n\t/**\n\t * Remove an entry from the cache.\n\t * @param key The key to remove from the cache.\n\t */\n\tpublic static remove(key: string): void {\n\t\tconst cache = AsyncCache.getSharedCache();\n\t\tdelete cache[key];\n\t}\n\n\t/**\n\t * Clear the cache.\n\t * @param prefix Optional prefix to clear only entries with that prefix.\n\t */\n\tpublic static clearCache(prefix?: string): void {\n\t\tconst cache = AsyncCache.getSharedCache();\n\t\tif (Is.stringValue(prefix)) {\n\t\t\tfor (const entry in cache) {\n\t\t\t\tif (entry.startsWith(prefix)) {\n\t\t\t\t\tdelete cache[entry];\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tSharedStore.set(\"asyncCache\", {});\n\t\t}\n\t}\n\n\t/**\n\t * Perform a cleanup of the expired entries in the cache.\n\t */\n\tpublic static cleanupExpired(): void {\n\t\tconst cache = AsyncCache.getSharedCache();\n\t\tfor (const entry in cache) {\n\t\t\tif (cache[entry].expires > 0 && cache[entry].expires < Date.now()) {\n\t\t\t\tdelete cache[entry];\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Get the shared cache.\n\t * @returns The shared cache.\n\t * @internal\n\t */\n\tprivate static getSharedCache<T = unknown>(): {\n\t\t[url: string]: {\n\t\t\tresult?: T;\n\t\t\terror?: unknown;\n\t\t\tpromiseQueue: {\n\t\t\t\trequestMethod: () => Promise<T>;\n\t\t\t\tresolve: (value: T | PromiseLike<T>) => void;\n\t\t\t\treject: (reason?: unknown) => void;\n\t\t\t}[];\n\t\t\texpires: number;\n\t\t};\n\t} {\n\t\tlet sharedCache = SharedStore.get<{\n\t\t\t[url: string]: {\n\t\t\t\tresult?: T;\n\t\t\t\terror?: unknown;\n\t\t\t\tpromiseQueue: {\n\t\t\t\t\trequestMethod: () => Promise<T>;\n\t\t\t\t\tresolve: (value: T | PromiseLike<T>) => void;\n\t\t\t\t\treject: (reason?: unknown) => void;\n\t\t\t\t}[];\n\t\t\t\texpires: number;\n\t\t\t};\n\t\t}>(\"asyncCache\");\n\n\t\tif (Is.undefined(sharedCache)) {\n\t\t\tsharedCache = {};\n\t\t\tSharedStore.set(\"asyncCache\", sharedCache);\n\t\t}\n\n\t\treturn sharedCache;\n\t}\n\n\t/**\n\t * Resolve a waiter by re-running its request method safely.\n\t * @param requestMethod The method to execute.\n\t * @param resolve The resolver for the waiter.\n\t * @param reject The rejector for the waiter.\n\t */\n\tprivate static async resolveWaiter<T>(\n\t\trequestMethod: () => Promise<T>,\n\t\tresolve: (value: T | PromiseLike<T>) => void,\n\t\treject: (reason?: unknown) => void\n\t): Promise<void> {\n\t\ttry {\n\t\t\tresolve(await requestMethod());\n\t\t} catch (waitErr) {\n\t\t\treject(waitErr);\n\t\t}\n\t}\n}\n"]}
|
|
@@ -39,4 +39,11 @@ export declare class AsyncCache {
|
|
|
39
39
|
* Perform a cleanup of the expired entries in the cache.
|
|
40
40
|
*/
|
|
41
41
|
static cleanupExpired(): void;
|
|
42
|
+
/**
|
|
43
|
+
* Resolve a waiter by re-running its request method safely.
|
|
44
|
+
* @param requestMethod The method to execute.
|
|
45
|
+
* @param resolve The resolver for the waiter.
|
|
46
|
+
* @param reject The rejector for the waiter.
|
|
47
|
+
*/
|
|
48
|
+
private static resolveWaiter;
|
|
42
49
|
}
|
package/docs/changelog.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.3-next.26](https://github.com/twinfoundation/framework/compare/core-v0.0.3-next.25...core-v0.0.3-next.26) (2026-03-24)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Miscellaneous Chores
|
|
7
|
+
|
|
8
|
+
* **core:** Synchronize repo versions
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @twin.org/nameof bumped from 0.0.3-next.25 to 0.0.3-next.26
|
|
16
|
+
* devDependencies
|
|
17
|
+
* @twin.org/nameof-transformer bumped from 0.0.3-next.25 to 0.0.3-next.26
|
|
18
|
+
* @twin.org/nameof-vitest-plugin bumped from 0.0.3-next.25 to 0.0.3-next.26
|
|
19
|
+
|
|
20
|
+
## [0.0.3-next.25](https://github.com/twinfoundation/framework/compare/core-v0.0.3-next.24...core-v0.0.3-next.25) (2026-03-23)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Bug Fixes
|
|
24
|
+
|
|
25
|
+
* improve exception handling in asyncCache ([c81b29b](https://github.com/twinfoundation/framework/commit/c81b29b660b152d2f0757d323430287e6491bf59))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### Dependencies
|
|
29
|
+
|
|
30
|
+
* The following workspace dependencies were updated
|
|
31
|
+
* dependencies
|
|
32
|
+
* @twin.org/nameof bumped from 0.0.3-next.24 to 0.0.3-next.25
|
|
33
|
+
* devDependencies
|
|
34
|
+
* @twin.org/nameof-transformer bumped from 0.0.3-next.24 to 0.0.3-next.25
|
|
35
|
+
* @twin.org/nameof-vitest-plugin bumped from 0.0.3-next.24 to 0.0.3-next.25
|
|
36
|
+
|
|
3
37
|
## [0.0.3-next.24](https://github.com/twinfoundation/framework/compare/core-v0.0.3-next.23...core-v0.0.3-next.24) (2026-03-19)
|
|
4
38
|
|
|
5
39
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twin.org/core",
|
|
3
|
-
"version": "0.0.3-next.
|
|
3
|
+
"version": "0.0.3-next.26",
|
|
4
4
|
"description": "Helper methods/classes for data type checking/validation/guarding/error handling",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"node": ">=20.0.0"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@twin.org/nameof": "0.0.3-next.
|
|
17
|
+
"@twin.org/nameof": "0.0.3-next.26",
|
|
18
18
|
"intl-messageformat": "11.1.3",
|
|
19
19
|
"rfc6902": "5.2.0"
|
|
20
20
|
},
|