@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 CHANGED
@@ -29,21 +29,34 @@ __export(index_exports, {
29
29
  LogLevel: () => LogLevel,
30
30
  LogLevelController: () => LogLevelController,
31
31
  PromiseSource: () => PromiseSource,
32
+ PromiseSourceWithTimeout: () => PromiseSourceWithTimeout,
33
+ ResolvedPromise: () => ResolvedPromise,
32
34
  Result: () => Result,
33
35
  RetryDelayLimitExceeded: () => RetryDelayLimitExceeded,
34
36
  RetryDelayNone: () => RetryDelayNone,
35
37
  RetryDelaySeq: () => RetryDelaySeq,
36
38
  RetryDelayer: () => RetryDelayer,
37
39
  RingBuffer: () => RingBuffer,
40
+ TimedOut: () => TimedOut,
41
+ TimeoutError: () => TimeoutError,
42
+ abortPromise: () => abortPromise,
38
43
  abortSignalKey: () => abortSignalKey,
44
+ catchErrors: () => catchErrors,
39
45
  createLogProvider: () => createLogProvider,
46
+ debounce: () => debounce,
47
+ delayAsync: () => delayAsync,
48
+ delayAsyncWith: () => delayAsyncWith,
40
49
  errorResult: () => errorResult,
41
50
  initLogging: () => initLogging,
42
51
  initWorkerLogging: () => initWorkerLogging,
43
52
  resolvedVoidPromise: () => resolvedVoidPromise,
44
53
  result: () => result,
45
54
  resultFrom: () => resultFrom,
46
- resultFromAsync: () => resultFromAsync
55
+ resultFromAsync: () => resultFromAsync,
56
+ retry: () => retry,
57
+ serialize: () => serialize,
58
+ throttle: () => throttle,
59
+ withTimeout: () => withTimeout
47
60
  });
48
61
  module.exports = __toCommonJS(index_exports);
49
62
 
@@ -642,6 +655,7 @@ var AsyncLock = class {
642
655
  // src/promise-source.ts
643
656
  var PromiseSource = class {
644
657
  promise;
658
+ [Symbol.toStringTag] = "Promise";
645
659
  _resolve;
646
660
  _reject;
647
661
  _isCompleted = false;
@@ -666,6 +680,15 @@ var PromiseSource = class {
666
680
  this._reject(reason);
667
681
  return true;
668
682
  }
683
+ then(onfulfilled, onrejected) {
684
+ return this.promise.then(onfulfilled, onrejected);
685
+ }
686
+ catch(onrejected) {
687
+ return this.promise.catch(onrejected);
688
+ }
689
+ finally(onfinally) {
690
+ return this.promise.finally(onfinally);
691
+ }
669
692
  };
670
693
  var resolvedVoidPromise = Promise.resolve();
671
694
 
@@ -694,10 +717,235 @@ var EventHandlerSet = class {
694
717
  ps.resolve(arg);
695
718
  };
696
719
  this._handlers.add(handler);
697
- return ps.promise;
720
+ return ps;
721
+ }
722
+ };
723
+
724
+ // src/withTimeout.ts
725
+ var TimeoutError = class extends Error {
726
+ name = "TimeoutError";
727
+ constructor(message = "Operation timed out") {
728
+ super(message);
729
+ }
730
+ };
731
+ async function withTimeout(promise, ms, message) {
732
+ let timer;
733
+ const timeoutPromise = new Promise((_, reject) => {
734
+ timer = setTimeout(
735
+ () => reject(new TimeoutError(message ?? `Operation timed out after ${ms}ms`)),
736
+ ms
737
+ );
738
+ });
739
+ timeoutPromise.catch(() => {
740
+ });
741
+ try {
742
+ return await Promise.race([promise, timeoutPromise]);
743
+ } finally {
744
+ if (timer !== void 0) clearTimeout(timer);
745
+ }
746
+ }
747
+
748
+ // src/promise-source-with-timeout.ts
749
+ var PromiseSourceWithTimeout = class extends PromiseSource {
750
+ _timer;
751
+ hasTimeout() {
752
+ return this._timer !== void 0;
753
+ }
754
+ /**
755
+ * Install (or replace) a timeout. Pass `null` to remove without setting a
756
+ * new one. `callback` is invoked when the timer fires — if omitted, the
757
+ * promise is rejected with a generic "timed out" error.
758
+ */
759
+ setTimeout(ms, callback) {
760
+ this.clearTimeout();
761
+ if (ms === null || this.isCompleted) return;
762
+ this._timer = setTimeout(() => {
763
+ this._timer = void 0;
764
+ if (callback) callback();
765
+ else this.reject(new TimeoutError(`The promise has timed out after ${ms}ms.`));
766
+ }, ms);
767
+ }
768
+ clearTimeout() {
769
+ if (this._timer === void 0) return;
770
+ clearTimeout(this._timer);
771
+ this._timer = void 0;
772
+ }
773
+ resolve(value) {
774
+ const didSettle = super.resolve(value);
775
+ if (didSettle) this.clearTimeout();
776
+ return didSettle;
777
+ }
778
+ reject(reason) {
779
+ const didSettle = super.reject(reason);
780
+ if (didSettle) this.clearTimeout();
781
+ return didSettle;
698
782
  }
699
783
  };
