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