@actuallab/core 13.0.25 → 13.0.167
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 +223 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +61 -9
- package/dist/index.d.ts +61 -9
- package/dist/index.js +217 -46
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -108,10 +108,11 @@ declare class Result<T> implements IResult<T> {
|
|
|
108
108
|
readonly hasError: boolean;
|
|
109
109
|
private readonly _value;
|
|
110
110
|
private readonly _error;
|
|
111
|
-
constructor(value: T | undefined, error?: unknown);
|
|
111
|
+
constructor(value: T | undefined, error?: unknown, hasError?: boolean);
|
|
112
112
|
get value(): T;
|
|
113
113
|
get error(): unknown;
|
|
114
114
|
get valueOrUndefined(): T | undefined;
|
|
115
|
+
equals(other: Result<T>, valueComparer?: (a: T, b: T) => boolean): boolean;
|
|
115
116
|
static ok<T>(value: T): Result<T>;
|
|
116
117
|
static error<T>(error: unknown): Result<T>;
|
|
117
118
|
}
|
|
@@ -129,12 +130,16 @@ declare class AsyncContextKey<T> {
|
|
|
129
130
|
/** General-purpose typed context container — named for forward-compatibility with TC39 AsyncContext proposal. */
|
|
130
131
|
declare const abortSignalKey: AsyncContextKey<AbortSignal | undefined>;
|
|
131
132
|
declare class AsyncContext {
|
|
132
|
-
static current: AsyncContext | undefined;
|
|
133
133
|
/** Immutable empty singleton — avoids allocating new AsyncContext(). */
|
|
134
134
|
static readonly empty: AsyncContext;
|
|
135
|
+
private static _current;
|
|
135
136
|
private static _defaults;
|
|
136
137
|
private _values;
|
|
137
138
|
constructor(values?: Map<symbol, unknown>);
|
|
139
|
+
static get current(): AsyncContext | undefined;
|
|
140
|
+
static set current(value: AsyncContext | undefined);
|
|
141
|
+
/** True when AsyncContext.current flows across awaits (Node AsyncLocalStorage is active). */
|
|
142
|
+
static get isAsyncLocalStorageActive(): boolean;
|
|
138
143
|
get<T>(key: AsyncContextKey<T>): T;
|
|
139
144
|
with<T>(key: AsyncContextKey<T>, value: T): AsyncContext;
|
|
140
145
|
activate(): Disposable;
|
|
@@ -147,6 +152,7 @@ declare class AsyncContext {
|
|
|
147
152
|
static fromArgs(args: unknown[]): AsyncContext | undefined;
|
|
148
153
|
static setDefault<T>(key: AsyncContextKey<T>, value: T): void;
|
|
149
154
|
static getOrCreate(): AsyncContext;
|
|
155
|
+
static _setAsyncLocalStorageActive(active: boolean): void;
|
|
150
156
|
}
|
|
151
157
|
|
|
152
158
|
/** Promise-based mutual exclusion lock for serializing async operations. */
|
|
@@ -154,22 +160,32 @@ declare class AsyncLock {
|
|
|
154
160
|
private _queue;
|
|
155
161
|
private _locked;
|
|
156
162
|
get isLocked(): boolean;
|
|
157
|
-
acquire(): Promise<void>;
|
|
163
|
+
acquire(signal?: AbortSignal): Promise<void>;
|
|
158
164
|
release(): void;
|
|
159
|
-
run<T>(fn: () => T | Promise<T
|
|
165
|
+
run<T>(fn: () => T | Promise<T>, signal?: AbortSignal): Promise<T>;
|
|
160
166
|
}
|
|
161
167
|
|
|
162
|
-
/**
|
|
168
|
+
/**
|
|
169
|
+
* Typed pub/sub event handler set — similar to .NET's EventHandler<T> multicast delegate.
|
|
170
|
+
* Deviation: Set-backed, so adding the same handler twice fires it once (a C# delegate fires it twice).
|
|
171
|
+
*/
|
|
163
172
|
declare class EventHandlerSet<T> {
|
|
164
173
|
private _handlers;
|
|
165
174
|
get count(): number;
|
|
166
175
|
add(handler: (arg: T) => void): void;
|
|
167
176
|
remove(handler: (arg: T) => void): void;
|
|
168
177
|
trigger(arg: T): void;
|
|
178
|
+
triggerSafe(arg: T, onError: (error: unknown) => void): void;
|
|
169
179
|
clear(): void;
|
|
170
180
|
whenNext(): Promise<T>;
|
|
171
181
|
}
|
|
172
182
|
|
|
183
|
+
declare class AsyncSignal {
|
|
184
|
+
private source;
|
|
185
|
+
wait(): Promise<void>;
|
|
186
|
+
notify(): void;
|
|
187
|
+
}
|
|
188
|
+
|
|
173
189
|
/** Externally-resolvable promise — similar to .NET's TaskCompletionSource<T>. */
|
|
174
190
|
declare class PromiseSource<T> implements Promise<T> {
|
|
175
191
|
readonly promise: Promise<T>;
|
|
@@ -264,13 +280,43 @@ declare class TimeoutError extends Error {
|
|
|
264
280
|
*/
|
|
265
281
|
declare function withTimeout<T>(promise: PromiseLike<T>, ms: number, message?: string): Promise<T>;
|
|
266
282
|
|
|
267
|
-
/** Resolves after `ms` milliseconds.
|
|
268
|
-
|
|
283
|
+
/** Resolves after `ms` milliseconds, or rejects with `signal.reason` if
|
|
284
|
+
* `signal` aborts first (including when it is already aborted). */
|
|
285
|
+
declare function delayAsync(ms: number, signal?: AbortSignal): Promise<void>;
|
|
269
286
|
/** Resolves with `value` after `ms` milliseconds. */
|
|
270
287
|
declare function delayAsyncWith<T>(ms: number, value: T): Promise<T>;
|
|
271
288
|
|
|
272
289
|
declare function abortPromise(signal: AbortSignal): Promise<never>;
|
|
273
290
|
|
|
291
|
+
/**
|
|
292
|
+
* True when `error` is a cancellation/abort signal rather than a real failure.
|
|
293
|
+
*
|
|
294
|
+
* Recognizes the wave-1 cancellation convention: `delayAsync`, `AsyncLock`, and
|
|
295
|
+
* `abortPromise` all reject with `signal.reason`, which — per the Web spec —
|
|
296
|
+
* defaults to a `DOMException` named `'AbortError'` (and is whatever value was
|
|
297
|
+
* passed to `abort(reason)` otherwise). A plain `Error` named `'AbortError'`
|
|
298
|
+
* (e.g. from a fetch abort) is matched too.
|
|
299
|
+
*/
|
|
300
|
+
declare function isCancellation(error: unknown): boolean;
|
|
301
|
+
/**
|
|
302
|
+
* Builds a cancellation-shaped error recognized by {@link isCancellation}.
|
|
303
|
+
* Named `'AbortError'` so it rides the same never-cache path as an aborted
|
|
304
|
+
* `fetch`: the compute kernel invalidates such computeds instead of caching
|
|
305
|
+
* the error (K6), and RPC callers treat it as a retryable cancellation.
|
|
306
|
+
*/
|
|
307
|
+
declare function cancellationError(message?: string): Error;
|
|
308
|
+
|
|
309
|
+
type AbortOutcome = 'resolve' | 'reject';
|
|
310
|
+
/**
|
|
311
|
+
* Builds a Promise that settles when the first completion source fires, then runs
|
|
312
|
+
* every registered cleanup exactly once — on completion or when `abortSignal`
|
|
313
|
+
* aborts. `wire` installs the sources (timers, event handlers), calling
|
|
314
|
+
* `complete()` to resolve and `addCleanup(fn)` to register teardown; every
|
|
315
|
+
* cleanup, plus the abort listener, is removed on every exit path. `onAbort`
|
|
316
|
+
* selects whether an abort resolves or rejects (with `signal.reason`).
|
|
317
|
+
*/
|
|
318
|
+
declare function awaitWithCleanup(abortSignal: AbortSignal | undefined, onAbort: AbortOutcome, wire: (complete: () => void, addCleanup: (cleanup: () => void) => void) => void): Promise<void>;
|
|
319
|
+
|
|
274
320
|
/** A function wrapped by {@link throttle} or {@link debounce}. Calling it
|
|
275
321
|
* triggers the underlying function according to the scheduling rule;
|
|
276
322
|
* `reset()` discards any pending scheduled call. */
|
|
@@ -393,8 +439,11 @@ type RetryDelaySchedule = (tryIndex: number) => number;
|
|
|
393
439
|
* `fn` is passed the 0-based attempt index and the last error (or
|
|
394
440
|
* `undefined` for the first attempt) — useful for adapting behavior per
|
|
395
441
|
* try (e.g. switching endpoints, escalating timeouts).
|
|
442
|
+
*
|
|
443
|
+
* Aborting `signal` during an inter-attempt delay rejects with
|
|
444
|
+
* `signal.reason` instead of waiting the delay out.
|
|
396
445
|
*/
|
|
397
|
-
declare function retry<TResult>(tryCount: number, fn: (tryIndex: number, lastError: unknown) => PromiseLike<TResult> | TResult, retryDelays?: RetryDelaySchedule): Promise<TResult>;
|
|
446
|
+
declare function retry<TResult>(tryCount: number, fn: (tryIndex: number, lastError: unknown) => PromiseLike<TResult> | TResult, retryDelays?: RetryDelaySchedule, signal?: AbortSignal): Promise<TResult>;
|
|
398
447
|
/**
|
|
399
448
|
* Run `fn` and swallow any throw, returning `onError(e)` if provided or
|
|
400
449
|
* `undefined` otherwise. The returned promise always settles successfully
|
|
@@ -406,4 +455,7 @@ declare function retry<TResult>(tryCount: number, fn: (tryIndex: number, lastErr
|
|
|
406
455
|
*/
|
|
407
456
|
declare function catchErrors<TResult>(fn: () => PromiseLike<TResult> | TResult, onError?: (e: unknown) => TResult): Promise<TResult | undefined>;
|
|
408
457
|
|
|
409
|
-
|
|
458
|
+
declare function ownMetadata<T extends object>(metadata: object, key: symbol): T;
|
|
459
|
+
declare function resolveArgCount(fn: (...args: never[]) => unknown, explicit: number | undefined, methodName: string): number;
|
|
460
|
+
|
|
461
|
+
export { type AbortOutcome, AsyncContext, AsyncContextKey, type AsyncDisposable, AsyncLock, AsyncSignal, 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, awaitWithCleanup, cancellationError, catchErrors, createLogProvider, debounce, delayAsync, delayAsyncWith, errorResult, initLogging, initWorkerLogging, isCancellation, ownMetadata, resolveArgCount, resolvedVoidPromise, result, resultFrom, resultFromAsync, retry, serialize, throttle, withTimeout };
|
package/dist/index.js
CHANGED
|
@@ -439,9 +439,9 @@ var Result = class _Result {
|
|
|
439
439
|
hasError;
|
|
440
440
|
_value;
|
|
441
441
|
_error;
|
|
442
|
-
constructor(value, error) {
|
|
443
|
-
this.
|
|
444
|
-
this.
|
|
442
|
+
constructor(value, error, hasError = error !== void 0) {
|
|
443
|
+
this.hasError = hasError;
|
|
444
|
+
this.hasValue = !hasError;
|
|
445
445
|
this._value = value;
|
|
446
446
|
this._error = error;
|
|
447
447
|
}
|
|
@@ -455,11 +455,17 @@ var Result = class _Result {
|
|
|
455
455
|
get valueOrUndefined() {
|
|
456
456
|
return this.hasValue ? this._value : void 0;
|
|
457
457
|
}
|
|
458
|
+
// Values compared with valueComparer (Object.is by default); errors by reference — mirrors C# Result<T>.Equals.
|
|
459
|
+
equals(other, valueComparer = Object.is) {
|
|
460
|
+
if (this.hasError !== other.hasError || this._error !== other._error)
|
|
461
|
+
return false;
|
|
462
|
+
return valueComparer(this._value, other._value);
|
|
463
|
+
}
|
|
458
464
|
static ok(value) {
|
|
459
|
-
return new _Result(value);
|
|
465
|
+
return new _Result(value, void 0, false);
|
|
460
466
|
}
|
|
461
467
|
static error(error) {
|
|
462
|
-
return new _Result(void 0, error);
|
|
468
|
+
return new _Result(void 0, error ?? new Error("Unspecified error"), true);
|
|
463
469
|
}
|
|
464
470
|
};
|
|
465
471
|
function result(value, error) {
|
|
@@ -496,15 +502,35 @@ var abortSignalKey = new AsyncContextKey(
|
|
|
496
502
|
"AbortSignal",
|
|
497
503
|
void 0
|
|
498
504
|
);
|
|
505
|
+
var _alsImpl = detectAsyncLocalStorage();
|
|
506
|
+
var _als = _alsImpl;
|
|
507
|
+
function detectAsyncLocalStorage() {
|
|
508
|
+
const proc = globalThis.process;
|
|
509
|
+
const asyncHooks = proc?.getBuiltinModule?.("node:async_hooks");
|
|
510
|
+
return asyncHooks === void 0 ? void 0 : new asyncHooks.AsyncLocalStorage();
|
|
511
|
+
}
|
|
499
512
|
var AsyncContext = class _AsyncContext {
|
|
500
|
-
static current = void 0;
|
|
501
513
|
/** Immutable empty singleton — avoids allocating new AsyncContext(). */
|
|
502
514
|
static empty = new _AsyncContext();
|
|
515
|
+
static _current = void 0;
|
|
503
516
|
static _defaults = /* @__PURE__ */ new Map();
|
|
504
517
|
_values;
|
|
505
518
|
constructor(values) {
|
|
506
519
|
this._values = values ?? /* @__PURE__ */ new Map();
|
|
507
520
|
}
|
|
521
|
+
static get current() {
|
|
522
|
+
return _als?.getStore() ?? _AsyncContext._current;
|
|
523
|
+
}
|
|
524
|
+
static set current(value) {
|
|
525
|
+
if (_als !== void 0)
|
|
526
|
+
_als.enterWith(value);
|
|
527
|
+
else
|
|
528
|
+
_AsyncContext._current = value;
|
|
529
|
+
}
|
|
530
|
+
/** True when AsyncContext.current flows across awaits (Node AsyncLocalStorage is active). */
|
|
531
|
+
static get isAsyncLocalStorageActive() {
|
|
532
|
+
return _als !== void 0;
|
|
533
|
+
}
|
|
508
534
|
get(key) {
|
|
509
535
|
if (this._values.has(key.id)) return this._values.get(key.id);
|
|
510
536
|
if (_AsyncContext._defaults.has(key.id))
|
|
@@ -518,20 +544,27 @@ var AsyncContext = class _AsyncContext {
|
|
|
518
544
|
}
|
|
519
545
|
activate() {
|
|
520
546
|
const prev = _AsyncContext.current;
|
|
521
|
-
|
|
547
|
+
const als = _als;
|
|
548
|
+
if (als !== void 0) {
|
|
549
|
+
als.enterWith(this);
|
|
550
|
+
return { dispose: () => als.enterWith(prev) };
|
|
551
|
+
}
|
|
552
|
+
_AsyncContext._current = this;
|
|
522
553
|
return {
|
|
523
554
|
dispose: () => {
|
|
524
|
-
_AsyncContext.
|
|
555
|
+
_AsyncContext._current = prev;
|
|
525
556
|
}
|
|
526
557
|
};
|
|
527
558
|
}
|
|
528
559
|
run(fn) {
|
|
529
|
-
|
|
530
|
-
|
|
560
|
+
if (_als !== void 0)
|
|
561
|
+
return _als.run(this, fn);
|
|
562
|
+
const prev = _AsyncContext._current;
|
|
563
|
+
_AsyncContext._current = this;
|
|
531
564
|
try {
|
|
532
565
|
return fn();
|
|
533
566
|
} finally {
|
|
534
|
-
_AsyncContext.
|
|
567
|
+
_AsyncContext._current = prev;
|
|
535
568
|
}
|
|
536
569
|
}
|
|
537
570
|
/** Strip THIS exact instance from args if it's the last element (reference equality). */
|
|
@@ -553,6 +586,12 @@ var AsyncContext = class _AsyncContext {
|
|
|
553
586
|
static getOrCreate() {
|
|
554
587
|
return _AsyncContext.current ?? _AsyncContext.empty;
|
|
555
588
|
}
|
|
589
|
+
// Toggles AsyncLocalStorage backing — for tests that exercise the browser fallback path.
|
|
590
|
+
// Clears the fallback static field so no stale context bleeds across the toggle.
|
|
591
|
+
static _setAsyncLocalStorageActive(active) {
|
|
592
|
+
_als = active ? _alsImpl : void 0;
|
|
593
|
+
_AsyncContext._current = void 0;
|
|
594
|
+
}
|
|
556
595
|
};
|
|
557
596
|
|
|
558
597
|
// src/async-lock.ts
|
|
@@ -562,13 +601,26 @@ var AsyncLock = class {
|
|
|
562
601
|
get isLocked() {
|
|
563
602
|
return this._locked;
|
|
564
603
|
}
|
|
565
|
-
async acquire() {
|
|
604
|
+
async acquire(signal) {
|
|
605
|
+
if (signal?.aborted)
|
|
606
|
+
throw signal.reason;
|
|
566
607
|
if (!this._locked) {
|
|
567
608
|
this._locked = true;
|
|
568
609
|
return;
|
|
569
610
|
}
|
|
570
|
-
return new Promise((resolve) => {
|
|
571
|
-
|
|
611
|
+
return new Promise((resolve, reject) => {
|
|
612
|
+
const onAbort = () => {
|
|
613
|
+
const i = this._queue.indexOf(waiter);
|
|
614
|
+
if (i >= 0)
|
|
615
|
+
this._queue.splice(i, 1);
|
|
616
|
+
reject(signal.reason);
|
|
617
|
+
};
|
|
618
|
+
const waiter = () => {
|
|
619
|
+
signal?.removeEventListener("abort", onAbort);
|
|
620
|
+
resolve();
|
|
621
|
+
};
|
|
622
|
+
this._queue.push(waiter);
|
|
623
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
572
624
|
});
|
|
573
625
|
}
|
|
574
626
|
release() {
|
|
@@ -580,8 +632,8 @@ var AsyncLock = class {
|
|
|
580
632
|
this._locked = false;
|
|
581
633
|
}
|
|
582
634
|
}
|
|
583
|
-
async run(fn) {
|
|
584
|
-
await this.acquire();
|
|
635
|
+
async run(fn, signal) {
|
|
636
|
+
await this.acquire(signal);
|
|
585
637
|
try {
|
|
586
638
|
return await fn();
|
|
587
639
|
} finally {
|
|
@@ -602,6 +654,8 @@ var PromiseSource = class {
|
|
|
602
654
|
this._resolve = resolve;
|
|
603
655
|
this._reject = reject;
|
|
604
656
|
});
|
|
657
|
+
this.promise.catch(() => {
|
|
658
|
+
});
|
|
605
659
|
}
|
|
606
660
|
get isCompleted() {
|
|
607
661
|
return this._isCompleted;
|
|
@@ -643,7 +697,18 @@ var EventHandlerSet = class {
|
|
|
643
697
|
this._handlers.delete(handler);
|
|
644
698
|
}
|
|
645
699
|
trigger(arg) {
|
|
646
|
-
for (const handler of this._handlers)
|
|
700
|
+
for (const handler of [...this._handlers])
|
|
701
|
+
handler(arg);
|
|
702
|
+
}
|
|
703
|
+
// Fires every handler once, isolating each so one that throws can't stop the rest.
|
|
704
|
+
triggerSafe(arg, onError) {
|
|
705
|
+
for (const handler of [...this._handlers]) {
|
|
706
|
+
try {
|
|
707
|
+
handler(arg);
|
|
708
|
+
} catch (error) {
|
|
709
|
+
onError(error);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
647
712
|
}
|
|
648
713
|
clear() {
|
|
649
714
|
this._handlers.clear();
|
|
@@ -659,6 +724,19 @@ var EventHandlerSet = class {
|
|
|
659
724
|
}
|
|
660
725
|
};
|
|
661
726
|
|
|
727
|
+
// src/async-signal.ts
|
|
728
|
+
var AsyncSignal = class {
|
|
729
|
+
source = new PromiseSource();
|
|
730
|
+
wait() {
|
|
731
|
+
return this.source.promise;
|
|
732
|
+
}
|
|
733
|
+
notify() {
|
|
734
|
+
const source = this.source;
|
|
735
|
+
this.source = new PromiseSource();
|
|
736
|
+
source.resolve();
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
|
|
662
740
|
// src/withTimeout.ts
|
|
663
741
|
var TimeoutError = class extends Error {
|
|
664
742
|
name = "TimeoutError";
|
|
@@ -733,9 +811,19 @@ var TimedOut = class _TimedOut {
|
|
|
733
811
|
};
|
|
734
812
|
|
|
735
813
|
// src/delay.ts
|
|
736
|
-
function delayAsync(ms) {
|
|
737
|
-
|
|
738
|
-
|
|
814
|
+
function delayAsync(ms, signal) {
|
|
815
|
+
if (signal?.aborted)
|
|
816
|
+
return Promise.reject(signal.reason);
|
|
817
|
+
return new Promise((resolve, reject) => {
|
|
818
|
+
const onAbort = () => {
|
|
819
|
+
clearTimeout(timer);
|
|
820
|
+
reject(signal.reason);
|
|
821
|
+
};
|
|
822
|
+
const timer = setTimeout(() => {
|
|
823
|
+
signal?.removeEventListener("abort", onAbort);
|
|
824
|
+
resolve();
|
|
825
|
+
}, ms);
|
|
826
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
739
827
|
});
|
|
740
828
|
}
|
|
741
829
|
function delayAsyncWith(ms, value) {
|
|
@@ -747,10 +835,13 @@ function delayAsyncWith(ms, value) {
|
|
|
747
835
|
// src/abort-promise.ts
|
|
748
836
|
var abortPromiseCache = /* @__PURE__ */ new WeakMap();
|
|
749
837
|
function abortPromise(signal) {
|
|
750
|
-
if (signal.aborted) return Promise.reject(signal.reason);
|
|
751
838
|
let cached = abortPromiseCache.get(signal);
|
|
752
839
|
if (!cached) {
|
|
753
840
|
cached = new Promise((_, reject) => {
|
|
841
|
+
if (signal.aborted) {
|
|
842
|
+
reject(signal.reason);
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
754
845
|
signal.addEventListener("abort", () => reject(signal.reason), { once: true });
|
|
755
846
|
});
|
|
756
847
|
cached.catch(() => {
|
|
@@ -760,6 +851,59 @@ function abortPromise(signal) {
|
|
|
760
851
|
return cached;
|
|
761
852
|
}
|
|
762
853
|
|
|
854
|
+
// src/cancellation.ts
|
|
855
|
+
function isCancellation(error) {
|
|
856
|
+
return error != null && typeof error === "object" && error.name === "AbortError";
|
|
857
|
+
}
|
|
858
|
+
function cancellationError(message = "The operation was cancelled.") {
|
|
859
|
+
const error = new Error(message);
|
|
860
|
+
error.name = "AbortError";
|
|
861
|
+
return error;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
// src/await-with-cleanup.ts
|
|
865
|
+
function awaitWithCleanup(abortSignal, onAbort, wire) {
|
|
866
|
+
if (abortSignal?.aborted)
|
|
867
|
+
return onAbort === "reject" ? Promise.reject(abortSignal.reason ?? new Error("Operation cancelled.")) : resolvedVoidPromise;
|
|
868
|
+
const ps = new PromiseSource();
|
|
869
|
+
const cleanups = [];
|
|
870
|
+
let settled = false;
|
|
871
|
+
const runCleanups = () => {
|
|
872
|
+
for (const cleanup of cleanups)
|
|
873
|
+
cleanup();
|
|
874
|
+
cleanups.length = 0;
|
|
875
|
+
};
|
|
876
|
+
const complete = () => {
|
|
877
|
+
if (settled)
|
|
878
|
+
return;
|
|
879
|
+
settled = true;
|
|
880
|
+
runCleanups();
|
|
881
|
+
ps.resolve(void 0);
|
|
882
|
+
};
|
|
883
|
+
const addCleanup = (cleanup) => {
|
|
884
|
+
if (settled)
|
|
885
|
+
cleanup();
|
|
886
|
+
else
|
|
887
|
+
cleanups.push(cleanup);
|
|
888
|
+
};
|
|
889
|
+
if (abortSignal !== void 0) {
|
|
890
|
+
const onAbortFired = () => {
|
|
891
|
+
if (settled)
|
|
892
|
+
return;
|
|
893
|
+
settled = true;
|
|
894
|
+
runCleanups();
|
|
895
|
+
if (onAbort === "reject")
|
|
896
|
+
ps.reject(abortSignal.reason ?? new Error("Operation cancelled."));
|
|
897
|
+
else
|
|
898
|
+
ps.resolve(void 0);
|
|
899
|
+
};
|
|
900
|
+
abortSignal.addEventListener("abort", onAbortFired, { once: true });
|
|
901
|
+
cleanups.push(() => abortSignal.removeEventListener("abort", onAbortFired));
|
|
902
|
+
}
|
|
903
|
+
wire(complete, addCleanup);
|
|
904
|
+
return ps;
|
|
905
|
+
}
|
|
906
|
+
|
|
763
907
|
// src/internal-logging.ts
|
|
764
908
|
var scopeDefaults = {
|
|
765
909
|
retry: 3 /* Warn */,
|
|
@@ -1041,29 +1185,10 @@ var RetryDelayer = class {
|
|
|
1041
1185
|
const actualDelayMs = Math.max(1, delayMs);
|
|
1042
1186
|
const endsAt = Date.now() + actualDelayMs;
|
|
1043
1187
|
const cancelSignal = this._cancelController.signal;
|
|
1044
|
-
const
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
}, actualDelayMs);
|
|
1049
|
-
const onCancel = () => {
|
|
1050
|
-
clearTimeout(timer);
|
|
1051
|
-
cleanup();
|
|
1052
|
-
resolve();
|
|
1053
|
-
};
|
|
1054
|
-
const onAbort = () => {
|
|
1055
|
-
clearTimeout(timer);
|
|
1056
|
-
cleanup();
|
|
1057
|
-
reject(new Error("Retry delay aborted."));
|
|
1058
|
-
};
|
|
1059
|
-
const cleanup = () => {
|
|
1060
|
-
cancelSignal.removeEventListener("abort", onCancel);
|
|
1061
|
-
cancellationSignal?.removeEventListener("abort", onAbort);
|
|
1062
|
-
};
|
|
1063
|
-
cancelSignal.addEventListener("abort", onCancel, { once: true });
|
|
1064
|
-
cancellationSignal?.addEventListener("abort", onAbort, {
|
|
1065
|
-
once: true
|
|
1066
|
-
});
|
|
1188
|
+
const combinedSignal = cancellationSignal ? AbortSignal.any([cancellationSignal, cancelSignal]) : cancelSignal;
|
|
1189
|
+
const promise = delayAsync(actualDelayMs, combinedSignal).catch((e) => {
|
|
1190
|
+
if (!cancelSignal.aborted)
|
|
1191
|
+
throw e;
|
|
1067
1192
|
});
|
|
1068
1193
|
return { promise, endsAt, isLimitExceeded: false };
|
|
1069
1194
|
}
|
|
@@ -1078,7 +1203,7 @@ var RetryDelayer = class {
|
|
|
1078
1203
|
// src/retry.ts
|
|
1079
1204
|
var { warnLog } = getLogs("retry");
|
|
1080
1205
|
var defaultRetryDelays = () => 50;
|
|
1081
|
-
async function retry(tryCount, fn, retryDelays = defaultRetryDelays) {
|
|
1206
|
+
async function retry(tryCount, fn, retryDelays = defaultRetryDelays, signal) {
|
|
1082
1207
|
if (tryCount <= 0)
|
|
1083
1208
|
throw new Error("retry: tryCount must be positive.");
|
|
1084
1209
|
let lastError;
|
|
@@ -1092,7 +1217,7 @@ async function retry(tryCount, fn, retryDelays = defaultRetryDelays) {
|
|
|
1092
1217
|
++tryIndex;
|
|
1093
1218
|
if (tryIndex >= tryCount) throw lastError;
|
|
1094
1219
|
warnLog?.log(`retry(${tryIndex}/${tryCount}): error:`, lastError);
|
|
1095
|
-
await delayAsync(retryDelays(tryIndex));
|
|
1220
|
+
await delayAsync(retryDelays(tryIndex), signal);
|
|
1096
1221
|
}
|
|
1097
1222
|
}
|
|
1098
1223
|
async function catchErrors(fn, onError) {
|
|
@@ -1102,10 +1227,51 @@ async function catchErrors(fn, onError) {
|
|
|
1102
1227
|
return onError ? onError(e) : void 0;
|
|
1103
1228
|
}
|
|
1104
1229
|
}
|
|
1230
|
+
|
|
1231
|
+
// src/decorators.ts
|
|
1232
|
+
function ownMetadata(metadata, key) {
|
|
1233
|
+
const bag = metadata;
|
|
1234
|
+
if (!Object.hasOwn(metadata, key))
|
|
1235
|
+
bag[key] = { ...bag[key] };
|
|
1236
|
+
return bag[key];
|
|
1237
|
+
}
|
|
1238
|
+
function resolveArgCount(fn, explicit, methodName) {
|
|
1239
|
+
if (explicit !== void 0)
|
|
1240
|
+
return explicit;
|
|
1241
|
+
if (hasAmbiguousArity(fn))
|
|
1242
|
+
throw new Error(
|
|
1243
|
+
`Cannot infer the argument count of "${methodName}": its parameter list uses default and/or rest parameters, for which Function.length is unreliable. Pass an explicit argCount to the decorator.`
|
|
1244
|
+
);
|
|
1245
|
+
return fn.length;
|
|
1246
|
+
}
|
|
1247
|
+
function hasAmbiguousArity(fn) {
|
|
1248
|
+
const params = parameterListText(fn);
|
|
1249
|
+
return params !== void 0 && (params.includes("=") || params.includes("..."));
|
|
1250
|
+
}
|
|
1251
|
+
function parameterListText(fn) {
|
|
1252
|
+
const src = fn.toString();
|
|
1253
|
+
const open = src.indexOf("(");
|
|
1254
|
+
const arrow = src.indexOf("=>");
|
|
1255
|
+
if (open < 0 || arrow >= 0 && arrow < open)
|
|
1256
|
+
return void 0;
|
|
1257
|
+
let depth = 0;
|
|
1258
|
+
for (let i = open; i < src.length; i++) {
|
|
1259
|
+
const ch = src[i];
|
|
1260
|
+
if (ch === "(")
|
|
1261
|
+
depth++;
|
|
1262
|
+
else if (ch === ")") {
|
|
1263
|
+
depth--;
|
|
1264
|
+
if (depth === 0)
|
|
1265
|
+
return src.slice(open + 1, i);
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
return void 0;
|
|
1269
|
+
}
|
|
1105
1270
|
export {
|
|
1106
1271
|
AsyncContext,
|
|
1107
1272
|
AsyncContextKey,
|
|
1108
1273
|
AsyncLock,
|
|
1274
|
+
AsyncSignal,
|
|
1109
1275
|
DisposableBag,
|
|
1110
1276
|
EventHandlerSet,
|
|
1111
1277
|
Log,
|
|
@@ -1124,6 +1290,8 @@ export {
|
|
|
1124
1290
|
TimeoutError,
|
|
1125
1291
|
abortPromise,
|
|
1126
1292
|
abortSignalKey,
|
|
1293
|
+
awaitWithCleanup,
|
|
1294
|
+
cancellationError,
|
|
1127
1295
|
catchErrors,
|
|
1128
1296
|
createLogProvider,
|
|
1129
1297
|
debounce,
|
|
@@ -1132,6 +1300,9 @@ export {
|
|
|
1132
1300
|
errorResult,
|
|
1133
1301
|
initLogging,
|
|
1134
1302
|
initWorkerLogging,
|
|
1303
|
+
isCancellation,
|
|
1304
|
+
ownMetadata,
|
|
1305
|
+
resolveArgCount,
|
|
1135
1306
|
resolvedVoidPromise,
|
|
1136
1307
|
result,
|
|
1137
1308
|
resultFrom,
|