xypriss 9.6.97 → 9.7.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/README.md +55 -22
- package/dist/cjs/src/index.js +0 -19
- package/dist/cjs/src/index.js.map +1 -1
- package/dist/cjs/src/middleware/built-in/BuiltInMiddleware.js +4 -4
- package/dist/cjs/src/middleware/built-in/BuiltInMiddleware.js.map +1 -1
- package/dist/cjs/src/middleware/built-in/security/HoneypotTarpit.js +510 -0
- package/dist/cjs/src/middleware/built-in/security/HoneypotTarpit.js.map +1 -0
- package/dist/cjs/src/middleware/built-in/security/SQLInjectionDetector.js +113 -34
- package/dist/cjs/src/middleware/built-in/security/SQLInjectionDetector.js.map +1 -1
- package/dist/cjs/src/middleware/built-in/security/UriNormalizer.js +413 -0
- package/dist/cjs/src/middleware/built-in/security/UriNormalizer.js.map +1 -0
- package/dist/cjs/src/middleware/built-in/security/XyPrissCors.js +98 -0
- package/dist/cjs/src/middleware/built-in/security/XyPrissCors.js.map +1 -0
- package/dist/cjs/src/middleware/built-in/security/XyPrissHPP.js +52 -0
- package/dist/cjs/src/middleware/built-in/security/XyPrissHPP.js.map +1 -0
- package/dist/cjs/src/middleware/safe-json-middleware.js +0 -82
- package/dist/cjs/src/middleware/safe-json-middleware.js.map +1 -1
- package/dist/cjs/src/middleware/security-middleware.js +7 -4
- package/dist/cjs/src/middleware/security-middleware.js.map +1 -1
- package/dist/cjs/src/plugins/builtin/xems/XemsBuiltinPlugin.js +33 -10
- package/dist/cjs/src/plugins/builtin/xems/XemsBuiltinPlugin.js.map +1 -1
- package/dist/cjs/src/plugins/builtin/xems/XemsPlugin.js +34 -3
- package/dist/cjs/src/plugins/builtin/xems/XemsPlugin.js.map +1 -1
- package/dist/cjs/src/plugins/const/OFFICIAL_PLUGINS.js +1 -1
- package/dist/cjs/src/plugins/const/OFFICIAL_PLUGINS.js.map +1 -1
- package/dist/cjs/src/plugins/const/XyprissTempDir.js +72 -9
- package/dist/cjs/src/plugins/const/XyprissTempDir.js.map +1 -1
- package/dist/cjs/src/plugins/core/manager/PluginLoader.js +8 -0
- package/dist/cjs/src/plugins/core/manager/PluginLoader.js.map +1 -1
- package/dist/cjs/src/plugins/core/manager/PluginSecurity.js +87 -0
- package/dist/cjs/src/plugins/core/manager/PluginSecurity.js.map +1 -1
- package/dist/cjs/src/server/FastServer/index.js +5 -0
- package/dist/cjs/src/server/FastServer/index.js.map +1 -1
- package/dist/cjs/src/server/ServerFactory.js +8 -13
- package/dist/cjs/src/server/ServerFactory.js.map +1 -1
- package/dist/cjs/src/server/components/fastapi/RedirectManager.js +8 -58
- package/dist/cjs/src/server/components/fastapi/RedirectManager.js.map +1 -1
- package/dist/cjs/src/server/components/fastapi/upload/FileUploadManager.js +1 -1
- package/dist/cjs/src/server/components/fastapi/upload/FileUploadManager.js.map +1 -1
- package/dist/cjs/src/server/components/multi-server/MultiServerManager.js +9 -1
- package/dist/cjs/src/server/components/multi-server/MultiServerManager.js.map +1 -1
- package/dist/cjs/src/server/core/HttpServer.js +22 -0
- package/dist/cjs/src/server/core/HttpServer.js.map +1 -1
- package/dist/cjs/src/server/core/XHSCBridge/EngineManager.js +33 -2
- package/dist/cjs/src/server/core/XHSCBridge/EngineManager.js.map +1 -1
- package/dist/cjs/src/server/core/XHSCBridge/cmd/buildSecurityArgs.js +1 -1
- package/dist/cjs/src/server/core/XHSCBridge/cmd/buildSecurityArgs.js.map +1 -1
- package/dist/cjs/src/server/core/XyServerCreator.js +1 -0
- package/dist/cjs/src/server/core/XyServerCreator.js.map +1 -1
- package/dist/cjs/src/shared/logger/quickLogger.js +162 -0
- package/dist/cjs/src/shared/logger/quickLogger.js.map +1 -0
- package/dist/cjs/src/xhsc/PathApi.js +44 -3
- package/dist/cjs/src/xhsc/PathApi.js.map +1 -1
- package/dist/cjs/src/xhsc/System.js +2 -0
- package/dist/cjs/src/xhsc/System.js.map +1 -1
- package/dist/cjs/src/xhsc/UtilsApi.js +52 -0
- package/dist/cjs/src/xhsc/UtilsApi.js.map +1 -0
- package/dist/cjs/src/xhsc/XyPrissRunner.js +30 -2
- package/dist/cjs/src/xhsc/XyPrissRunner.js.map +1 -1
- package/dist/cjs/src/xhsc/fs/FSCore.js +148 -0
- package/dist/cjs/src/xhsc/fs/FSCore.js.map +1 -1
- package/dist/cjs/src/xhsc/fs/FileHandle.js +112 -0
- package/dist/cjs/src/xhsc/fs/FileHandle.js.map +1 -0
- package/dist/cjs/src/xhsc/ipc/XHSCDirectIPC.js +134 -0
- package/dist/cjs/src/xhsc/ipc/XHSCDirectIPC.js.map +1 -0
- package/dist/cjs/src/xhsc/utils/ArrayUtils.js +67 -0
- package/dist/cjs/src/xhsc/utils/ArrayUtils.js.map +1 -0
- package/dist/cjs/src/xhsc/utils/AsyncUtils.js +582 -0
- package/dist/cjs/src/xhsc/utils/AsyncUtils.js.map +1 -0
- package/dist/cjs/src/xhsc/utils/DateUtils.js +959 -0
- package/dist/cjs/src/xhsc/utils/DateUtils.js.map +1 -0
- package/dist/cjs/src/xhsc/utils/FunctionUtils.js +29 -0
- package/dist/cjs/src/xhsc/utils/FunctionUtils.js.map +1 -0
- package/dist/cjs/src/xhsc/utils/IdUtils.js +22 -0
- package/dist/cjs/src/xhsc/utils/IdUtils.js.map +1 -0
- package/dist/cjs/src/xhsc/utils/NumberUtils.js +79 -0
- package/dist/cjs/src/xhsc/utils/NumberUtils.js.map +1 -0
- package/dist/cjs/src/xhsc/utils/ObjectUtils.js +141 -0
- package/dist/cjs/src/xhsc/utils/ObjectUtils.js.map +1 -0
- package/dist/cjs/src/xhsc/utils/StringUtils.js +145 -0
- package/dist/cjs/src/xhsc/utils/StringUtils.js.map +1 -0
- package/dist/cjs/src/xhsc/utils/ValidationUtils.js +49 -0
- package/dist/cjs/src/xhsc/utils/ValidationUtils.js.map +1 -0
- package/dist/cjs/src/xhsc.js +5 -3
- package/dist/cjs/src/xhsc.js.map +1 -1
- package/dist/esm/src/index.js +0 -2
- package/dist/esm/src/index.js.map +1 -1
- package/dist/esm/src/middleware/built-in/BuiltInMiddleware.js +4 -4
- package/dist/esm/src/middleware/built-in/BuiltInMiddleware.js.map +1 -1
- package/dist/esm/src/middleware/built-in/security/HoneypotTarpit.js +508 -0
- package/dist/esm/src/middleware/built-in/security/HoneypotTarpit.js.map +1 -0
- package/dist/esm/src/middleware/built-in/security/SQLInjectionDetector.js +113 -34
- package/dist/esm/src/middleware/built-in/security/SQLInjectionDetector.js.map +1 -1
- package/dist/esm/src/middleware/built-in/security/UriNormalizer.js +391 -0
- package/dist/esm/src/middleware/built-in/security/UriNormalizer.js.map +1 -0
- package/dist/esm/src/middleware/built-in/security/XyPrissCors.js +96 -0
- package/dist/esm/src/middleware/built-in/security/XyPrissCors.js.map +1 -0
- package/dist/esm/src/middleware/built-in/security/XyPrissHPP.js +50 -0
- package/dist/esm/src/middleware/built-in/security/XyPrissHPP.js.map +1 -0
- package/dist/esm/src/middleware/safe-json-middleware.js +1 -79
- package/dist/esm/src/middleware/safe-json-middleware.js.map +1 -1
- package/dist/esm/src/middleware/security-middleware.js +7 -4
- package/dist/esm/src/middleware/security-middleware.js.map +1 -1
- package/dist/esm/src/plugins/builtin/xems/XemsBuiltinPlugin.js +33 -10
- package/dist/esm/src/plugins/builtin/xems/XemsBuiltinPlugin.js.map +1 -1
- package/dist/esm/src/plugins/builtin/xems/XemsPlugin.js +34 -3
- package/dist/esm/src/plugins/builtin/xems/XemsPlugin.js.map +1 -1
- package/dist/esm/src/plugins/const/OFFICIAL_PLUGINS.js +1 -1
- package/dist/esm/src/plugins/const/OFFICIAL_PLUGINS.js.map +1 -1
- package/dist/esm/src/plugins/const/XyprissTempDir.js +70 -9
- package/dist/esm/src/plugins/const/XyprissTempDir.js.map +1 -1
- package/dist/esm/src/plugins/core/manager/PluginLoader.js +8 -0
- package/dist/esm/src/plugins/core/manager/PluginLoader.js.map +1 -1
- package/dist/esm/src/plugins/core/manager/PluginSecurity.js +87 -0
- package/dist/esm/src/plugins/core/manager/PluginSecurity.js.map +1 -1
- package/dist/esm/src/server/FastServer/index.js +5 -0
- package/dist/esm/src/server/FastServer/index.js.map +1 -1
- package/dist/esm/src/server/ServerFactory.js +8 -1
- package/dist/esm/src/server/ServerFactory.js.map +1 -1
- package/dist/esm/src/server/components/fastapi/RedirectManager.js +8 -58
- package/dist/esm/src/server/components/fastapi/RedirectManager.js.map +1 -1
- package/dist/esm/src/server/components/fastapi/upload/FileUploadManager.js +1 -1
- package/dist/esm/src/server/components/fastapi/upload/FileUploadManager.js.map +1 -1
- package/dist/esm/src/server/components/multi-server/MultiServerManager.js +9 -1
- package/dist/esm/src/server/components/multi-server/MultiServerManager.js.map +1 -1
- package/dist/esm/src/server/core/HttpServer.js +22 -0
- package/dist/esm/src/server/core/HttpServer.js.map +1 -1
- package/dist/esm/src/server/core/XHSCBridge/EngineManager.js +33 -2
- package/dist/esm/src/server/core/XHSCBridge/EngineManager.js.map +1 -1
- package/dist/esm/src/server/core/XHSCBridge/cmd/buildSecurityArgs.js +1 -1
- package/dist/esm/src/server/core/XHSCBridge/cmd/buildSecurityArgs.js.map +1 -1
- package/dist/esm/src/server/core/XyServerCreator.js +1 -0
- package/dist/esm/src/server/core/XyServerCreator.js.map +1 -1
- package/dist/esm/src/shared/logger/quickLogger.js +160 -0
- package/dist/esm/src/shared/logger/quickLogger.js.map +1 -0
- package/dist/esm/src/xhsc/PathApi.js +44 -3
- package/dist/esm/src/xhsc/PathApi.js.map +1 -1
- package/dist/esm/src/xhsc/System.js +2 -0
- package/dist/esm/src/xhsc/System.js.map +1 -1
- package/dist/esm/src/xhsc/UtilsApi.js +50 -0
- package/dist/esm/src/xhsc/UtilsApi.js.map +1 -0
- package/dist/esm/src/xhsc/XyPrissRunner.js +30 -2
- package/dist/esm/src/xhsc/XyPrissRunner.js.map +1 -1
- package/dist/esm/src/xhsc/fs/FSCore.js +148 -0
- package/dist/esm/src/xhsc/fs/FSCore.js.map +1 -1
- package/dist/esm/src/xhsc/fs/FileHandle.js +110 -0
- package/dist/esm/src/xhsc/fs/FileHandle.js.map +1 -0
- package/dist/esm/src/xhsc/ipc/XHSCDirectIPC.js +113 -0
- package/dist/esm/src/xhsc/ipc/XHSCDirectIPC.js.map +1 -0
- package/dist/esm/src/xhsc/utils/ArrayUtils.js +65 -0
- package/dist/esm/src/xhsc/utils/ArrayUtils.js.map +1 -0
- package/dist/esm/src/xhsc/utils/AsyncUtils.js +580 -0
- package/dist/esm/src/xhsc/utils/AsyncUtils.js.map +1 -0
- package/dist/esm/src/xhsc/utils/DateUtils.js +957 -0
- package/dist/esm/src/xhsc/utils/DateUtils.js.map +1 -0
- package/dist/esm/src/xhsc/utils/FunctionUtils.js +27 -0
- package/dist/esm/src/xhsc/utils/FunctionUtils.js.map +1 -0
- package/dist/esm/src/xhsc/utils/IdUtils.js +20 -0
- package/dist/esm/src/xhsc/utils/IdUtils.js.map +1 -0
- package/dist/esm/src/xhsc/utils/NumberUtils.js +77 -0
- package/dist/esm/src/xhsc/utils/NumberUtils.js.map +1 -0
- package/dist/esm/src/xhsc/utils/ObjectUtils.js +139 -0
- package/dist/esm/src/xhsc/utils/ObjectUtils.js.map +1 -0
- package/dist/esm/src/xhsc/utils/StringUtils.js +143 -0
- package/dist/esm/src/xhsc/utils/StringUtils.js.map +1 -0
- package/dist/esm/src/xhsc/utils/ValidationUtils.js +47 -0
- package/dist/esm/src/xhsc/utils/ValidationUtils.js.map +1 -0
- package/dist/esm/src/xhsc.js +6 -5
- package/dist/esm/src/xhsc.js.map +1 -1
- package/dist/index.d.ts +1872 -234
- package/package.json +119 -137
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* # AsyncUtils — XyPriss Async Control Flow
|
|
5
|
+
*
|
|
6
|
+
* A comprehensive library of asynchronous control flow primitives for TypeScript.
|
|
7
|
+
* Each method is designed to be safe, performant, and composable.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* const async = new AsyncUtils();
|
|
12
|
+
*
|
|
13
|
+
* // Auto-retry + debounce + performance measurement in a few lines
|
|
14
|
+
* const save = async.debounce(async (data: string) => {
|
|
15
|
+
* const { result, durationMs } = await async.measure(() =>
|
|
16
|
+
* async.retry(() => api.save(data), { maxAttempts: 3, delay: 1000 })
|
|
17
|
+
* );
|
|
18
|
+
* console.log(`Saved in ${durationMs.toFixed(1)}ms`, result);
|
|
19
|
+
* }, 500);
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @module AsyncUtils
|
|
23
|
+
*/
|
|
24
|
+
// ─── Class ────────────────────────────────────────────────────────────────────
|
|
25
|
+
class AsyncUtils {
|
|
26
|
+
// ─── Timing Primitives ───────────────────────────────────────────────────
|
|
27
|
+
/**
|
|
28
|
+
* ## Asynchronous Pause
|
|
29
|
+
*
|
|
30
|
+
* Suspends execution for a given duration.
|
|
31
|
+
* Compatible with `AbortSignal`: sleep will be interrupted cleanly
|
|
32
|
+
* if the signal is triggered (the promise **resolves** without error in this case).
|
|
33
|
+
*
|
|
34
|
+
* @param ms - Pause duration in milliseconds.
|
|
35
|
+
* @param signal - Optional cancellation signal (AbortController).
|
|
36
|
+
* @returns A promise that resolves after `ms` ms (or earlier if signal triggered).
|
|
37
|
+
*
|
|
38
|
+
* @example Simple pause
|
|
39
|
+
* ```ts
|
|
40
|
+
* await utils.sleep(2000); // waits 2 seconds
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @example Cancellation via AbortController
|
|
44
|
+
* ```ts
|
|
45
|
+
* const controller = new AbortController();
|
|
46
|
+
* setTimeout(() => controller.abort(), 500);
|
|
47
|
+
*
|
|
48
|
+
* await utils.sleep(5000, controller.signal); // resolves after ~500ms
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
sleep(ms, signal) {
|
|
52
|
+
return new Promise((resolve) => {
|
|
53
|
+
if (signal?.aborted)
|
|
54
|
+
return resolve();
|
|
55
|
+
let timer;
|
|
56
|
+
const onAbort = () => {
|
|
57
|
+
if (timer)
|
|
58
|
+
clearTimeout(timer);
|
|
59
|
+
resolve();
|
|
60
|
+
};
|
|
61
|
+
timer = setTimeout(() => {
|
|
62
|
+
signal?.removeEventListener("abort", onAbort);
|
|
63
|
+
resolve();
|
|
64
|
+
}, ms);
|
|
65
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* ## Asynchronous Pause (alias of `sleep`)
|
|
70
|
+
*
|
|
71
|
+
* @alias sleep
|
|
72
|
+
* @see {@link sleep}
|
|
73
|
+
*/
|
|
74
|
+
wait(ms, signal) {
|
|
75
|
+
return this.sleep(ms, signal);
|
|
76
|
+
}
|
|
77
|
+
// ─── Robustness & Resilience ─────────────────────────────────────────────
|
|
78
|
+
/**
|
|
79
|
+
* ## Retry with Exponential Backoff
|
|
80
|
+
*
|
|
81
|
+
* Retries an asynchronous operation up to `maxAttempts` times.
|
|
82
|
+
* Supports exponential backoff, maximum delay, filter predicate,
|
|
83
|
+
* and `AbortSignal` to interrupt the retry cycle.
|
|
84
|
+
*
|
|
85
|
+
* Delay formula: `min(delay × backoffFactor^attempt, maxDelay)`.
|
|
86
|
+
*
|
|
87
|
+
* @param fn - The asynchronous function to execute.
|
|
88
|
+
* @param options - Retry options (see {@link RetryOptions}).
|
|
89
|
+
* @returns Resolved value of `fn` on the first successful attempt.
|
|
90
|
+
* @throws Last error if all attempts fail.
|
|
91
|
+
*
|
|
92
|
+
* @example Basic retry (3 attempts, 500ms between each)
|
|
93
|
+
* ```ts
|
|
94
|
+
* const data = await utils.retry(() => fetch("/api/data").then(r => r.json()));
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* @example Exponential backoff: 200ms → 400ms → 800ms → max 1000ms
|
|
98
|
+
* ```ts
|
|
99
|
+
* const result = await utils.retry(() => unstableApi(), {
|
|
100
|
+
* maxAttempts: 4,
|
|
101
|
+
* delay: 200,
|
|
102
|
+
* backoffFactor: 2,
|
|
103
|
+
* maxDelay: 1000,
|
|
104
|
+
* onRetry: (err, n) => console.warn(`Retry #${n}`, err),
|
|
105
|
+
* });
|
|
106
|
+
* ```
|
|
107
|
+
*
|
|
108
|
+
* @example Do not retry auth errors
|
|
109
|
+
* ```ts
|
|
110
|
+
* await utils.retry(() => api.call(), {
|
|
111
|
+
* retryIf: (err) => !(err instanceof AuthError),
|
|
112
|
+
* });
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
async retry(fn, options = {}) {
|
|
116
|
+
const { maxAttempts = 3, delay = 500, backoffFactor = 1, maxDelay = Infinity, signal, retryIf, onRetry, } = options;
|
|
117
|
+
let lastError;
|
|
118
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
119
|
+
if (signal?.aborted)
|
|
120
|
+
throw lastError ?? new DOMException("Aborted", "AbortError");
|
|
121
|
+
try {
|
|
122
|
+
return await fn();
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
lastError = err;
|
|
126
|
+
if (retryIf && !retryIf(err, attempt + 1))
|
|
127
|
+
throw err;
|
|
128
|
+
if (attempt < maxAttempts - 1) {
|
|
129
|
+
onRetry?.(err, attempt + 1);
|
|
130
|
+
const wait = Math.min(delay * Math.pow(backoffFactor, attempt), maxDelay);
|
|
131
|
+
await this.sleep(wait, signal);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
throw lastError;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* ## Promise Timeout
|
|
139
|
+
*
|
|
140
|
+
* Wraps a promise with a maximum duration. If the promise does not
|
|
141
|
+
* resolve within the given time, an `Error` is thrown.
|
|
142
|
+
*
|
|
143
|
+
* Automatically handles internal timer cleanup to prevent memory leaks.
|
|
144
|
+
*
|
|
145
|
+
* @param fn - Function returning the promise to monitor.
|
|
146
|
+
* @param ms - Maximum delay in milliseconds before rejecting.
|
|
147
|
+
* @param options - Additional options (error message, cancellation signal).
|
|
148
|
+
* @returns Resolved value if the promise succeeds within delay.
|
|
149
|
+
* @throws `Error` with `options.message` if timeout is reached.
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```ts
|
|
153
|
+
* const result = await utils.timeout(
|
|
154
|
+
* () => fetch("/slow-api").then(r => r.json()),
|
|
155
|
+
* 3000,
|
|
156
|
+
* { message: "API took too long to respond" }
|
|
157
|
+
* );
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
timeout(fn, ms, options = {}) {
|
|
161
|
+
const { message = "Operation timed out", signal } = options;
|
|
162
|
+
return new Promise((resolve, reject) => {
|
|
163
|
+
const onAbort = () => {
|
|
164
|
+
clearTimeout(timer);
|
|
165
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
166
|
+
};
|
|
167
|
+
const timer = setTimeout(() => {
|
|
168
|
+
signal?.removeEventListener("abort", onAbort);
|
|
169
|
+
reject(new Error(message));
|
|
170
|
+
}, ms);
|
|
171
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
172
|
+
fn().then((val) => {
|
|
173
|
+
clearTimeout(timer);
|
|
174
|
+
signal?.removeEventListener("abort", onAbort);
|
|
175
|
+
resolve(val);
|
|
176
|
+
}, (err) => {
|
|
177
|
+
clearTimeout(timer);
|
|
178
|
+
signal?.removeEventListener("abort", onAbort);
|
|
179
|
+
reject(err);
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* ## Safe Execution (Never Throws)
|
|
185
|
+
*
|
|
186
|
+
* Executes an asynchronous function and always captures the result as a
|
|
187
|
+
* discriminated object `{ ok, value }` or `{ ok, error }`.
|
|
188
|
+
* **Never throws exceptions**, simplifying control flow.
|
|
189
|
+
*
|
|
190
|
+
* Ideal for API calls, parsing, or any operation where failure is a normal outcome
|
|
191
|
+
* and must be handled explicitly.
|
|
192
|
+
*
|
|
193
|
+
* @param fn - Asynchronous function to execute safely.
|
|
194
|
+
* @returns Discriminated object indicating success or failure.
|
|
195
|
+
*
|
|
196
|
+
* @example Without `attempt` (verbose)
|
|
197
|
+
* ```ts
|
|
198
|
+
* let user;
|
|
199
|
+
* try { user = await fetchUser(id); }
|
|
200
|
+
* catch (e) { console.error(e); return; }
|
|
201
|
+
* ```
|
|
202
|
+
*
|
|
203
|
+
* @example With `attempt` (concise)
|
|
204
|
+
* ```ts
|
|
205
|
+
* const { ok, value: user, error } = await utils.attempt(() => fetchUser(id));
|
|
206
|
+
* if (!ok) { console.error(error); return; }
|
|
207
|
+
* // `user` is guaranteed defined here
|
|
208
|
+
* ```
|
|
209
|
+
*
|
|
210
|
+
* @example Combined with `retry`
|
|
211
|
+
* ```ts
|
|
212
|
+
* const { ok, value } = await utils.attempt(() =>
|
|
213
|
+
* utils.retry(() => api.getData(), { maxAttempts: 5 })
|
|
214
|
+
* );
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
async attempt(fn) {
|
|
218
|
+
try {
|
|
219
|
+
const value = await fn();
|
|
220
|
+
return { ok: true, value };
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
return { ok: false, error };
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// ─── Rate Limiting & Flow Control ────────────────────────────────────────
|
|
227
|
+
/**
|
|
228
|
+
* ## Debounce
|
|
229
|
+
*
|
|
230
|
+
* Delays execution of `fn` until `wait` ms have elapsed since the last call.
|
|
231
|
+
* If a new call arrives before the delay ends, the previous one is cancelled
|
|
232
|
+
* and the timer restarts from zero.
|
|
233
|
+
*
|
|
234
|
+
* Typical use cases: search fields (prevents one request per keystroke),
|
|
235
|
+
* resize listeners, auto-save.
|
|
236
|
+
*
|
|
237
|
+
* The returned version exposes a `.cancel()` method to manually cancel the
|
|
238
|
+
* pending timer, and `.flush()` to trigger execution immediately.
|
|
239
|
+
*
|
|
240
|
+
* @param fn - Function to debounce.
|
|
241
|
+
* @param wait - Quiet period required before execution (ms). @default 300
|
|
242
|
+
* @returns Debounced version of `fn` with `.cancel()` and `.flush()` methods.
|
|
243
|
+
*
|
|
244
|
+
* @example Real-time search
|
|
245
|
+
* ```ts
|
|
246
|
+
* const search = utils.debounce((query: string) => {
|
|
247
|
+
* fetch(`/api/search?q=${query}`);
|
|
248
|
+
* }, 400);
|
|
249
|
+
*
|
|
250
|
+
* input.addEventListener("input", (e) => search(e.target.value));
|
|
251
|
+
* ```
|
|
252
|
+
*
|
|
253
|
+
* @example Explicit cancellation (e.g., on component unmount)
|
|
254
|
+
* ```ts
|
|
255
|
+
* const save = utils.debounce(saveToServer, 1000);
|
|
256
|
+
* onUnmount(() => save.cancel());
|
|
257
|
+
* ```
|
|
258
|
+
*
|
|
259
|
+
* @example Immediate flush (e.g., before navigation)
|
|
260
|
+
* ```ts
|
|
261
|
+
* window.addEventListener("beforeunload", () => save.flush());
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
debounce(fn, wait = 300) {
|
|
265
|
+
let timeout = null;
|
|
266
|
+
let lastArgs = null;
|
|
267
|
+
const debounced = (...args) => {
|
|
268
|
+
lastArgs = args;
|
|
269
|
+
if (timeout)
|
|
270
|
+
clearTimeout(timeout);
|
|
271
|
+
timeout = setTimeout(() => {
|
|
272
|
+
timeout = null;
|
|
273
|
+
fn(...args);
|
|
274
|
+
}, wait);
|
|
275
|
+
};
|
|
276
|
+
debounced.cancel = () => {
|
|
277
|
+
if (timeout) {
|
|
278
|
+
clearTimeout(timeout);
|
|
279
|
+
timeout = null;
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
debounced.flush = (...args) => {
|
|
283
|
+
debounced.cancel();
|
|
284
|
+
fn(...(args.length ? args : (lastArgs ?? [])));
|
|
285
|
+
};
|
|
286
|
+
return debounced;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* ## Throttle
|
|
290
|
+
*
|
|
291
|
+
* Guarantees that `fn` executes no more than once per `limit` ms window,
|
|
292
|
+
* regardless of how many calls are received.
|
|
293
|
+
*
|
|
294
|
+
* Unlike debounce, throttle executes `fn` **immediately** on the first call,
|
|
295
|
+
* then ignores subsequent calls until the window ends.
|
|
296
|
+
*
|
|
297
|
+
* Typical use cases: scroll handlers, mousemove, drag-and-drop, gamepads.
|
|
298
|
+
*
|
|
299
|
+
* The returned version exposes a `.cancel()` method to manually reset the
|
|
300
|
+
* throttle window.
|
|
301
|
+
*
|
|
302
|
+
* @param fn - Function to throttle.
|
|
303
|
+
* @param limit - Minimum duration between two executions (ms). @default 300
|
|
304
|
+
* @returns Throttled version of `fn` with `.cancel()` method.
|
|
305
|
+
*
|
|
306
|
+
* @example Scroll handler limited to 60fps (~16ms)
|
|
307
|
+
* ```ts
|
|
308
|
+
* const onScroll = utils.throttle(() => {
|
|
309
|
+
* updateScrollIndicator();
|
|
310
|
+
* }, 16);
|
|
311
|
+
*
|
|
312
|
+
* window.addEventListener("scroll", onScroll);
|
|
313
|
+
* ```
|
|
314
|
+
*/
|
|
315
|
+
throttle(fn, limit = 300) {
|
|
316
|
+
let inThrottle = false;
|
|
317
|
+
let timerId = null;
|
|
318
|
+
const throttled = (...args) => {
|
|
319
|
+
if (!inThrottle) {
|
|
320
|
+
fn(...args);
|
|
321
|
+
inThrottle = true;
|
|
322
|
+
timerId = setTimeout(() => {
|
|
323
|
+
inThrottle = false;
|
|
324
|
+
}, limit);
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
throttled.cancel = () => {
|
|
328
|
+
if (timerId) {
|
|
329
|
+
clearTimeout(timerId);
|
|
330
|
+
timerId = null;
|
|
331
|
+
}
|
|
332
|
+
inThrottle = false;
|
|
333
|
+
};
|
|
334
|
+
return throttled;
|
|
335
|
+
}
|
|
336
|
+
// ─── Measurement & Diagnostics ──────────────────────────────────────────
|
|
337
|
+
/**
|
|
338
|
+
* ## High-Precision Execution Time Measurement
|
|
339
|
+
*
|
|
340
|
+
* Wraps a synchronous or asynchronous function and returns its result
|
|
341
|
+
* along with its execution time in milliseconds (microsecond precision via `performance.now()`).
|
|
342
|
+
*
|
|
343
|
+
* @param fn - Function to measure (sync or async).
|
|
344
|
+
* @returns An object `{ result, durationMs }`.
|
|
345
|
+
*
|
|
346
|
+
* @example Measuring an API call
|
|
347
|
+
* ```ts
|
|
348
|
+
* const { result, durationMs } = await utils.measure(() =>
|
|
349
|
+
* fetch("/api/heavy").then(r => r.json())
|
|
350
|
+
* );
|
|
351
|
+
* console.log(`Response received in ${durationMs.toFixed(2)}ms:`, result);
|
|
352
|
+
* ```
|
|
353
|
+
*/
|
|
354
|
+
async measure(fn) {
|
|
355
|
+
const start = performance.now();
|
|
356
|
+
const result = await fn();
|
|
357
|
+
return { result, durationMs: performance.now() - start };
|
|
358
|
+
}
|
|
359
|
+
// ─── Intervals & Loops ───────────────────────────────────────────────────
|
|
360
|
+
/**
|
|
361
|
+
* ## High-Precision Drift-Corrected Interval
|
|
362
|
+
*
|
|
363
|
+
* Repeatedly executes `fn` with automatic compensation for accumulated
|
|
364
|
+
* clock drift. Unlike `setInterval`, this implementation adjusts each delay
|
|
365
|
+
* based on actual elapsed time.
|
|
366
|
+
*
|
|
367
|
+
* The current tick count is passed as a parameter to `fn`, enabling
|
|
368
|
+
* animations or progression counting.
|
|
369
|
+
*
|
|
370
|
+
* Execution stops cleanly when `signal` is aborted.
|
|
371
|
+
*
|
|
372
|
+
* @param fn - Callback called at each tick, receiving the tick index (0-indexed).
|
|
373
|
+
* @param ms - Target interval in milliseconds.
|
|
374
|
+
* @param signal - `AbortSignal` to stop the loop.
|
|
375
|
+
* @returns A promise that resolves when the signal is aborted.
|
|
376
|
+
*
|
|
377
|
+
* @example Counter update every second
|
|
378
|
+
* ```ts
|
|
379
|
+
* const controller = new AbortController();
|
|
380
|
+
*
|
|
381
|
+
* utils.repeat((tick) => {
|
|
382
|
+
* console.log(`Tick ${tick} — ${new Date().toLocaleTimeString()}`);
|
|
383
|
+
* }, 1000, controller.signal);
|
|
384
|
+
*
|
|
385
|
+
* // Stop after 5 seconds
|
|
386
|
+
* setTimeout(() => controller.abort(), 5000);
|
|
387
|
+
* ```
|
|
388
|
+
*/
|
|
389
|
+
async repeat(fn, ms, signal) {
|
|
390
|
+
let count = 0;
|
|
391
|
+
const startTime = Date.now();
|
|
392
|
+
while (!signal?.aborted) {
|
|
393
|
+
await fn(count++);
|
|
394
|
+
const nextExpected = startTime + count * ms;
|
|
395
|
+
const delay = nextExpected - Date.now();
|
|
396
|
+
if (delay > 0)
|
|
397
|
+
await this.sleep(delay, signal);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* ## Parallel Execution with Limited Concurrency
|
|
402
|
+
*
|
|
403
|
+
* Processes an array of values in parallel via `fn`, limiting the number
|
|
404
|
+
* of active promises simultaneously to `concurrency`. Results are returned
|
|
405
|
+
* in the same order as inputs.
|
|
406
|
+
*
|
|
407
|
+
* Ideal for scenarios where you want to avoid saturating a server or database
|
|
408
|
+
* with thousands of simultaneous requests.
|
|
409
|
+
*
|
|
410
|
+
* @param items - Array of items to process.
|
|
411
|
+
* @param fn - Asynchronous function applied to each element.
|
|
412
|
+
* @param concurrency - Maximum number of active parallel promises. @default 5
|
|
413
|
+
* @returns Array of results in the same order as `items`.
|
|
414
|
+
*
|
|
415
|
+
* @example Batch file import (max 3 at a time)
|
|
416
|
+
* ```ts
|
|
417
|
+
* const files = ["f1.csv", "f2.csv", "f3.csv", "f4.csv"];
|
|
418
|
+
* const results = await utils.pool(files, f => importFile(f), 3);
|
|
419
|
+
* ```
|
|
420
|
+
*/
|
|
421
|
+
async pool(items, fn, concurrency = 5) {
|
|
422
|
+
const results = new Array(items.length);
|
|
423
|
+
let index = 0;
|
|
424
|
+
const worker = async () => {
|
|
425
|
+
while (index < items.length) {
|
|
426
|
+
const i = index++;
|
|
427
|
+
results[i] = await fn(items[i], i);
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
const workers = Array.from({ length: Math.min(concurrency, items.length) }, worker);
|
|
431
|
+
await Promise.all(workers);
|
|
432
|
+
return results;
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* ## Race with Built-in Timeout
|
|
436
|
+
*
|
|
437
|
+
* Launches multiple promises in parallel and returns the first one to resolve.
|
|
438
|
+
* If none resolve within `timeoutMs`, an error is thrown.
|
|
439
|
+
*
|
|
440
|
+
* Similar to `Promise.race`, but with an integrated temporal safety net.
|
|
441
|
+
*
|
|
442
|
+
* @param fns - Array of functions returning promises.
|
|
443
|
+
* @param timeoutMs - Maximum delay in milliseconds. @default Infinity
|
|
444
|
+
* @returns Value of the first resolved promise.
|
|
445
|
+
* @throws `Error("Race timed out")` if timeout is reached.
|
|
446
|
+
*/
|
|
447
|
+
race(fns, timeoutMs = Infinity) {
|
|
448
|
+
const promises = fns.map((fn) => fn());
|
|
449
|
+
if (timeoutMs !== Infinity) {
|
|
450
|
+
promises.push(this.sleep(timeoutMs).then(() => {
|
|
451
|
+
throw new Error("Race timed out");
|
|
452
|
+
}));
|
|
453
|
+
}
|
|
454
|
+
return Promise.race(promises);
|
|
455
|
+
}
|
|
456
|
+
// ─── Advanced Patterns ───────────────────────────────────────────────────
|
|
457
|
+
/**
|
|
458
|
+
* ## Async Memoization with TTL
|
|
459
|
+
*
|
|
460
|
+
* Returns a memoized version of `fn`: results are cached for `ttlMs` milliseconds.
|
|
461
|
+
* After this delay, the next call triggers a fresh execution.
|
|
462
|
+
*
|
|
463
|
+
* If multiple identical calls arrive simultaneously (while the promise is pending),
|
|
464
|
+
* they share the same promise — avoiding "thundering herd" on cold caches.
|
|
465
|
+
*
|
|
466
|
+
* @param fn - Asynchronous function to memoize.
|
|
467
|
+
* @param ttlMs - Cache entry TTL (ms). `0` = no expiration.
|
|
468
|
+
* @param keyFn - Serialization function for arguments into cache keys.
|
|
469
|
+
* @default `JSON.stringify`
|
|
470
|
+
* @returns Memoized version of `fn` with `.clear()` method.
|
|
471
|
+
*/
|
|
472
|
+
memoize(fn, ttlMs = 0, keyFn = (...args) => JSON.stringify(args)) {
|
|
473
|
+
const cache = new Map();
|
|
474
|
+
const memoized = (...args) => {
|
|
475
|
+
const key = keyFn(...args);
|
|
476
|
+
const now = Date.now();
|
|
477
|
+
const entry = cache.get(key);
|
|
478
|
+
if (entry && (ttlMs === 0 || entry.expiresAt > now)) {
|
|
479
|
+
return entry.promise;
|
|
480
|
+
}
|
|
481
|
+
const promise = fn(...args).catch((err) => {
|
|
482
|
+
cache.delete(key);
|
|
483
|
+
throw err;
|
|
484
|
+
});
|
|
485
|
+
cache.set(key, {
|
|
486
|
+
promise,
|
|
487
|
+
expiresAt: ttlMs > 0 ? now + ttlMs : Infinity,
|
|
488
|
+
});
|
|
489
|
+
return promise;
|
|
490
|
+
};
|
|
491
|
+
memoized.clear = () => cache.clear();
|
|
492
|
+
return memoized;
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* ## Sequential Queue
|
|
496
|
+
*
|
|
497
|
+
* Guarantees that tasks are executed **one by one, in the order they were added**.
|
|
498
|
+
* Tasks submitted while another is pending are queued and executed sequentially.
|
|
499
|
+
*
|
|
500
|
+
* Unlike `pool(items, fn, 1)`, `queue` allows adding tasks dynamically over time.
|
|
501
|
+
*
|
|
502
|
+
* @returns An object `{ add, size }`:
|
|
503
|
+
* - `add(fn)` — Enqueues a task and returns a promise for its result.
|
|
504
|
+
* - `size` — Getter for the current number of pending tasks.
|
|
505
|
+
*
|
|
506
|
+
* @example Critical Database Mutation
|
|
507
|
+
* ```ts
|
|
508
|
+
* const db = utils.queue();
|
|
509
|
+
*
|
|
510
|
+
* async function transfer(from: string, to: string, amount: number) {
|
|
511
|
+
* return db.add(async () => {
|
|
512
|
+
* const balance = await getBalance(from);
|
|
513
|
+
* if (balance < amount) throw new Error("Insufficient funds");
|
|
514
|
+
* await debit(from, amount);
|
|
515
|
+
* await credit(to, amount);
|
|
516
|
+
* });
|
|
517
|
+
* }
|
|
518
|
+
* ```
|
|
519
|
+
*/
|
|
520
|
+
queue() {
|
|
521
|
+
let chain = Promise.resolve();
|
|
522
|
+
let pending = 0;
|
|
523
|
+
return {
|
|
524
|
+
add(fn) {
|
|
525
|
+
pending++;
|
|
526
|
+
const result = chain.then(fn).finally(() => {
|
|
527
|
+
pending--;
|
|
528
|
+
});
|
|
529
|
+
chain = result.catch(() => { });
|
|
530
|
+
return result;
|
|
531
|
+
},
|
|
532
|
+
get size() {
|
|
533
|
+
return pending;
|
|
534
|
+
},
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* ## Once — Guaranteed Single Execution
|
|
539
|
+
*
|
|
540
|
+
* Returns a version of `fn` that executes only **once**, regardless of how
|
|
541
|
+
* many calls are made. Subsequent calls receive the cached promise or value
|
|
542
|
+
* without re-executing `fn`.
|
|
543
|
+
*
|
|
544
|
+
* Particularly useful for expensive initializations (DB connections, config loading).
|
|
545
|
+
*
|
|
546
|
+
* @param fn - The function to execute exactly once.
|
|
547
|
+
* @returns A function that always returns the same resolved promise.
|
|
548
|
+
*/
|
|
549
|
+
once(fn) {
|
|
550
|
+
let promise = null;
|
|
551
|
+
return (...args) => {
|
|
552
|
+
if (!promise)
|
|
553
|
+
promise = fn(...args);
|
|
554
|
+
return promise;
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* ## Conditional Polling
|
|
559
|
+
*
|
|
560
|
+
* Repeatedly polls `fn` until `predicate` returns `true` or a signal is aborted.
|
|
561
|
+
*
|
|
562
|
+
* @param fn - Asynchronous function returning value to test.
|
|
563
|
+
* @param predicate - Success condition for the returned value.
|
|
564
|
+
* @param interval - Delay between attempts (ms). @default 1000
|
|
565
|
+
* @param signal - `AbortSignal` to stop polling.
|
|
566
|
+
* @returns The value for which `predicate` returned `true`.
|
|
567
|
+
* @throws `DOMException("AbortError")` if signal is aborted before success.
|
|
568
|
+
*/
|
|
569
|
+
async poll(fn, predicate, interval = 1000, signal) {
|
|
570
|
+
while (true) {
|
|
571
|
+
if (signal?.aborted)
|
|
572
|
+
throw new DOMException("Aborted", "AbortError");
|
|
573
|
+
const value = await fn();
|
|
574
|
+
if (predicate(value))
|
|
575
|
+
return value;
|
|
576
|
+
await this.sleep(interval, signal);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
exports.AsyncUtils = AsyncUtils;
|
|
582
|
+
//# sourceMappingURL=AsyncUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AsyncUtils.js","sources":["../../../../../src/xhsc/utils/AsyncUtils.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|