700
784
 
785
+ // src/resolved-promise.ts
786
+ var ResolvedPromise = {
787
+ Void: Promise.resolve(),
788
+ True: Promise.resolve(true),
789
+ False: Promise.resolve(false)
790
+ };
791
+
792
+ // src/timed-out.ts
793
+ var TimedOut = class _TimedOut {
794
+ static instance = new _TimedOut();
795
+ };
796
+
797
+ // src/delay.ts
798
+ function delayAsync(ms) {
799
+ return new Promise((resolve) => {
800
+ setTimeout(resolve, ms);
801
+ });
802
+ }
803
+ function delayAsyncWith(ms, value) {
804
+ return new Promise((resolve) => {
805
+ setTimeout(() => resolve(value), ms);
806
+ });
807
+ }
808
+
809
+ // src/abort-promise.ts
810
+ var abortPromiseCache = /* @__PURE__ */ new WeakMap();
811
+ function abortPromise(signal) {
812
+ if (signal.aborted) return Promise.reject(signal.reason);
813
+ let cached = abortPromiseCache.get(signal);
814
+ if (!cached) {
815
+ cached = new Promise((_, reject) => {
816
+ signal.addEventListener("abort", () => reject(signal.reason), { once: true });
817
+ });
818
+ cached.catch(() => {
819
+ });
820
+ abortPromiseCache.set(signal, cached);
821
+ }
822
+ return cached;
823
+ }
824
+
825
+ // src/internal-logging.ts
826
+ var scopeDefaults = {
827
+ retry: 3 /* Warn */,
828
+ throttle: 3 /* Warn */
829
+ };
830
+ var getLogs = createLogProvider("core.", scopeDefaults);
831
+
832
+ // src/throttle.ts
833
+ var { errorLog } = getLogs("throttle");
834
+ var Call = class {
835
+ constructor(func, self, parameters) {
836
+ this.func = func;
837
+ this.self = self;
838
+ this.parameters = parameters;
839
+ }
840
+ invoke() {
841
+ return this.func.apply(this.self, this.parameters);
842
+ }
843
+ invokeSilently() {
844
+ try {
845
+ return this.invoke();
846
+ } catch (error) {
847
+ errorLog?.log("Call.invokeSilently: unhandled error:", error);
848
+ }
849
+ }
850
+ };
851
+ function throttle(func, intervalMs, mode = "default") {
852
+ let lastCall = null;
853
+ let nextFireTime = 0;
854
+ let timeoutHandle = null;
855
+ const reset2 = () => {
856
+ if (timeoutHandle !== null) clearTimeout(timeoutHandle);
857
+ timeoutHandle = null;
858
+ lastCall = null;
859
+ nextFireTime = 0;
860
+ };
861
+ const fire = () => {
862
+ if (timeoutHandle !== null) clearTimeout(timeoutHandle);
863
+ if (lastCall !== null) {
864
+ const call = lastCall;
865
+ lastCall = null;
866
+ nextFireTime = Date.now() + intervalMs;
867
+ timeoutHandle = setTimeout(fire, intervalMs);
868
+ call.invokeSilently();
869
+ } else {
870
+ timeoutHandle = null;
871
+ nextFireTime = 0;
872
+ }
873
+ };
874
+ const wrapped = function(...args) {
875
+ const call = new Call(func, this, args);
876
+ const fireDelay = nextFireTime - Date.now();
877
+ if (timeoutHandle !== null && fireDelay <= 0) {
878
+ fire();
879
+ }
880
+ if (timeoutHandle === null) {
881
+ nextFireTime = Date.now() + intervalMs;
882
+ timeoutHandle = setTimeout(fire, intervalMs);
883
+ if (mode === "delayHead") {
884
+ lastCall = call;
885
+ } else {
886
+ call.invokeSilently();
887
+ }
888
+ } else if (mode !== "skip") {
889
+ lastCall = call;
890
+ }
891
+ };
892
+ wrapped.reset = reset2;
893
+ return wrapped;
894
+ }
895
+ function debounce(func, intervalMs) {
896
+ let lastCall = null;
897
+ let nextFireTime = 0;
898
+ let timeoutHandle = null;
899
+ const reset2 = () => {
900
+ timeoutHandle = null;
901
+ lastCall = null;
902
+ nextFireTime = 0;
903
+ };
904
+ const fire = () => {
905
+ if (timeoutHandle !== null) clearTimeout(timeoutHandle);
906
+ timeoutHandle = null;
907
+ const fireDelay = nextFireTime - Date.now();
908
+ if (fireDelay <= 0) {
909
+ nextFireTime = 0;
910
+ if (lastCall !== null) {
911
+ const call = lastCall;
912
+ lastCall = null;
913
+ call.invokeSilently();
914
+ }
915
+ } else {
916
+ timeoutHandle = setTimeout(fire, fireDelay);
917
+ }
918
+ };
919
+ const wrapped = function(...args) {
920
+ lastCall = new Call(func, this, args);
921
+ nextFireTime = Date.now() + intervalMs;
922
+ timeoutHandle ??= setTimeout(fire, intervalMs);
923
+ };
924
+ wrapped.reset = reset2;
925
+ return wrapped;
926
+ }
927
+
928
+ // src/serialize.ts
929
+ function serialize(func, limit = null) {
930
+ let lastCall = Promise.resolve(null);
931
+ let queueSize = 0;
932
+ return function(...args) {
933
+ if (limit !== null && queueSize >= limit) return lastCall;
934
+ queueSize++;
935
+ const prevCall = lastCall;
936
+ const invoke = () => func.apply(this, args);
937
+ return lastCall = (async () => {
938
+ try {
939
+ await prevCall.catch(() => {
940
+ });
941
+ return await invoke();
942
+ } finally {
943
+ queueSize--;
944
+ }
945
+ })();
946
+ };
947
+ }
948
+
701
949
  // src/ring-buffer.ts
