@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.cjs
CHANGED
|
@@ -23,6 +23,7 @@ __export(index_exports, {
|
|
|
23
23
|
AsyncContext: () => AsyncContext,
|
|
24
24
|
AsyncContextKey: () => AsyncContextKey,
|
|
25
25
|
AsyncLock: () => AsyncLock,
|
|
26
|
+
AsyncSignal: () => AsyncSignal,
|
|
26
27
|
DisposableBag: () => DisposableBag,
|
|
27
28
|
EventHandlerSet: () => EventHandlerSet,
|
|
28
29
|
Log: () => Log,
|
|
@@ -41,6 +42,8 @@ __export(index_exports, {
|
|
|
41
42
|
TimeoutError: () => TimeoutError,
|
|
42
43
|
abortPromise: () => abortPromise,
|
|
43
44
|
abortSignalKey: () => abortSignalKey,
|
|
45
|
+
awaitWithCleanup: () => awaitWithCleanup,
|
|
46
|
+
cancellationError: () => cancellationError,
|
|
44
47
|
catchErrors: () => catchErrors,
|
|
45
48
|
createLogProvider: () => createLogProvider,
|
|
46
49
|
debounce: () => debounce,
|
|
@@ -49,6 +52,9 @@ __export(index_exports, {
|
|
|
49
52
|
errorResult: () => errorResult,
|
|
50
53
|
initLogging: () => initLogging,
|
|
51
54
|
initWorkerLogging: () => initWorkerLogging,
|
|
55
|
+
isCancellation: () => isCancellation,
|
|
56
|
+
ownMetadata: () => ownMetadata,
|
|
57
|
+
resolveArgCount: () => resolveArgCount,
|
|
52
58
|
resolvedVoidPromise: () => resolvedVoidPromise,
|
|
53
59
|
result: () => result,
|
|
54
60
|
resultFrom: () => resultFrom,
|
|
@@ -501,9 +507,9 @@ var Result = class _Result {
|
|
|
501
507
|
hasError;
|
|
502
508
|
_value;
|
|
503
509
|
_error;
|
|
504
|
-
constructor(value, error) {
|
|
505
|
-
this.
|
|
506
|
-
this.
|
|
510
|
+
constructor(value, error, hasError = error !== void 0) {
|
|
511
|
+
this.hasError = hasError;
|
|
512
|
+
this.hasValue = !hasError;
|
|
507
513
|
this._value = value;
|
|
508
514
|
this._error = error;
|
|
509
515
|
}
|
|
@@ -517,11 +523,17 @@ var Result = class _Result {
|
|
|
517
523
|
get valueOrUndefined() {
|
|
518
524
|
return this.hasValue ? this._value : void 0;
|
|
519
525
|
}
|
|
526
|
+
// Values compared with valueComparer (Object.is by default); errors by reference — mirrors C# Result<T>.Equals.
|
|
527
|
+
equals(other, valueComparer = Object.is) {
|
|
528
|
+
if (this.hasError !== other.hasError || this._error !== other._error)
|
|
529
|
+
return false;
|
|
530
|
+
return valueComparer(this._value, other._value);
|
|
531
|
+
}
|
|
520
532
|
static ok(value) {
|
|
521
|
-
return new _Result(value);
|
|
533
|
+
return new _Result(value, void 0, false);
|
|
522
534
|
}
|
|
523
535
|
static error(error) {
|
|
524
|
-
return new _Result(void 0, error);
|
|
536
|
+
return new _Result(void 0, error ?? new Error("Unspecified error"), true);
|
|
525
537
|
}
|
|
526
538
|
};
|
|
527
539
|
function result(value, error) {
|
|
@@ -558,15 +570,35 @@ var abortSignalKey = new AsyncContextKey(
|
|
|
558
570
|
"AbortSignal",
|
|
559
571
|
void 0
|
|
560
572
|
);
|
|
573
|
+
var _alsImpl = detectAsyncLocalStorage();
|
|
574
|
+
var _als = _alsImpl;
|
|
575
|
+
function detectAsyncLocalStorage() {
|
|
576
|
+
const proc = globalThis.process;
|
|
577
|
+
const asyncHooks = proc?.getBuiltinModule?.("node:async_hooks");
|
|
578
|
+
return asyncHooks === void 0 ? void 0 : new asyncHooks.AsyncLocalStorage();
|
|
579
|
+
}
|
|
561
580
|
var AsyncContext = class _AsyncContext {
|
|
562
|
-
static current = void 0;
|
|
563
581
|
/** Immutable empty singleton — avoids allocating new AsyncContext(). */
|
|
564
582
|
static empty = new _AsyncContext();
|
|
583
|
+
static _current = void 0;
|
|
565
584
|
static _defaults = /* @__PURE__ */ new Map();
|
|
566
585
|
_values;
|
|
567
586
|
constructor(values) {
|
|
568
587
|
this._values = values ?? /* @__PURE__ */ new Map();
|
|
569
588
|
}
|
|
589
|
+
static get current() {
|
|
590
|
+
return _als?.getStore() ?? _AsyncContext._current;
|
|
591
|
+
}
|
|
592
|
+
static set current(value) {
|
|
593
|
+
if (_als !== void 0)
|
|
594
|
+
_als.enterWith(value);
|
|
595
|
+
else
|
|
596
|
+
_AsyncContext._current = value;
|
|
597
|
+
}
|
|
598
|
+
/** True when AsyncContext.current flows across awaits (Node AsyncLocalStorage is active). */
|
|
599
|
+
static get isAsyncLocalStorageActive() {
|
|
600
|
+
return _als !== void 0;
|
|
601
|
+
}
|
|
570
602
|
get(key) {
|
|
571
603
|
if (this._values.has(key.id)) return this._values.get(key.id);
|
|
572
604
|
if (_AsyncContext._defaults.has(key.id))
|
|
@@ -580,20 +612,27 @@ var AsyncContext = class _AsyncContext {
|
|
|
580
612
|
}
|
|
581
613
|
activate() {
|
|
582
614
|
const prev = _AsyncContext.current;
|
|
583
|
-
|
|
615
|
+
const als = _als;
|
|
616
|
+
if (als !== void 0) {
|
|
617
|
+
als.enterWith(this);
|
|
618
|
+
return { dispose: () => als.enterWith(prev) };
|
|
619
|
+
}
|
|
620
|
+
_AsyncContext._current = this;
|
|
584
621
|
return {
|
|
585
622
|
dispose: () => {
|
|
586
|
-
_AsyncContext.
|
|
623
|
+
_AsyncContext._current = prev;
|
|
587
624
|
}
|
|
588
625
|
};
|
|
589
626
|
}
|
|
590
627
|
run(fn) {
|
|
591
|
-
|
|
592
|
-
|
|
628
|
+
if (_als !== void 0)
|
|
629
|
+
return _als.run(this, fn);
|
|
630
|
+
const prev = _AsyncContext._current;
|
|
631
|
+
_AsyncContext._current = this;
|
|
593
632
|
try {
|
|
594
633
|
return fn();
|
|
595
634
|
} finally {
|
|
596
|
-
_AsyncContext.
|
|
635
|
+
_AsyncContext._current = prev;
|
|
597
636
|
}
|
|
598
637
|
}
|
|
599
638
|
/** Strip THIS exact instance from args if it's the last element (reference equality). */
|
|
@@ -615,6 +654,12 @@ var AsyncContext = class _AsyncContext {
|
|
|
615
654
|
static getOrCreate() {
|
|
616
655
|
return _AsyncContext.current ?? _AsyncContext.empty;
|
|
617
656
|
}
|
|
657
|
+
// Toggles AsyncLocalStorage backing — for tests that exercise the browser fallback path.
|
|
658
|
+
// Clears the fallback static field so no stale context bleeds across the toggle.
|
|
659
|
+
static _setAsyncLocalStorageActive(active) {
|
|
660
|
+
_als = active ? _alsImpl : void 0;
|
|
661
|
+
_AsyncContext._current = void 0;
|
|
662
|
+
}
|
|
618
663
|
};
|
|
619
664
|
|
|
620
665
|
// src/async-lock.ts
|
|
@@ -624,13 +669,26 @@ var AsyncLock = class {
|
|
|
624
669
|
get isLocked() {
|
|
625
670
|
return this._locked;
|
|
626
671
|
}
|
|
627
|
-
async acquire() {
|
|
672
|
+
async acquire(signal) {
|
|
673
|
+
if (signal?.aborted)
|
|
674
|
+
throw signal.reason;
|
|
628
675
|
if (!this._locked) {
|
|
629
676
|
this._locked = true;
|
|
630
677
|
return;
|
|
631
678
|
}
|
|
632
|
-
return new Promise((resolve) => {
|
|
633
|
-
|
|
679
|
+
return new Promise((resolve, reject) => {
|
|
680
|
+
const onAbort = () => {
|
|
681
|
+
const i = this._queue.indexOf(waiter);
|
|
682
|
+
if (i >= 0)
|
|
683
|
+
this._queue.splice(i, 1);
|
|
684
|
+
reject(signal.reason);
|
|
685
|
+
};
|
|
686
|
+
const waiter = () => {
|
|
687
|
+
signal?.removeEventListener("abort", onAbort);
|
|
688
|
+
resolve();
|
|
689
|
+
};
|
|
690
|
+
this._queue.push(waiter);
|
|
691
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
634
692
|
});
|
|
635
693
|
}
|
|
636
694
|
release() {
|
|
@@ -642,8 +700,8 @@ var AsyncLock = class {
|
|
|
642
700
|
this._locked = false;
|
|
643
701
|
}
|
|
644
702
|
}
|
|
645
|
-
async run(fn) {
|
|
646
|
-
await this.acquire();
|
|
703
|
+
async run(fn, signal) {
|
|
704
|
+
await this.acquire(signal);
|
|
647
705
|
try {
|
|
648
706
|
return await fn();
|
|
649
707
|
} finally {
|
|
@@ -664,6 +722,8 @@ var PromiseSource = class {
|
|
|
664
722
|
this._resolve = resolve;
|
|
665
723
|
this._reject = reject;
|
|
666
724
|
});
|
|
725
|
+
this.promise.catch(() => {
|
|
726
|
+
});
|
|
667
727
|
}
|
|
668
728
|
get isCompleted() {
|
|
669
729
|
return this._isCompleted;
|
|
@@ -705,7 +765,18 @@ var EventHandlerSet = class {
|
|
|
705
765
|
this._handlers.delete(handler);
|
|
706
766
|
}
|
|
707
767
|
trigger(arg) {
|
|
708
|
-
for (const handler of this._handlers)
|
|
768
|
+
for (const handler of [...this._handlers])
|
|
769
|
+
handler(arg);
|
|
770
|
+
}
|
|
771
|
+
// Fires every handler once, isolating each so one that throws can't stop the rest.
|
|
772
|
+
triggerSafe(arg, onError) {
|
|
773
|
+
for (const handler of [...this._handlers]) {
|
|
774
|
+
try {
|
|
775
|
+
handler(arg);
|
|
776
|
+
} catch (error) {
|
|
777
|
+
onError(error);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
709
780
|
}
|
|
710
781
|
clear() {
|
|
711
782
|
this._handlers.clear();
|
|
@@ -721,6 +792,19 @@ var EventHandlerSet = class {
|
|
|
721
792
|
}
|
|
722
793
|
};
|
|
723
794
|
|
|
795
|
+
// src/async-signal.ts
|
|
796
|
+
var AsyncSignal = class {
|
|
797
|
+
source = new PromiseSource();
|
|
798
|
+
wait() {
|
|
799
|
+
return this.source.promise;
|
|
800
|
+
}
|
|
801
|
+
notify() {
|
|
802
|
+
const source = this.source;
|
|
803
|
+
this.source = new PromiseSource();
|
|
804
|
+
source.resolve();
|
|
805
|
+
}
|
|
806
|
+
};
|
|
807
|
+
|
|
724
808
|
// src/withTimeout.ts
|
|
725
809
|
var TimeoutError = class extends Error {
|
|
726
810
|
name = "TimeoutError";
|
|
@@ -795,9 +879,19 @@ var TimedOut = class _TimedOut {
|
|
|
795
879
|
};
|
|
796
880
|
|
|
797
881
|
// src/delay.ts
|
|
798
|
-
function delayAsync(ms) {
|
|
799
|
-
|
|
800
|
-
|
|
882
|
+
function delayAsync(ms, signal) {
|
|
883
|
+
if (signal?.aborted)
|
|
884
|
+
return Promise.reject(signal.reason);
|
|
885
|
+
return new Promise((resolve, reject) => {
|
|
886
|
+
const onAbort = () => {
|
|
887
|
+
clearTimeout(timer);
|
|
888
|
+
reject(signal.reason);
|
|
889
|
+
};
|
|
890
|
+
const timer = setTimeout(() => {
|
|
891
|
+
signal?.removeEventListener("abort", onAbort);
|
|
892
|
+
resolve();
|
|
893
|
+
}, ms);
|
|
894
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
801
895
|
});
|
|
802
896
|
}
|
|
803
897
|
function delayAsyncWith(ms, value) {
|
|
@@ -809,10 +903,13 @@ function delayAsyncWith(ms, value) {
|
|
|
809
903
|
// src/abort-promise.ts
|
|
810
904
|
var abortPromiseCache = /* @__PURE__ */ new WeakMap();
|
|
811
905
|
function abortPromise(signal) {
|
|
812
|
-
if (signal.aborted) return Promise.reject(signal.reason);
|
|
813
906
|
let cached = abortPromiseCache.get(signal);
|
|
814
907
|
if (!cached) {
|
|
815
908
|
cached = new Promise((_, reject) => {
|
|
909
|
+
if (signal.aborted) {
|
|
910
|
+
reject(signal.reason);
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
816
913
|
signal.addEventListener("abort", () => reject(signal.reason), { once: true });
|
|
817
914
|
});
|
|
818
915
|
cached.catch(() => {
|
|
@@ -822,6 +919,59 @@ function abortPromise(signal) {
|
|
|
822
919
|
return cached;
|
|
823
920
|
}
|
|
824
921
|
|
|
922
|
+
// src/cancellation.ts
|
|
923
|
+
function isCancellation(error) {
|
|
924
|
+
return error != null && typeof error === "object" && error.name === "AbortError";
|
|
925
|
+
}
|
|
926
|
+
function cancellationError(message = "The operation was cancelled.") {
|
|
927
|
+
const error = new Error(message);
|
|
928
|
+
error.name = "AbortError";
|
|
929
|
+
return error;
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
// src/await-with-cleanup.ts
|
|
933
|
+
function awaitWithCleanup(abortSignal, onAbort, wire) {
|
|
934
|
+
if (abortSignal?.aborted)
|
|
935
|
+
return onAbort === "reject" ? Promise.reject(abortSignal.reason ?? new Error("Operation cancelled.")) : resolvedVoidPromise;
|
|
936
|
+
const ps = new PromiseSource();
|
|
937
|
+
const cleanups = [];
|
|
938
|
+
let settled = false;
|
|
939
|
+
const runCleanups = () => {
|
|
940
|
+
for (const cleanup of cleanups)
|
|
941
|
+
cleanup();
|
|
942
|
+
cleanups.length = 0;
|
|
943
|
+
};
|
|
944
|
+
const complete = () => {
|
|
945
|
+
if (settled)
|
|
946
|
+
return;
|
|
947
|
+
settled = true;
|
|
948
|
+
runCleanups();
|
|
949
|
+
ps.resolve(void 0);
|
|
950
|
+
};
|
|
951
|
+
const addCleanup = (cleanup) => {
|
|
952
|
+
if (settled)
|
|
953
|
+
cleanup();
|
|
954
|
+
else
|
|
955
|
+
cleanups.push(cleanup);
|
|
956
|
+
};
|
|
957
|
+
if (abortSignal !== void 0) {
|
|
958
|
+
const onAbortFired = () => {
|
|
959
|
+
if (settled)
|
|
960
|
+
return;
|
|
961
|
+
settled = true;
|
|
962
|
+
runCleanups();
|
|
963
|
+
if (onAbort === "reject")
|
|
964
|
+
ps.reject(abortSignal.reason ?? new Error("Operation cancelled."));
|
|
965
|
+
else
|
|
966
|
+
ps.resolve(void 0);
|
|
967
|
+
};
|
|
968
|
+
abortSignal.addEventListener("abort", onAbortFired, { once: true });
|
|
969
|
+
cleanups.push(() => abortSignal.removeEventListener("abort", onAbortFired));
|
|
970
|
+
}
|
|
971
|
+
wire(complete, addCleanup);
|
|
972
|
+
return ps;
|
|
973
|
+
}
|
|
974
|
+
|
|
825
975
|
// src/internal-logging.ts
|
|
826
976
|
var scopeDefaults = {
|
|
827
977
|
retry: 3 /* Warn */,
|
|
@@ -1103,29 +1253,10 @@ var RetryDelayer = class {
|
|
|
1103
1253
|
const actualDelayMs = Math.max(1, delayMs);
|
|
1104
1254
|
const endsAt = Date.now() + actualDelayMs;
|
|
1105
1255
|
const cancelSignal = this._cancelController.signal;
|
|
1106
|
-
const
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
}, actualDelayMs);
|
|
1111
|
-
const onCancel = () => {
|
|
1112
|
-
clearTimeout(timer);
|
|
1113
|
-
cleanup();
|
|
1114
|
-
resolve();
|
|
1115
|
-
};
|
|
1116
|
-
const onAbort = () => {
|
|
1117
|
-
clearTimeout(timer);
|
|
1118
|
-
cleanup();
|
|
1119
|
-
reject(new Error("Retry delay aborted."));
|
|
1120
|
-
};
|
|
1121
|
-
const cleanup = () => {
|
|
1122
|
-
cancelSignal.removeEventListener("abort", onCancel);
|
|
1123
|
-
cancellationSignal?.removeEventListener("abort", onAbort);
|
|
1124
|
-
};
|
|
1125
|
-
cancelSignal.addEventListener("abort", onCancel, { once: true });
|
|
1126
|
-
cancellationSignal?.addEventListener("abort", onAbort, {
|
|
1127
|
-
once: true
|
|
1128
|
-
});
|
|
1256
|
+
const combinedSignal = cancellationSignal ? AbortSignal.any([cancellationSignal, cancelSignal]) : cancelSignal;
|
|
1257
|
+
const promise = delayAsync(actualDelayMs, combinedSignal).catch((e) => {
|
|
1258
|
+
if (!cancelSignal.aborted)
|
|
1259
|
+
throw e;
|
|
1129
1260
|
});
|
|
1130
1261
|
return { promise, endsAt, isLimitExceeded: false };
|
|
1131
1262
|
}
|
|
@@ -1140,7 +1271,7 @@ var RetryDelayer = class {
|
|
|
1140
1271
|
// src/retry.ts
|
|
1141
1272
|
var { warnLog } = getLogs("retry");
|
|
1142
1273
|
var defaultRetryDelays = () => 50;
|
|
1143
|
-
async function retry(tryCount, fn, retryDelays = defaultRetryDelays) {
|
|
1274
|
+
async function retry(tryCount, fn, retryDelays = defaultRetryDelays, signal) {
|
|
1144
1275
|
if (tryCount <= 0)
|
|
1145
1276
|
throw new Error("retry: tryCount must be positive.");
|
|
1146
1277
|
let lastError;
|
|
@@ -1154,7 +1285,7 @@ async function retry(tryCount, fn, retryDelays = defaultRetryDelays) {
|
|
|
1154
1285
|
++tryIndex;
|
|
1155
1286
|
if (tryIndex >= tryCount) throw lastError;
|
|
1156
1287
|
warnLog?.log(`retry(${tryIndex}/${tryCount}): error:`, lastError);
|
|
1157
|
-
await delayAsync(retryDelays(tryIndex));
|
|
1288
|
+
await delayAsync(retryDelays(tryIndex), signal);
|
|
1158
1289
|
}
|
|
1159
1290
|
}
|
|
1160
1291
|
async function catchErrors(fn, onError) {
|
|
@@ -1164,11 +1295,52 @@ async function catchErrors(fn, onError) {
|
|
|
1164
1295
|
return onError ? onError(e) : void 0;
|
|
1165
1296
|
}
|
|
1166
1297
|
}
|
|
1298
|
+
|
|
1299
|
+
// src/decorators.ts
|
|
1300
|
+
function ownMetadata(metadata, key) {
|
|
1301
|
+
const bag = metadata;
|
|
1302
|
+
if (!Object.hasOwn(metadata, key))
|
|
1303
|
+
bag[key] = { ...bag[key] };
|
|
1304
|
+
return bag[key];
|
|
1305
|
+
}
|
|
1306
|
+
function resolveArgCount(fn, explicit, methodName) {
|
|
1307
|
+
if (explicit !== void 0)
|
|
1308
|
+
return explicit;
|
|
1309
|
+
if (hasAmbiguousArity(fn))
|
|
1310
|
+
throw new Error(
|
|
1311
|
+
`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.`
|
|
1312
|
+
);
|
|
1313
|
+
return fn.length;
|
|
1314
|
+
}
|
|
1315
|
+
function hasAmbiguousArity(fn) {
|
|
1316
|
+
const params = parameterListText(fn);
|
|
1317
|
+
return params !== void 0 && (params.includes("=") || params.includes("..."));
|
|
1318
|
+
}
|
|
1319
|
+
function parameterListText(fn) {
|
|
1320
|
+
const src = fn.toString();
|
|
1321
|
+
const open = src.indexOf("(");
|
|
1322
|
+
const arrow = src.indexOf("=>");
|
|
1323
|
+
if (open < 0 || arrow >= 0 && arrow < open)
|
|
1324
|
+
return void 0;
|
|
1325
|
+
let depth = 0;
|
|
1326
|
+
for (let i = open; i < src.length; i++) {
|
|
1327
|
+
const ch = src[i];
|
|
1328
|
+
if (ch === "(")
|
|
1329
|
+
depth++;
|
|
1330
|
+
else if (ch === ")") {
|
|
1331
|
+
depth--;
|
|
1332
|
+
if (depth === 0)
|
|
1333
|
+
return src.slice(open + 1, i);
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
return void 0;
|
|
1337
|
+
}
|
|
1167
1338
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1168
1339
|
0 && (module.exports = {
|
|
1169
1340
|
AsyncContext,
|
|
1170
1341
|
AsyncContextKey,
|
|
1171
1342
|
AsyncLock,
|
|
1343
|
+
AsyncSignal,
|
|
1172
1344
|
DisposableBag,
|
|
1173
1345
|
EventHandlerSet,
|
|
1174
1346
|
Log,
|
|
@@ -1187,6 +1359,8 @@ async function catchErrors(fn, onError) {
|
|
|
1187
1359
|
TimeoutError,
|
|
1188
1360
|
abortPromise,
|
|
1189
1361
|
abortSignalKey,
|
|
1362
|
+
awaitWithCleanup,
|
|
1363
|
+
cancellationError,
|
|
1190
1364
|
catchErrors,
|
|
1191
1365
|
createLogProvider,
|
|
1192
1366
|
debounce,
|
|
@@ -1195,6 +1369,9 @@ async function catchErrors(fn, onError) {
|
|
|
1195
1369
|
errorResult,
|
|
1196
1370
|
initLogging,
|
|
1197
1371
|
initWorkerLogging,
|
|
1372
|
+
isCancellation,
|
|
1373
|
+
ownMetadata,
|
|
1374
|
+
resolveArgCount,
|
|
1198
1375
|
resolvedVoidPromise,
|
|
1199
1376
|
result,
|
|
1200
1377
|
resultFrom,
|