@twin.org/core 0.0.3-next.23 → 0.0.3-next.25
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/es/utils/asyncCache.js +92 -74
- package/dist/es/utils/asyncCache.js.map +1 -1
- package/dist/types/utils/asyncCache.d.ts +7 -0
- package/docs/changelog.md +34 -0
- package/docs/reference/classes/AlreadyExistsError.md +17 -17
- package/docs/reference/classes/AsyncCache.md +2 -2
- package/docs/reference/classes/BaseError.md +17 -17
- package/docs/reference/classes/ConflictError.md +17 -17
- package/docs/reference/classes/GeneralError.md +17 -17
- package/docs/reference/classes/GuardError.md +17 -17
- package/docs/reference/classes/Guards.md +2 -2
- package/docs/reference/classes/Is.md +2 -2
- package/docs/reference/classes/JsonHelper.md +2 -2
- package/docs/reference/classes/NotFoundError.md +17 -17
- package/docs/reference/classes/NotImplementedError.md +17 -17
- package/docs/reference/classes/NotSupportedError.md +17 -17
- package/docs/reference/classes/ObjectHelper.md +12 -12
- package/docs/reference/classes/RandomHelper.md +2 -2
- package/docs/reference/classes/UnauthorizedError.md +17 -17
- package/docs/reference/classes/UnprocessableError.md +17 -17
- package/docs/reference/classes/Urn.md +2 -2
- package/docs/reference/classes/ValidationError.md +17 -17
- package/docs/reference/interfaces/IError.md +4 -4
- package/docs/reference/interfaces/ILocaleDictionary.md +1 -1
- package/docs/reference/interfaces/IPatchOperation.md +2 -2
- package/docs/reference/interfaces/IUrlParts.md +3 -3
- package/docs/reference/interfaces/IValidationFailure.md +1 -1
- package/package.json +3 -3
|
@@ -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.25](https://github.com/twinfoundation/framework/compare/core-v0.0.3-next.24...core-v0.0.3-next.25) (2026-03-23)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* improve exception handling in asyncCache ([c81b29b](https://github.com/twinfoundation/framework/commit/c81b29b660b152d2f0757d323430287e6491bf59))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @twin.org/nameof bumped from 0.0.3-next.24 to 0.0.3-next.25
|
|
16
|
+
* devDependencies
|
|
17
|
+
* @twin.org/nameof-transformer bumped from 0.0.3-next.24 to 0.0.3-next.25
|
|
18
|
+
* @twin.org/nameof-vitest-plugin bumped from 0.0.3-next.24 to 0.0.3-next.25
|
|
19
|
+
|
|
20
|
+
## [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)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Bug Fixes
|
|
24
|
+
|
|
25
|
+
* ensure __decorate is defined for decorators ([103a563](https://github.com/twinfoundation/framework/commit/103a563ce01ebdef6240d2e590e7b026e8692684))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### Dependencies
|
|
29
|
+
|
|
30
|
+
* The following workspace dependencies were updated
|
|
31
|
+
* dependencies
|
|
32
|
+
* @twin.org/nameof bumped from 0.0.3-next.23 to 0.0.3-next.24
|
|
33
|
+
* devDependencies
|
|
34
|
+
* @twin.org/nameof-transformer bumped from 0.0.3-next.23 to 0.0.3-next.24
|
|
35
|
+
* @twin.org/nameof-vitest-plugin bumped from 0.0.3-next.23 to 0.0.3-next.24
|
|
36
|
+
|
|
3
37
|
## [0.0.3-next.23](https://github.com/twinfoundation/framework/compare/core-v0.0.3-next.22...core-v0.0.3-next.23) (2026-03-17)
|
|
4
38
|
|
|
5
39
|
|
|
@@ -64,7 +64,7 @@ Runtime name for the class.
|
|
|
64
64
|
|
|
65
65
|
### source? {#source}
|
|
66
66
|
|
|
67
|
-
> `optional` **source
|
|
67
|
+
> `optional` **source?**: `string`
|
|
68
68
|
|
|
69
69
|
The source of the error.
|
|
70
70
|
|
|
@@ -76,7 +76,7 @@ The source of the error.
|
|
|
76
76
|
|
|
77
77
|
### properties? {#properties}
|
|
78
78
|
|
|
79
|
-
> `optional` **properties
|
|
79
|
+
> `optional` **properties?**: `object`
|
|
80
80
|
|
|
81
81
|
Any additional information for the error.
|
|
82
82
|
|
|
@@ -92,7 +92,7 @@ Any additional information for the error.
|
|
|
92
92
|
|
|
93
93
|
### cause? {#cause}
|
|
94
94
|
|
|
95
|
-
> `optional` **cause
|
|
95
|
+
> `optional` **cause?**: [`IError`](../interfaces/IError.md)
|
|
96
96
|
|
|
97
97
|
The cause of the error.
|
|
98
98
|
|
|
@@ -164,9 +164,9 @@ Expand an error tree.
|
|
|
164
164
|
|
|
165
165
|
##### errors
|
|
166
166
|
|
|
167
|
-
|
|
167
|
+
[`IError`](../interfaces/IError.md)[] \| `undefined`
|
|
168
168
|
|
|
169
|
-
|
|
169
|
+
The list of errors to expand.
|
|
170
170
|
|
|
171
171
|
#### Returns
|
|
172
172
|
|
|
@@ -196,9 +196,9 @@ The error to test.
|
|
|
196
196
|
|
|
197
197
|
##### name
|
|
198
198
|
|
|
199
|
-
|
|
199
|
+
`string` \| `RegExp`
|
|
200
200
|
|
|
201
|
-
|
|
201
|
+
The name to check for.
|
|
202
202
|
|
|
203
203
|
#### Returns
|
|
204
204
|
|
|
@@ -228,9 +228,9 @@ The error to test.
|
|
|
228
228
|
|
|
229
229
|
##### message
|
|
230
230
|
|
|
231
|
-
|
|
231
|
+
`string` \| `RegExp`
|
|
232
232
|
|
|
233
|
-
|
|
233
|
+
The message to check for.
|
|
234
234
|
|
|
235
235
|
#### Returns
|
|
236
236
|
|
|
@@ -260,9 +260,9 @@ The error to test.
|
|
|
260
260
|
|
|
261
261
|
##### code
|
|
262
262
|
|
|
263
|
-
|
|
263
|
+
`string` \| `RegExp`
|
|
264
264
|
|
|
265
|
-
|
|
265
|
+
The code to check for.
|
|
266
266
|
|
|
267
267
|
#### Returns
|
|
268
268
|
|
|
@@ -292,9 +292,9 @@ The error to test.
|
|
|
292
292
|
|
|
293
293
|
##### name
|
|
294
294
|
|
|
295
|
-
|
|
295
|
+
`string` \| `RegExp`
|
|
296
296
|
|
|
297
|
-
|
|
297
|
+
The name to check for.
|
|
298
298
|
|
|
299
299
|
#### Returns
|
|
300
300
|
|
|
@@ -324,9 +324,9 @@ The error to test.
|
|
|
324
324
|
|
|
325
325
|
##### message
|
|
326
326
|
|
|
327
|
-
|
|
327
|
+
`string` \| `RegExp`
|
|
328
328
|
|
|
329
|
-
|
|
329
|
+
The message to check for.
|
|
330
330
|
|
|
331
331
|
#### Returns
|
|
332
332
|
|
|
@@ -388,9 +388,9 @@ The error to test.
|
|
|
388
388
|
|
|
389
389
|
##### code
|
|
390
390
|
|
|
391
|
-
|
|
391
|
+
`string` \| `RegExp`
|
|
392
392
|
|
|
393
|
-
|
|
393
|
+
The code to check for.
|
|
394
394
|
|
|
395
395
|
#### Returns
|
|
396
396
|
|
|
@@ -73,7 +73,7 @@ The cause of error if we have wrapped another error.
|
|
|
73
73
|
|
|
74
74
|
### source? {#source}
|
|
75
75
|
|
|
76
|
-
> `optional` **source
|
|
76
|
+
> `optional` **source?**: `string`
|
|
77
77
|
|
|
78
78
|
The source of the error.
|
|
79
79
|
|
|
@@ -85,7 +85,7 @@ The source of the error.
|
|
|
85
85
|
|
|
86
86
|
### properties? {#properties}
|
|
87
87
|
|
|
88
|
-
> `optional` **properties
|
|
88
|
+
> `optional` **properties?**: `object`
|
|
89
89
|
|
|
90
90
|
Any additional information for the error.
|
|
91
91
|
|
|
@@ -101,7 +101,7 @@ Any additional information for the error.
|
|
|
101
101
|
|
|
102
102
|
### cause? {#cause}
|
|
103
103
|
|
|
104
|
-
> `optional` **cause
|
|
104
|
+
> `optional` **cause?**: [`IError`](../interfaces/IError.md)
|
|
105
105
|
|
|
106
106
|
The cause of the error.
|
|
107
107
|
|
|
@@ -169,9 +169,9 @@ Expand an error tree.
|
|
|
169
169
|
|
|
170
170
|
##### errors
|
|
171
171
|
|
|
172
|
-
|
|
172
|
+
[`IError`](../interfaces/IError.md)[] \| `undefined`
|
|
173
173
|
|
|
174
|
-
|
|
174
|
+
The list of errors to expand.
|
|
175
175
|
|
|
176
176
|
#### Returns
|
|
177
177
|
|
|
@@ -197,9 +197,9 @@ The error to test.
|
|
|
197
197
|
|
|
198
198
|
##### name
|
|
199
199
|
|
|
200
|
-
|
|
200
|
+
`string` \| `RegExp`
|
|
201
201
|
|
|
202
|
-
|
|
202
|
+
The name to check for.
|
|
203
203
|
|
|
204
204
|
#### Returns
|
|
205
205
|
|
|
@@ -225,9 +225,9 @@ The error to test.
|
|
|
225
225
|
|
|
226
226
|
##### message
|
|
227
227
|
|
|
228
|
-
|
|
228
|
+
`string` \| `RegExp`
|
|
229
229
|
|
|
230
|
-
|
|
230
|
+
The message to check for.
|
|
231
231
|
|
|
232
232
|
#### Returns
|
|
233
233
|
|
|
@@ -253,9 +253,9 @@ The error to test.
|
|
|
253
253
|
|
|
254
254
|
##### code
|
|
255
255
|
|
|
256
|
-
|
|
256
|
+
`string` \| `RegExp`
|
|
257
257
|
|
|
258
|
-
|
|
258
|
+
The code to check for.
|
|
259
259
|
|
|
260
260
|
#### Returns
|
|
261
261
|
|
|
@@ -281,9 +281,9 @@ The error to test.
|
|
|
281
281
|
|
|
282
282
|
##### name
|
|
283
283
|
|
|
284
|
-
|
|
284
|
+
`string` \| `RegExp`
|
|
285
285
|
|
|
286
|
-
|
|
286
|
+
The name to check for.
|
|
287
287
|
|
|
288
288
|
#### Returns
|
|
289
289
|
|
|
@@ -309,9 +309,9 @@ The error to test.
|
|
|
309
309
|
|
|
310
310
|
##### message
|
|
311
311
|
|
|
312
|
-
|
|
312
|
+
`string` \| `RegExp`
|
|
313
313
|
|
|
314
|
-
|
|
314
|
+
The message to check for.
|
|
315
315
|
|
|
316
316
|
#### Returns
|
|
317
317
|
|
|
@@ -365,9 +365,9 @@ The error to test.
|
|
|
365
365
|
|
|
366
366
|
##### code
|
|
367
367
|
|
|
368
|
-
|
|
368
|
+
`string` \| `RegExp`
|
|
369
369
|
|
|
370
|
-
|
|
370
|
+
The code to check for.
|
|
371
371
|
|
|
372
372
|
#### Returns
|
|
373
373
|
|
|
@@ -62,7 +62,7 @@ The cause or the error if we have wrapped another error.
|
|
|
62
62
|
|
|
63
63
|
### source? {#source}
|
|
64
64
|
|
|
65
|
-
> `optional` **source
|
|
65
|
+
> `optional` **source?**: `string`
|
|
66
66
|
|
|
67
67
|
The source of the error.
|
|
68
68
|
|
|
@@ -74,7 +74,7 @@ The source of the error.
|
|
|
74
74
|
|
|
75
75
|
### properties? {#properties}
|
|
76
76
|
|
|
77
|
-
> `optional` **properties
|
|
77
|
+
> `optional` **properties?**: `object`
|
|
78
78
|
|
|
79
79
|
Any additional information for the error.
|
|
80
80
|
|
|
@@ -90,7 +90,7 @@ Any additional information for the error.
|
|
|
90
90
|
|
|
91
91
|
### cause? {#cause}
|
|
92
92
|
|
|
93
|
-
> `optional` **cause
|
|
93
|
+
> `optional` **cause?**: [`IError`](../interfaces/IError.md)
|
|
94
94
|
|
|
95
95
|
The cause of the error.
|
|
96
96
|
|
|
@@ -170,9 +170,9 @@ Expand an error tree.
|
|
|
170
170
|
|
|
171
171
|
##### errors
|
|
172
172
|
|
|
173
|
-
|
|
173
|
+
[`IError`](../interfaces/IError.md)[] \| `undefined`
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
The list of errors to expand.
|
|
176
176
|
|
|
177
177
|
#### Returns
|
|
178
178
|
|
|
@@ -202,9 +202,9 @@ The error to test.
|
|
|
202
202
|
|
|
203
203
|
##### name
|
|
204
204
|
|
|
205
|
-
|
|
205
|
+
`string` \| `RegExp`
|
|
206
206
|
|
|
207
|
-
|
|
207
|
+
The name to check for.
|
|
208
208
|
|
|
209
209
|
#### Returns
|
|
210
210
|
|
|
@@ -234,9 +234,9 @@ The error to test.
|
|
|
234
234
|
|
|
235
235
|
##### message
|
|
236
236
|
|
|
237
|
-
|
|
237
|
+
`string` \| `RegExp`
|
|
238
238
|
|
|
239
|
-
|
|
239
|
+
The message to check for.
|
|
240
240
|
|
|
241
241
|
#### Returns
|
|
242
242
|
|
|
@@ -266,9 +266,9 @@ The error to test.
|
|
|
266
266
|
|
|
267
267
|
##### code
|
|
268
268
|
|
|
269
|
-
|
|
269
|
+
`string` \| `RegExp`
|
|
270
270
|
|
|
271
|
-
|
|
271
|
+
The code to check for.
|
|
272
272
|
|
|
273
273
|
#### Returns
|
|
274
274
|
|
|
@@ -298,9 +298,9 @@ The error to test.
|
|
|
298
298
|
|
|
299
299
|
##### name
|
|
300
300
|
|
|
301
|
-
|
|
301
|
+
`string` \| `RegExp`
|
|
302
302
|
|
|
303
|
-
|
|
303
|
+
The name to check for.
|
|
304
304
|
|
|
305
305
|
#### Returns
|
|
306
306
|
|
|
@@ -330,9 +330,9 @@ The error to test.
|
|
|
330
330
|
|
|
331
331
|
##### message
|
|
332
332
|
|
|
333
|
-
|
|
333
|
+
`string` \| `RegExp`
|
|
334
334
|
|
|
335
|
-
|
|
335
|
+
The message to check for.
|
|
336
336
|
|
|
337
337
|
#### Returns
|
|
338
338
|
|
|
@@ -394,9 +394,9 @@ The error to test.
|
|
|
394
394
|
|
|
395
395
|
##### code
|
|
396
396
|
|
|
397
|
-
|
|
397
|
+
`string` \| `RegExp`
|
|
398
398
|
|
|
399
|
-
|
|
399
|
+
The code to check for.
|
|
400
400
|
|
|
401
401
|
#### Returns
|
|
402
402
|
|