@actuallab/core 13.0.4 → 13.0.14
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/index.cjs +292 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +158 -2
- package/dist/index.d.ts +158 -2
- package/dist/index.js +278 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -171,8 +171,9 @@ declare class EventHandlerSet<T> {
|
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
/** Externally-resolvable promise — similar to .NET's TaskCompletionSource<T>. */
|
|
174
|
-
declare class PromiseSource<T> {
|
|
174
|
+
declare class PromiseSource<T> implements Promise<T> {
|
|
175
175
|
readonly promise: Promise<T>;
|
|
176
|
+
readonly [Symbol.toStringTag] = "Promise";
|
|
176
177
|
private _resolve;
|
|
177
178
|
private _reject;
|
|
178
179
|
private _isCompleted;
|
|
@@ -180,9 +181,139 @@ declare class PromiseSource<T> {
|
|
|
180
181
|
get isCompleted(): boolean;
|
|
181
182
|
resolve(value: T): boolean;
|
|
182
183
|
reject(reason?: unknown): boolean;
|
|
184
|
+
then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
|
|
185
|
+
catch<TResult = never>(onrejected?: ((reason: unknown) => TResult | PromiseLike<TResult>) | null): Promise<T | TResult>;
|
|
186
|
+
finally(onfinally?: (() => void) | null): Promise<T>;
|
|
183
187
|
}
|
|
184
188
|
declare const resolvedVoidPromise: Promise<void>;
|
|
185
189
|
|
|
190
|
+
/**
|
|
191
|
+
* A {@link PromiseSource} with a built-in timer that can reject (or run a
|
|
192
|
+
* caller-supplied callback) after a configurable delay. The timer is
|
|
193
|
+
* automatically cleared when the promise settles by other means, so callers
|
|
194
|
+
* don't have to remember to `clearTimeout()` on every success path.
|
|
195
|
+
*
|
|
196
|
+
* Typical use:
|
|
197
|
+
* ```ts
|
|
198
|
+
* const ps = new PromiseSourceWithTimeout<string>();
|
|
199
|
+
* ps.setTimeout(5_000); // rejects after 5s if still pending
|
|
200
|
+
* ps.setTimeout(5_000, () => ps.resolve('fallback')); // or run a custom callback
|
|
201
|
+
* ```
|
|
202
|
+
*
|
|
203
|
+
* Replaces the `PromiseSourceWithTimeout` previously kept in
|
|
204
|
+
* `ActualChat/src/nodejs/src/promises.ts`. Note: the Voxt original supported a
|
|
205
|
+
* "precise" (requestAnimationFrame-based) variant; we drop it here because no
|
|
206
|
+
* caller in ActualChat uses it outside `promises.ts` itself.
|
|
207
|
+
*/
|
|
208
|
+
declare class PromiseSourceWithTimeout<T> extends PromiseSource<T> {
|
|
209
|
+
private _timer;
|
|
210
|
+
hasTimeout(): boolean;
|
|
211
|
+
/**
|
|
212
|
+
* Install (or replace) a timeout. Pass `null` to remove without setting a
|
|
213
|
+
* new one. `callback` is invoked when the timer fires — if omitted, the
|
|
214
|
+
* promise is rejected with a generic "timed out" error.
|
|
215
|
+
*/
|
|
216
|
+
setTimeout(ms: number | null, callback?: () => unknown): void;
|
|
217
|
+
clearTimeout(): void;
|
|
218
|
+
resolve(value: T): boolean;
|
|
219
|
+
reject(reason?: unknown): boolean;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Pre-resolved promises for the three values most often returned as a
|
|
224
|
+
* "no-op" successful path: `void`, `true`, `false`. Returning these
|
|
225
|
+
* avoids allocating a fresh promise per call site.
|
|
226
|
+
*
|
|
227
|
+
* Idiomatic use:
|
|
228
|
+
* ```ts
|
|
229
|
+
* if (alreadyInitialized) return ResolvedPromise.Void;
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
declare const ResolvedPromise: {
|
|
233
|
+
readonly Void: Promise<void>;
|
|
234
|
+
readonly True: Promise<boolean>;
|
|
235
|
+
readonly False: Promise<boolean>;
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Sentinel returned/thrown by code that distinguishes "the operation took
|
|
240
|
+
* too long" from a generic rejection. Identity-comparable via the
|
|
241
|
+
* `instance` singleton — callers can branch on `result === TimedOut.instance`.
|
|
242
|
+
*/
|
|
243
|
+
declare class TimedOut {
|
|
244
|
+
static readonly instance: TimedOut;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/** Error type rejected by {@link withTimeout} when its budget elapses. */
|
|
248
|
+
declare class TimeoutError extends Error {
|
|
249
|
+
readonly name = "TimeoutError";
|
|
250
|
+
constructor(message?: string);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Race `promise` against a `ms`-millisecond timer. Resolves with the inner
|
|
254
|
+
* promise's value if it settles first; otherwise rejects with a
|
|
255
|
+
* {@link TimeoutError} carrying `message`. The timer is always cleared in
|
|
256
|
+
* a `finally`, so it cannot keep the event loop alive after the race ends.
|
|
257
|
+
*
|
|
258
|
+
* The inner promise's rejection (and the timeout's) are routed through
|
|
259
|
+
* `Promise.race`, so callers should `await` the result inside a `try/catch`
|
|
260
|
+
* exactly as they would for a single awaited promise. There's no
|
|
261
|
+
* "unhandled rejection" hazard from the timeout branch — the race always
|
|
262
|
+
* observes whichever promise wins, and the loser is allowed to settle
|
|
263
|
+
* silently into the void.
|
|
264
|
+
*/
|
|
265
|
+
declare function withTimeout<T>(promise: PromiseLike<T>, ms: number, message?: string): Promise<T>;
|
|
266
|
+
|
|
267
|
+
/** Resolves after `ms` milliseconds. */
|
|
268
|
+
declare function delayAsync(ms: number): Promise<void>;
|
|
269
|
+
/** Resolves with `value` after `ms` milliseconds. */
|
|
270
|
+
declare function delayAsyncWith<T>(ms: number, value: T): Promise<T>;
|
|
271
|
+
|
|
272
|
+
declare function abortPromise(signal: AbortSignal): Promise<never>;
|
|
273
|
+
|
|
274
|
+
/** A function wrapped by {@link throttle} or {@link debounce}. Calling it
|
|
275
|
+
* triggers the underlying function according to the scheduling rule;
|
|
276
|
+
* `reset()` discards any pending scheduled call. */
|
|
277
|
+
interface ResettableFunc<TArgs extends unknown[]> {
|
|
278
|
+
(...args: TArgs): void;
|
|
279
|
+
reset(): void;
|
|
280
|
+
}
|
|
281
|
+
/** Throttle modes:
|
|
282
|
+
* - `default` — fire the head call immediately, then drop further calls
|
|
283
|
+
* until the interval elapses; the *last* one is fired at interval end.
|
|
284
|
+
* - `skip` — fire the head call immediately, drop ALL calls during the
|
|
285
|
+
* interval (no tail call).
|
|
286
|
+
* - `delayHead` — delay even the head call by one interval; subsequent
|
|
287
|
+
* calls overwrite the pending one. */
|
|
288
|
+
type ThrottleMode = 'default' | 'skip' | 'delayHead';
|
|
289
|
+
/**
|
|
290
|
+
* Throttle calls to `func` so that it fires at most once every `intervalMs`.
|
|
291
|
+
* The returned function has a `.reset()` that discards any pending tail call
|
|
292
|
+
* and re-arms the head-call behavior on the next invocation.
|
|
293
|
+
*/
|
|
294
|
+
declare function throttle<TArgs extends unknown[]>(func: (...args: TArgs) => unknown, intervalMs: number, mode?: ThrottleMode): ResettableFunc<TArgs>;
|
|
295
|
+
/**
|
|
296
|
+
* Debounce calls to `func`: the function fires only after `intervalMs` have
|
|
297
|
+
* elapsed since the LAST call. Each new call resets the timer. `.reset()`
|
|
298
|
+
* discards any pending fire without invoking `func`.
|
|
299
|
+
*/
|
|
300
|
+
declare function debounce<TArgs extends unknown[]>(func: (...args: TArgs) => unknown, intervalMs: number): ResettableFunc<TArgs>;
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Wrap an async function so concurrent invocations are serialized into a
|
|
304
|
+
* single chain — each call awaits the previous one before running, and the
|
|
305
|
+
* caller receives the result of *its* own invocation.
|
|
306
|
+
*
|
|
307
|
+
* Useful for stateful async operations (DB writes, file I/O, network I/O
|
|
308
|
+
* that must not overlap) where the underlying contract is "one at a time."
|
|
309
|
+
*
|
|
310
|
+
* If `limit` is set and the queue is already that deep, the call short-
|
|
311
|
+
* circuits and returns the same promise the most recent queued call returned
|
|
312
|
+
* — i.e. it coalesces excess pressure onto the trailing in-flight call.
|
|
313
|
+
* Pass `null` (the default) for unbounded queueing.
|
|
314
|
+
*/
|
|
315
|
+
declare function serialize<TArgs extends unknown[], TResult>(func: (...args: TArgs) => PromiseLike<TResult> | TResult, limit?: number | null): (...args: TArgs) => Promise<TResult>;
|
|
316
|
+
|
|
186
317
|
/**
|
|
187
318
|
* A fixed-capacity circular buffer supporting efficient push/pull at both
|
|
188
319
|
* head and tail.
|
|
@@ -250,4 +381,29 @@ declare class RetryDelayer {
|
|
|
250
381
|
cancelDelays(): void;
|
|
251
382
|
}
|
|
252
383
|
|
|
253
|
-
|
|
384
|
+
/** A sequence of retry delays — given a 1-based try index (1 = first
|
|
385
|
+
* retry, i.e. AFTER the initial failure), returns the delay in ms before
|
|
386
|
+
* the next attempt. For more elaborate delay schemes, see
|
|
387
|
+
* {@link RetryDelaySeq.getDelay}. */
|
|
388
|
+
type RetryDelaySchedule = (tryIndex: number) => number;
|
|
389
|
+
/**
|
|
390
|
+
* Run `fn` up to `tryCount` times, awaiting a delay between attempts.
|
|
391
|
+
* The last error is rethrown if every attempt fails.
|
|
392
|
+
*
|
|
393
|
+
* `fn` is passed the 0-based attempt index and the last error (or
|
|
394
|
+
* `undefined` for the first attempt) — useful for adapting behavior per
|
|
395
|
+
* try (e.g. switching endpoints, escalating timeouts).
|
|
396
|
+
*/
|
|
397
|
+
declare function retry<TResult>(tryCount: number, fn: (tryIndex: number, lastError: unknown) => PromiseLike<TResult> | TResult, retryDelays?: RetryDelaySchedule): Promise<TResult>;
|
|
398
|
+
/**
|
|
399
|
+
* Run `fn` and swallow any throw, returning `onError(e)` if provided or
|
|
400
|
+
* `undefined` otherwise. The returned promise always settles successfully
|
|
401
|
+
* — the caller never has to `try/catch` it.
|
|
402
|
+
*
|
|
403
|
+
* Useful where a logical "best-effort" return is wanted but the runtime
|
|
404
|
+
* defaults — unhandled rejection warnings, exception escape past finally
|
|
405
|
+
* blocks — are not.
|
|
406
|
+
*/
|
|
407
|
+
declare function catchErrors<TResult>(fn: () => PromiseLike<TResult> | TResult, onError?: (e: unknown) => TResult): Promise<TResult | undefined>;
|
|
408
|
+
|
|
409
|
+
export { AsyncContext, AsyncContextKey, type AsyncDisposable, AsyncLock, type Disposable, DisposableBag, EventHandlerSet, type IResult, Log, LogLevel, LogLevelController, type LogRef, type LogScopeFns, PromiseSource, PromiseSourceWithTimeout, type ResettableFunc, ResolvedPromise, Result, type RetryDelay, RetryDelayLimitExceeded, RetryDelayNone, type RetryDelaySchedule, RetryDelaySeq, RetryDelayer, RingBuffer, type ThrottleMode, TimedOut, TimeoutError, abortPromise, abortSignalKey, catchErrors, createLogProvider, debounce, delayAsync, delayAsyncWith, errorResult, initLogging, initWorkerLogging, resolvedVoidPromise, result, resultFrom, resultFromAsync, retry, serialize, throttle, withTimeout };
|
package/dist/index.js
CHANGED
|
@@ -593,6 +593,7 @@ var AsyncLock = class {
|
|
|
593
593
|
// src/promise-source.ts
|
|
594
594
|
var PromiseSource = class {
|
|
595
595
|
promise;
|
|
596
|
+
[Symbol.toStringTag] = "Promise";
|
|
596
597
|
_resolve;
|
|
597
598
|
_reject;
|
|
598
599
|
_isCompleted = false;
|
|
@@ -617,6 +618,15 @@ var PromiseSource = class {
|
|
|
617
618
|
this._reject(reason);
|
|
618
619
|
return true;
|
|
619
620
|
}
|
|
621
|
+
then(onfulfilled, onrejected) {
|
|
622
|
+
return this.promise.then(onfulfilled, onrejected);
|
|
623
|
+
}
|
|
624
|
+
catch(onrejected) {
|
|
625
|
+
return this.promise.catch(onrejected);
|
|
626
|
+
}
|
|
627
|
+
finally(onfinally) {
|
|
628
|
+
return this.promise.finally(onfinally);
|
|
629
|
+
}
|
|
620
630
|
};
|
|
621
631
|
var resolvedVoidPromise = Promise.resolve();
|
|
622
632
|
|
|
@@ -645,10 +655,235 @@ var EventHandlerSet = class {
|
|
|
645
655
|
ps.resolve(arg);
|
|
646
656
|
};
|
|
647
657
|
this._handlers.add(handler);
|
|
648
|
-
return ps
|
|
658
|
+
return ps;
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
// src/withTimeout.ts
|
|
663
|
+
var TimeoutError = class extends Error {
|
|
664
|
+
name = "TimeoutError";
|
|
665
|
+
constructor(message = "Operation timed out") {
|
|
666
|
+
super(message);
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
async function withTimeout(promise, ms, message) {
|
|
670
|
+
let timer;
|
|
671
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
672
|
+
timer = setTimeout(
|
|
673
|
+
() => reject(new TimeoutError(message ?? `Operation timed out after ${ms}ms`)),
|
|
674
|
+
ms
|
|
675
|
+
);
|
|
676
|
+
});
|
|
677
|
+
timeoutPromise.catch(() => {
|
|
678
|
+
});
|
|
679
|
+
try {
|
|
680
|
+
return await Promise.race([promise, timeoutPromise]);
|
|
681
|
+
} finally {
|
|
682
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// src/promise-source-with-timeout.ts
|
|
687
|
+
var PromiseSourceWithTimeout = class extends PromiseSource {
|
|
688
|
+
_timer;
|
|
689
|
+
hasTimeout() {
|
|
690
|
+
return this._timer !== void 0;
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Install (or replace) a timeout. Pass `null` to remove without setting a
|
|
694
|
+
* new one. `callback` is invoked when the timer fires — if omitted, the
|
|
695
|
+
* promise is rejected with a generic "timed out" error.
|
|
696
|
+
*/
|
|
697
|
+
setTimeout(ms, callback) {
|
|
698
|
+
this.clearTimeout();
|
|
699
|
+
if (ms === null || this.isCompleted) return;
|
|
700
|
+
this._timer = setTimeout(() => {
|
|
701
|
+
this._timer = void 0;
|
|
702
|
+
if (callback) callback();
|
|
703
|
+
else this.reject(new TimeoutError(`The promise has timed out after ${ms}ms.`));
|
|
704
|
+
}, ms);
|
|
705
|
+
}
|
|
706
|
+
clearTimeout() {
|
|
707
|
+
if (this._timer === void 0) return;
|
|
708
|
+
clearTimeout(this._timer);
|
|
709
|
+
this._timer = void 0;
|
|
710
|
+
}
|
|
711
|
+
resolve(value) {
|
|
712
|
+
const didSettle = super.resolve(value);
|
|
713
|
+
if (didSettle) this.clearTimeout();
|
|
714
|
+
return didSettle;
|
|
715
|
+
}
|
|
716
|
+
reject(reason) {
|
|
717
|
+
const didSettle = super.reject(reason);
|
|
718
|
+
if (didSettle) this.clearTimeout();
|
|
719
|
+
return didSettle;
|
|
649
720
|
}
|
|
650
721
|
};
|
|
651
722
|
|
|
723
|
+
// src/resolved-promise.ts
|
|
724
|
+
var ResolvedPromise = {
|
|
725
|
+
Void: Promise.resolve(),
|
|
726
|
+
True: Promise.resolve(true),
|
|
727
|
+
False: Promise.resolve(false)
|
|
728
|
+
};
|
|
729
|
+
|
|
730
|
+
// src/timed-out.ts
|
|
731
|
+
var TimedOut = class _TimedOut {
|
|
732
|
+
static instance = new _TimedOut();
|
|
733
|
+
};
|
|
734
|
+
|
|
735
|
+
// src/delay.ts
|
|
736
|
+
function delayAsync(ms) {
|
|
737
|
+
return new Promise((resolve) => {
|
|
738
|
+
setTimeout(resolve, ms);
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
function delayAsyncWith(ms, value) {
|
|
742
|
+
return new Promise((resolve) => {
|
|
743
|
+
setTimeout(() => resolve(value), ms);
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// src/abort-promise.ts
|
|
748
|
+
var abortPromiseCache = /* @__PURE__ */ new WeakMap();
|
|
749
|
+
function abortPromise(signal) {
|
|
750
|
+
if (signal.aborted) return Promise.reject(signal.reason);
|
|
751
|
+
let cached = abortPromiseCache.get(signal);
|
|
752
|
+
if (!cached) {
|
|
753
|
+
cached = new Promise((_, reject) => {
|
|
754
|
+
signal.addEventListener("abort", () => reject(signal.reason), { once: true });
|
|
755
|
+
});
|
|
756
|
+
cached.catch(() => {
|
|
757
|
+
});
|
|
758
|
+
abortPromiseCache.set(signal, cached);
|
|
759
|
+
}
|
|
760
|
+
return cached;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// src/internal-logging.ts
|
|
764
|
+
var scopeDefaults = {
|
|
765
|
+
retry: 3 /* Warn */,
|
|
766
|
+
throttle: 3 /* Warn */
|
|
767
|
+
};
|
|
768
|
+
var getLogs = createLogProvider("core.", scopeDefaults);
|
|
769
|
+
|
|
770
|
+
// src/throttle.ts
|
|
771
|
+
var { errorLog } = getLogs("throttle");
|
|
772
|
+
var Call = class {
|
|
773
|
+
constructor(func, self, parameters) {
|
|
774
|
+
this.func = func;
|
|
775
|
+
this.self = self;
|
|
776
|
+
this.parameters = parameters;
|
|
777
|
+
}
|
|
778
|
+
invoke() {
|
|
779
|
+
return this.func.apply(this.self, this.parameters);
|
|
780
|
+
}
|
|
781
|
+
invokeSilently() {
|
|
782
|
+
try {
|
|
783
|
+
return this.invoke();
|
|
784
|
+
} catch (error) {
|
|
785
|
+
errorLog?.log("Call.invokeSilently: unhandled error:", error);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
};
|
|
789
|
+
function throttle(func, intervalMs, mode = "default") {
|
|
790
|
+
let lastCall = null;
|
|
791
|
+
let nextFireTime = 0;
|
|
792
|
+
let timeoutHandle = null;
|
|
793
|
+
const reset2 = () => {
|
|
794
|
+
if (timeoutHandle !== null) clearTimeout(timeoutHandle);
|
|
795
|
+
timeoutHandle = null;
|
|
796
|
+
lastCall = null;
|
|
797
|
+
nextFireTime = 0;
|
|
798
|
+
};
|
|
799
|
+
const fire = () => {
|
|
800
|
+
if (timeoutHandle !== null) clearTimeout(timeoutHandle);
|
|
801
|
+
if (lastCall !== null) {
|
|
802
|
+
const call = lastCall;
|
|
803
|
+
lastCall = null;
|
|
804
|
+
nextFireTime = Date.now() + intervalMs;
|
|
805
|
+
timeoutHandle = setTimeout(fire, intervalMs);
|
|
806
|
+
call.invokeSilently();
|
|
807
|
+
} else {
|
|
808
|
+
timeoutHandle = null;
|
|
809
|
+
nextFireTime = 0;
|
|
810
|
+
}
|
|
811
|
+
};
|
|
812
|
+
const wrapped = function(...args) {
|
|
813
|
+
const call = new Call(func, this, args);
|
|
814
|
+
const fireDelay = nextFireTime - Date.now();
|
|
815
|
+
if (timeoutHandle !== null && fireDelay <= 0) {
|
|
816
|
+
fire();
|
|
817
|
+
}
|
|
818
|
+
if (timeoutHandle === null) {
|
|
819
|
+
nextFireTime = Date.now() + intervalMs;
|
|
820
|
+
timeoutHandle = setTimeout(fire, intervalMs);
|
|
821
|
+
if (mode === "delayHead") {
|
|
822
|
+
lastCall = call;
|
|
823
|
+
} else {
|
|
824
|
+
call.invokeSilently();
|
|
825
|
+
}
|
|
826
|
+
} else if (mode !== "skip") {
|
|
827
|
+
lastCall = call;
|
|
828
|
+
}
|
|
829
|
+
};
|
|
830
|
+
wrapped.reset = reset2;
|
|
831
|
+
return wrapped;
|
|
832
|
+
}
|
|
833
|
+
function debounce(func, intervalMs) {
|
|
834
|
+
let lastCall = null;
|
|
835
|
+
let nextFireTime = 0;
|
|
836
|
+
let timeoutHandle = null;
|
|
837
|
+
const reset2 = () => {
|
|
838
|
+
timeoutHandle = null;
|
|
839
|
+
lastCall = null;
|
|
840
|
+
nextFireTime = 0;
|
|
841
|
+
};
|
|
842
|
+
const fire = () => {
|
|
843
|
+
if (timeoutHandle !== null) clearTimeout(timeoutHandle);
|
|
844
|
+
timeoutHandle = null;
|
|
845
|
+
const fireDelay = nextFireTime - Date.now();
|
|
846
|
+
if (fireDelay <= 0) {
|
|
847
|
+
nextFireTime = 0;
|
|
848
|
+
if (lastCall !== null) {
|
|
849
|
+
const call = lastCall;
|
|
850
|
+
lastCall = null;
|
|
851
|
+
call.invokeSilently();
|
|
852
|
+
}
|
|
853
|
+
} else {
|
|
854
|
+
timeoutHandle = setTimeout(fire, fireDelay);
|
|
855
|
+
}
|
|
856
|
+
};
|
|
857
|
+
const wrapped = function(...args) {
|
|
858
|
+
lastCall = new Call(func, this, args);
|
|
859
|
+
nextFireTime = Date.now() + intervalMs;
|
|
860
|
+
timeoutHandle ??= setTimeout(fire, intervalMs);
|
|
861
|
+
};
|
|
862
|
+
wrapped.reset = reset2;
|
|
863
|
+
return wrapped;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// src/serialize.ts
|
|
867
|
+
function serialize(func, limit = null) {
|
|
868
|
+
let lastCall = Promise.resolve(null);
|
|
869
|
+
let queueSize = 0;
|
|
870
|
+
return function(...args) {
|
|
871
|
+
if (limit !== null && queueSize >= limit) return lastCall;
|
|
872
|
+
queueSize++;
|
|
873
|
+
const prevCall = lastCall;
|
|
874
|
+
const invoke = () => func.apply(this, args);
|
|
875
|
+
return lastCall = (async () => {
|
|
876
|
+
try {
|
|
877
|
+
await prevCall.catch(() => {
|
|
878
|
+
});
|
|
879
|
+
return await invoke();
|
|
880
|
+
} finally {
|
|
881
|
+
queueSize--;
|
|
882
|
+
}
|
|
883
|
+
})();
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
|
|
652
887
|
// src/ring-buffer.ts
|
|
653
888
|
var RingBuffer = class {
|
|
654
889
|
_buffer;
|
|
@@ -839,6 +1074,34 @@ var RetryDelayer = class {
|
|
|
839
1074
|
this.cancelDelaysChanged.trigger();
|
|
840
1075
|
}
|
|
841
1076
|
};
|
|
1077
|
+
|
|
1078
|
+
// src/retry.ts
|
|
1079
|
+
var { warnLog } = getLogs("retry");
|
|
1080
|
+
var defaultRetryDelays = () => 50;
|
|
1081
|
+
async function retry(tryCount, fn, retryDelays = defaultRetryDelays) {
|
|
1082
|
+
if (tryCount <= 0)
|
|
1083
|
+
throw new Error("retry: tryCount must be positive.");
|
|
1084
|
+
let lastError;
|
|
1085
|
+
for (let tryIndex = 0; ; ) {
|
|
1086
|
+
if (tryIndex >= tryCount) throw lastError;
|
|
1087
|
+
try {
|
|
1088
|
+
return await fn(tryIndex, lastError);
|
|
1089
|
+
} catch (e) {
|
|
1090
|
+
lastError = e;
|
|
1091
|
+
}
|
|
1092
|
+
++tryIndex;
|
|
1093
|
+
if (tryIndex >= tryCount) throw lastError;
|
|
1094
|
+
warnLog?.log(`retry(${tryIndex}/${tryCount}): error:`, lastError);
|
|
1095
|
+
await delayAsync(retryDelays(tryIndex));
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
async function catchErrors(fn, onError) {
|
|
1099
|
+
try {
|
|
1100
|
+
return await fn();
|
|
1101
|
+
} catch (e) {
|
|
1102
|
+
return onError ? onError(e) : void 0;
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
842
1105
|
export {
|
|
843
1106
|
AsyncContext,
|
|
844
1107
|
AsyncContextKey,
|
|
@@ -849,20 +1112,33 @@ export {
|
|
|
849
1112
|
LogLevel,
|
|
850
1113
|
LogLevelController,
|
|
851
1114
|
PromiseSource,
|
|
1115
|
+
PromiseSourceWithTimeout,
|
|
1116
|
+
ResolvedPromise,
|
|
852
1117
|
Result,
|
|
853
1118
|
RetryDelayLimitExceeded,
|
|
854
1119
|
RetryDelayNone,
|
|
855
1120
|
RetryDelaySeq,
|
|
856
1121
|
RetryDelayer,
|
|
857
1122
|
RingBuffer,
|
|
1123
|
+
TimedOut,
|
|
1124
|
+
TimeoutError,
|
|
1125
|
+
abortPromise,
|
|
858
1126
|
abortSignalKey,
|
|
1127
|
+
catchErrors,
|
|
859
1128
|
createLogProvider,
|
|
1129
|
+
debounce,
|
|
1130
|
+
delayAsync,
|
|
1131
|
+
delayAsyncWith,
|
|
860
1132
|
errorResult,
|
|
861
1133
|
initLogging,
|
|
862
1134
|
initWorkerLogging,
|
|
863
1135
|
resolvedVoidPromise,
|
|
864
1136
|
result,
|
|
865
1137
|
resultFrom,
|
|
866
|
-
resultFromAsync
|
|
1138
|
+
resultFromAsync,
|
|
1139
|
+
retry,
|
|
1140
|
+
serialize,
|
|
1141
|
+
throttle,
|
|
1142
|
+
withTimeout
|
|
867
1143
|
};
|
|
868
1144
|
//# sourceMappingURL=index.js.map
|