702
950
  var RingBuffer = class {
703
951
  _buffer;
@@ -888,6 +1136,34 @@ var RetryDelayer = class {
888
1136
  this.cancelDelaysChanged.trigger();
889
1137
  }
890
1138
  };
1139
+
1140
+ // src/retry.ts
1141
+ var { warnLog } = getLogs("retry");
1142
+ var defaultRetryDelays = () => 50;
1143
+ async function retry(tryCount, fn, retryDelays = defaultRetryDelays) {
1144
+ if (tryCount <= 0)
1145
+ throw new Error("retry: tryCount must be positive.");
1146
+ let lastError;
1147
+ for (let tryIndex = 0; ; ) {
1148
+ if (tryIndex >= tryCount) throw lastError;
1149
+ try {
1150
+ return await fn(tryIndex, lastError);
1151
+ } catch (e) {
1152
+ lastError = e;
1153
+ }
1154
+ ++tryIndex;
1155
+ if (tryIndex >= tryCount) throw lastError;
1156
+ warnLog?.log(`retry(${tryIndex}/${tryCount}): error:`, lastError);
1157
+ await delayAsync(retryDelays(tryIndex));
1158
+ }
1159
+ }
1160
+ async function catchErrors(fn, onError) {
1161
+ try {
1162
+ return await fn();
1163
+ } catch (e) {
1164
+ return onError ? onError(e) : void 0;
1165
+ }
1166
+ }
891
1167
  // Annotate the CommonJS export names for ESM import in node:
892
1168
  0 && (module.exports = {
893
1169
  AsyncContext,
@@ -899,20 +1175,33 @@ var RetryDelayer = class {
899
1175
  LogLevel,
900
1176
  LogLevelController,
901
1177
  PromiseSource,
1178
+ PromiseSourceWithTimeout,
1179
+ ResolvedPromise,
902
1180
  Result,
903
1181
  RetryDelayLimitExceeded,
904
1182
  RetryDelayNone,
905
1183
  RetryDelaySeq,
906
1184
  RetryDelayer,
907
1185
  RingBuffer,
1186
+ TimedOut,
1187
+ TimeoutError,
1188
+ abortPromise,
908
1189
  abortSignalKey,
1190
+ catchErrors,
909
1191
  createLogProvider,
1192
+ debounce,
1193
+ delayAsync,
1194
+ delayAsyncWith,
910
1195
  errorResult,
911
1196
  initLogging,
912
1197
  initWorkerLogging,
913
1198
  resolvedVoidPromise,
914
1199
  result,
915
1200
  resultFrom,
916
- resultFromAsync
1201
+ resultFromAsync,
1202
+ retry,
1203
+ serialize,
1204
+ throttle,
1205
+ withTimeout
917
1206
  });
918
1207
  //# sourceMappingURL=index.cjs.map