@dxos/async 0.7.5-main.9d26e3a → 0.7.5-main.b19bfc8

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.
@@ -139,6 +139,7 @@ var EventSubscriptions = class {
139
139
  this._listeners.length = 0;
140
140
  }
141
141
  };
142
+ var DO_NOT_ERROR_ON_ASYNC_CALLBACK = true;
142
143
  var Event = class _Event {
143
144
  constructor() {
144
145
  this._listeners = /* @__PURE__ */ new Set();
@@ -167,7 +168,23 @@ var Event = class _Event {
167
168
  */
168
169
  emit(data) {
169
170
  for (const listener of this._listeners) {
170
- void listener.trigger(data);
171
+ listener.trigger(data);
172
+ if (listener.once) {
173
+ this._listeners.delete(listener);
174
+ }
175
+ }
176
+ }
177
+ /**
178
+ * Emit an event and wait for async listeners to complete.
179
+ * In most cases should only be called by the class or entity containing the event.
180
+ * All listeners are called in order of subscription with persistent ones first.
181
+ * Listeners are called sequentially.
182
+ *
183
+ * @param data param that will be passed to all listeners.
184
+ */
185
+ async emitAsync(data) {
186
+ for (const listener of this._listeners) {
187
+ await listener.triggerAsync(data);
171
188
  if (listener.once) {
172
189
  this._listeners.delete(listener);
173
190
  }
@@ -180,7 +197,7 @@ var Event = class _Event {
180
197
  ] : [
181
198
  new Context(void 0, {
182
199
  F: __dxlog_file,
183
- L: 124
200
+ L: 148
184
201
  }),
185
202
  _ctx
186
203
  ];
@@ -213,7 +230,7 @@ var Event = class _Event {
213
230
  ] : [
214
231
  new Context(void 0, {
215
232
  F: __dxlog_file,
216
- L: 161
233
+ L: 185
217
234
  }),
218
235
  _ctx
219
236
  ];
@@ -397,7 +414,21 @@ var EventListener = class {
397
414
  derefCallback() {
398
415
  return this.weak ? this.callback.deref() : this.callback;
399
416
  }
400
- async trigger(data) {
417
+ trigger(data) {
418
+ let result;
419
+ try {
420
+ const callback = this.derefCallback();
421
+ result = callback?.(data);
422
+ } catch (err) {
423
+ this.ctx.raise(err);
424
+ }
425
+ if (!DO_NOT_ERROR_ON_ASYNC_CALLBACK) {
426
+ if (result instanceof Promise) {
427
+ throw new TypeError("Event has async callbacks, use emitAsync instead");
428
+ }
429
+ }
430
+ }
431
+ async triggerAsync(data) {
401
432
  try {
402
433
  const callback = this.derefCallback();
403
434
  await callback?.(data);
@@ -476,6 +507,98 @@ var latch = ({ count = 1, timeout } = {}) => {
476
507
  ];
477
508
  };
478
509
 
510
+ // packages/common/async/src/mutex.ts
511
+ import "@dxos/util";
512
+ import { warnAfterTimeout } from "@dxos/debug";
513
+ var Mutex = class {
514
+ constructor() {
515
+ this._queue = Promise.resolve();
516
+ this._queueLength = 0;
517
+ this._tag = null;
518
+ }
519
+ get tag() {
520
+ return this._tag;
521
+ }
522
+ isLocked() {
523
+ return this._queueLength > 0;
524
+ }
525
+ /**
526
+ * Acquires the lock.
527
+ * Caller is responsible for releasing the lock using the returned callback.
528
+ * NOTE: Using `executeSynchronized` is preferred over using `acquire` directly.
529
+ * @returns Release callback
530
+ */
531
+ async acquire(tag) {
532
+ const prev = this._queue;
533
+ let guard;
534
+ this._queueLength++;
535
+ this._queue = new Promise((resolve) => {
536
+ guard = new MutexGuard(() => {
537
+ this._queueLength--;
538
+ this._tag = null;
539
+ resolve();
540
+ });
541
+ });
542
+ await prev;
543
+ if (tag !== void 0) {
544
+ this._tag = tag;
545
+ }
546
+ return guard;
547
+ }
548
+ /**
549
+ * Waits for all previous executions to complete and then executes a given function.
550
+ * Only a single function can be executed at a time.
551
+ * Function are executed in the same order as `executeSynchronized` is called.
552
+ * WARNING: Calling `executeSynchronized` inside of `executeSynchronized` on the same lock instance is a deadlock.
553
+ */
554
+ async executeSynchronized(fun) {
555
+ const guard = await this.acquire();
556
+ try {
557
+ return await fun();
558
+ } finally {
559
+ guard.release();
560
+ }
561
+ }
562
+ };
563
+ var MutexGuard = class {
564
+ constructor(_release) {
565
+ this._release = _release;
566
+ }
567
+ /**
568
+ * Releases the lock.
569
+ */
570
+ release() {
571
+ this._release();
572
+ }
573
+ [Symbol.dispose]() {
574
+ this.release();
575
+ }
576
+ };
577
+ var classMutexSymbol = Symbol("class-mutex");
578
+ var FORCE_DISABLE_WARNING = false;
579
+ var enableWarning = !FORCE_DISABLE_WARNING && globalThis.mochaExecutor;
580
+ var synchronized = (target, propertyName, descriptor) => {
581
+ const method = descriptor.value;
582
+ descriptor.value = async function synchronizedMethod(...args) {
583
+ const mutex = this[classMutexSymbol] ??= new Mutex();
584
+ const tag = `${target.constructor.name}.${propertyName}`;
585
+ let guard;
586
+ if (!enableWarning) {
587
+ guard = await mutex.acquire(tag);
588
+ } else {
589
+ guard = await warnAfterTimeout(1e4, `lock on ${tag} (taken by ${mutex.tag})`, () => mutex.acquire(tag));
590
+ }
591
+ try {
592
+ return await method.apply(this, args);
593
+ } finally {
594
+ guard.release();
595
+ }
596
+ };
597
+ Object.defineProperty(descriptor.value, "name", {
598
+ value: propertyName + "$synchronized"
599
+ });
600
+ };
601
+
479
602
  // packages/common/async/src/observable.ts
480
603
  import Observable from "zen-observable";
481
604
  import PushStream from "zen-push";
@@ -721,340 +844,93 @@ var CancellableObservableProvider = class extends ObservableProvider {
721
844
  }
722
845
  };
723
846
 
724
- // packages/common/async/src/mutex.ts
725
- import "@dxos/util";
726
- import { warnAfterTimeout } from "@dxos/debug";
727
- var Mutex = class {
728
- constructor() {
729
- this._queue = Promise.resolve();
730
- this._queueLength = 0;
731
- this._tag = null;
847
+ // packages/common/async/src/persistent-lifecycle.ts
848
+ import { LifecycleState, Resource, cancelWithContext } from "@dxos/context";
849
+ import { warnAfterTimeout as warnAfterTimeout2 } from "@dxos/debug";
850
+ import { log as log2 } from "@dxos/log";
851
+
852
+ // packages/common/async/src/task-scheduling.ts
853
+ import { ContextDisposedError as ContextDisposedError2 } from "@dxos/context";
854
+ import { StackTrace as StackTrace2 } from "@dxos/debug";
855
+
856
+ // packages/common/async/src/track-leaks.ts
857
+ import { StackTrace } from "@dxos/debug";
858
+ import { log } from "@dxos/log";
859
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/common/async/src/track-leaks.ts";
860
+ var enabled = typeof process !== "undefined" && !!process.env.DX_TRACK_LEAKS;
861
+ var openResources = /* @__PURE__ */ new Set();
862
+ var handleSymbol = Symbol("checkLeaksHandle");
863
+ var trackResource = (resourceProvider) => {
864
+ if (!enabled) {
865
+ return () => {
866
+ };
732
867
  }
733
- get tag() {
734
- return this._tag;
868
+ const resource = resourceProvider();
869
+ openResources.add(resource);
870
+ return () => {
871
+ openResources.delete(resource);
872
+ };
873
+ };
874
+ var trackLeaks = (open, close) => (target) => {
875
+ if (!enabled) {
876
+ return;
735
877
  }
736
- isLocked() {
737
- return this._queueLength > 0;
878
+ const openMethod = target.prototype[open];
879
+ const closeMethod = target.prototype[close];
880
+ if (!openMethod || !closeMethod) {
881
+ throw new Error(`Cannot find ${open} or ${close} method in ${target.name}`);
738
882
  }
739
- /**
740
- * Acquires the lock.
741
- * Caller is responsible for releasing the lock using the returned callback.
742
- * NOTE: Using `executeSynchronized` is preferred over using `acquire` directly.
743
- * @returns Release callback
744
- */
745
- async acquire(tag) {
746
- const prev = this._queue;
747
- let guard;
748
- this._queueLength++;
749
- this._queue = new Promise((resolve) => {
750
- guard = new MutexGuard(() => {
751
- this._queueLength--;
752
- this._tag = null;
753
- resolve();
754
- });
883
+ {
884
+ target.prototype[open] = async function(...args) {
885
+ this[handleSymbol] = trackResource(() => ({
886
+ name: target.name,
887
+ openStack: new StackTrace()
888
+ }));
889
+ return openMethod.apply(this, args);
890
+ };
891
+ Object.defineProperty(target.prototype[open], "name", {
892
+ value: open + "$checkLeaks"
755
893
  });
756
- await prev;
757
- if (tag !== void 0) {
758
- this._tag = tag;
759
- }
760
- return guard;
761
894
  }
762
- /**
763
- * Waits for all previous executions to complete and then executes a given function.
764
- * Only a single function can be executed at a time.
765
- * Function are executed in the same order as `executeSynchronized` is called.
766
- * WARNING: Calling `executeSynchronized` inside of `executeSynchronized` on the same lock instance is a deadlock.
767
- */
768
- async executeSynchronized(fun) {
769
- const guard = await this.acquire();
770
- try {
771
- return await fun();
772
- } finally {
773
- guard.release();
774
- }
895
+ {
896
+ target.prototype[close] = async function(...args) {
897
+ this[handleSymbol]?.();
898
+ return closeMethod.apply(this, args);
899
+ };
900
+ Object.defineProperty(target.prototype[close], "name", {
901
+ value: close + "$checkLeaks"
902
+ });
775
903
  }
776
904
  };
777
- var MutexGuard = class {
778
- constructor(_release) {
779
- this._release = _release;
780
- }
781
- /**
782
- * Releases the lock.
783
- */
784
- release() {
785
- this._release();
905
+ var dumpLeaks = () => {
906
+ if (!enabled) {
907
+ return;
786
908
  }
787
- [Symbol.dispose]() {
788
- this.release();
789
- }
790
- };
791
- var classMutexSymbol = Symbol("class-mutex");
792
- var FORCE_DISABLE_WARNING = false;
793
- var enableWarning = !FORCE_DISABLE_WARNING && globalThis.mochaExecutor;
794
- var synchronized = (target, propertyName, descriptor) => {
795
- const method = descriptor.value;
796
- descriptor.value = async function synchronizedMethod(...args) {
797
- const mutex = this[classMutexSymbol] ??= new Mutex();
798
- const tag = `${target.constructor.name}.${propertyName}`;
799
- let guard;
800
- if (!enableWarning) {
801
- guard = await mutex.acquire(tag);
802
- } else {
803
- guard = await warnAfterTimeout(1e4, `lock on ${tag} (taken by ${mutex.tag})`, () => mutex.acquire(tag));
804
- }
805
- try {
806
- return await method.apply(this, args);
807
- } finally {
808
- guard.release();
809
- }
810
- };
811
- Object.defineProperty(descriptor.value, "name", {
812
- value: propertyName + "$synchronized"
813
- });
814
- };
815
-
816
- // packages/common/async/src/sink.ts
817
- var sink = (emitter, event, count = 1) => {
818
- const [getPromise, resolve] = trigger();
819
- let counter = 0;
820
- const listener = () => {
821
- if (++counter === count) {
822
- emitter.off(event, listener);
823
- resolve();
824
- }
825
- };
826
- emitter.on(event, listener);
827
- return getPromise();
828
- };
829
-
830
- // packages/common/async/src/stream-to-array.ts
831
- var streamToArray = (stream) => {
832
- let deferred;
833
- if (!stream.readable) {
834
- deferred = Promise.resolve([]);
835
- } else {
836
- deferred = new Promise((resolve, reject) => {
837
- if (!stream.readable) {
838
- return resolve([]);
839
- }
840
- let arr = [];
841
- const onData = (doc) => {
842
- arr?.push(doc);
843
- };
844
- const onEnd = (err) => {
845
- if (err) {
846
- reject(err);
847
- } else {
848
- resolve(arr);
849
- }
850
- cleanup();
851
- };
852
- const onClose = () => {
853
- resolve(arr);
854
- cleanup();
855
- };
856
- const cleanup = () => {
857
- arr = [];
858
- stream.removeListener("data", onData);
859
- stream.removeListener("end", onEnd);
860
- stream.removeListener("error", onEnd);
861
- stream.removeListener("close", onClose);
862
- };
863
- stream.on("data", onData);
864
- stream.on("end", onEnd);
865
- stream.on("error", onEnd);
866
- stream.on("close", onClose);
867
- });
868
- }
869
- return deferred;
870
- };
871
-
872
- // packages/common/async/src/timer.ts
873
- var Timer = class {
874
- constructor(_callback) {
875
- this._callback = _callback;
876
- this._state = new Event();
877
- this._count = 0;
878
- }
879
- get state() {
880
- return this._state;
881
- }
882
- get running() {
883
- return !!this._timer;
884
- }
885
- start(options, cb) {
886
- if (isNaN(options.count) || isNaN(options.interval)) {
887
- throw new Error(`Invalid options: ${JSON.stringify(options)}`);
888
- }
889
- if (this.running) {
890
- this.stop();
891
- }
892
- const stop = () => {
893
- this.stop();
894
- cb?.();
895
- };
896
- const run = () => {
897
- if (this._count >= (options.count ?? 0)) {
898
- stop();
899
- } else {
900
- const interval = (options.interval ?? 0) + Math.random() * (options.jitter ?? 0);
901
- this._timer = setTimeout(async () => {
902
- await this._callback(this._count++);
903
- run();
904
- }, interval);
905
- }
906
- };
907
- this._state.emit(true);
908
- this._count = 0;
909
- setTimeout(run);
910
- return this;
911
- }
912
- stop() {
913
- clearInterval(this._timer);
914
- this._timer = void 0;
915
- this._state.emit(false);
916
- return this;
917
- }
918
- };
919
-
920
- // packages/common/async/src/testing.ts
921
- var waitForCondition = ({ condition, timeout = 0, interval = 10, error }) => {
922
- const stopTime = timeout ? Date.now() + timeout : 0;
923
- const trigger2 = new Trigger();
924
- const waiter = async () => {
925
- while (!stopTime || Date.now() < stopTime) {
926
- try {
927
- const value = await condition();
928
- if (value) {
929
- trigger2.wake(value);
930
- break;
931
- }
932
- } catch (err) {
933
- }
934
- await sleep(interval);
935
- }
936
- };
937
- setTimeout(waiter, 0);
938
- return timeout ? asyncTimeout(trigger2.wait(), timeout, error ?? new Error("Timeout")) : trigger2.wait();
939
- };
940
-
941
- // packages/common/async/src/until.ts
942
- var until = (cb, timeout) => {
943
- return new Promise((resolve, reject) => {
944
- const t = timeout && setTimeout(() => {
945
- reject(new Error(`Timeout after ${t}ms`));
946
- }, timeout);
947
- setTimeout(async () => {
948
- try {
949
- await cb((value) => {
950
- t && clearTimeout(t);
951
- resolve(value);
952
- }, (error) => {
953
- t && clearTimeout(t);
954
- reject(error);
955
- });
956
- } catch (err) {
957
- reject(err);
958
- }
959
- });
960
- });
961
- };
962
- var untilPromise = (cb) => cb();
963
- var untilError = (cb) => {
964
- return new Promise((resolve, reject) => {
965
- setTimeout(async () => {
966
- try {
967
- await cb();
968
- reject(new Error("No error was thrown."));
969
- } catch (err) {
970
- resolve(err);
971
- }
972
- });
973
- });
974
- };
975
-
976
- // packages/common/async/src/task-scheduling.ts
977
- import { ContextDisposedError as ContextDisposedError2 } from "@dxos/context";
978
- import { StackTrace as StackTrace2 } from "@dxos/debug";
979
-
980
- // packages/common/async/src/track-leaks.ts
981
- import { StackTrace } from "@dxos/debug";
982
- import { log } from "@dxos/log";
983
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/common/async/src/track-leaks.ts";
984
- var enabled = typeof process !== "undefined" && !!process.env.DX_TRACK_LEAKS;
985
- var openResources = /* @__PURE__ */ new Set();
986
- var handleSymbol = Symbol("checkLeaksHandle");
987
- var trackResource = (resourceProvider) => {
988
- if (!enabled) {
989
- return () => {
990
- };
991
- }
992
- const resource = resourceProvider();
993
- openResources.add(resource);
994
- return () => {
995
- openResources.delete(resource);
996
- };
997
- };
998
- var trackLeaks = (open, close) => (target) => {
999
- if (!enabled) {
1000
- return;
1001
- }
1002
- const openMethod = target.prototype[open];
1003
- const closeMethod = target.prototype[close];
1004
- if (!openMethod || !closeMethod) {
1005
- throw new Error(`Cannot find ${open} or ${close} method in ${target.name}`);
1006
- }
1007
- {
1008
- target.prototype[open] = async function(...args) {
1009
- this[handleSymbol] = trackResource(() => ({
1010
- name: target.name,
1011
- openStack: new StackTrace()
1012
- }));
1013
- return openMethod.apply(this, args);
1014
- };
1015
- Object.defineProperty(target.prototype[open], "name", {
1016
- value: open + "$checkLeaks"
1017
- });
1018
- }
1019
- {
1020
- target.prototype[close] = async function(...args) {
1021
- this[handleSymbol]?.();
1022
- return closeMethod.apply(this, args);
1023
- };
1024
- Object.defineProperty(target.prototype[close], "name", {
1025
- value: close + "$checkLeaks"
1026
- });
1027
- }
1028
- };
1029
- var dumpLeaks = () => {
1030
- if (!enabled) {
1031
- return;
1032
- }
1033
- log.info(`Leaked resources ${openResources.size}:`, void 0, {
1034
- F: __dxlog_file3,
1035
- L: 82,
1036
- S: void 0,
1037
- C: (f, a) => f(...a)
1038
- });
1039
- for (const resource of openResources) {
1040
- log.info(`- ${resource.name} at`, void 0, {
1041
- F: __dxlog_file3,
1042
- L: 84,
1043
- S: void 0,
1044
- C: (f, a) => f(...a)
1045
- });
1046
- log.info(resource.openStack.getStack(1), void 0, {
1047
- F: __dxlog_file3,
1048
- L: 85,
1049
- S: void 0,
1050
- C: (f, a) => f(...a)
1051
- });
1052
- log.info("\n", void 0, {
1053
- F: __dxlog_file3,
1054
- L: 86,
1055
- S: void 0,
1056
- C: (f, a) => f(...a)
1057
- });
909
+ log.info(`Leaked resources ${openResources.size}:`, void 0, {
910
+ F: __dxlog_file3,
911
+ L: 82,
912
+ S: void 0,
913
+ C: (f, a) => f(...a)
914
+ });
915
+ for (const resource of openResources) {
916
+ log.info(`- ${resource.name} at`, void 0, {
917
+ F: __dxlog_file3,
918
+ L: 84,
919
+ S: void 0,
920
+ C: (f, a) => f(...a)
921
+ });
922
+ log.info(resource.openStack.getStack(1), void 0, {
923
+ F: __dxlog_file3,
924
+ L: 85,
925
+ S: void 0,
926
+ C: (f, a) => f(...a)
927
+ });
928
+ log.info("\n", void 0, {
929
+ F: __dxlog_file3,
930
+ L: 86,
931
+ S: void 0,
932
+ C: (f, a) => f(...a)
933
+ });
1058
934
  }
1059
935
  };
1060
936
  if (enabled) {
@@ -1070,6 +946,9 @@ var DeferredTask = class {
1070
946
  this._currentTask = null;
1071
947
  this._nextTask = new Trigger();
1072
948
  }
949
+ get scheduled() {
950
+ return this._scheduled;
951
+ }
1073
952
  /**
1074
953
  * Schedule the task to run asynchronously.
1075
954
  */
@@ -1184,6 +1063,173 @@ var scheduleExponentialBackoffTaskInterval = (ctx, task, initialInterval) => {
1184
1063
  });
1185
1064
  };
1186
1065
 
1066
+ // packages/common/async/src/persistent-lifecycle.ts
1067
+ function _ts_decorate(decorators, target, key, desc) {
1068
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1069
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1070
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1071
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1072
+ }
1073
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/common/async/src/persistent-lifecycle.ts";
1074
+ var INIT_RESTART_DELAY = 100;
1075
+ var DEFAULT_MAX_RESTART_DELAY = 5e3;
1076
+ var PersistentLifecycle = class extends Resource {
1077
+ constructor({ start, stop, onRestart, maxRestartDelay = DEFAULT_MAX_RESTART_DELAY }) {
1078
+ super();
1079
+ this._currentState = void 0;
1080
+ this._restartTask = void 0;
1081
+ this._restartAfter = 0;
1082
+ this._start = start;
1083
+ this._stop = stop;
1084
+ this._onRestart = onRestart;
1085
+ this._maxRestartDelay = maxRestartDelay;
1086
+ }
1087
+ get state() {
1088
+ return this._currentState;
1089
+ }
1090
+ async _open() {
1091
+ this._restartTask = new DeferredTask(this._ctx, async () => {
1092
+ try {
1093
+ await this._restart();
1094
+ } catch (err) {
1095
+ log2.warn("Restart failed", {
1096
+ err
1097
+ }, {
1098
+ F: __dxlog_file4,
1099
+ L: 72,
1100
+ S: this,
1101
+ C: (f, a) => f(...a)
1102
+ });
1103
+ this._restartTask?.schedule();
1104
+ }
1105
+ });
1106
+ this._currentState = await this._start().catch((err) => {
1107
+ log2.warn("Start failed", {
1108
+ err
1109
+ }, {
1110
+ F: __dxlog_file4,
1111
+ L: 77,
1112
+ S: this,
1113
+ C: (f, a) => f(...a)
1114
+ });
1115
+ this._restartTask?.schedule();
1116
+ return void 0;
1117
+ });
1118
+ }
1119
+ async _close() {
1120
+ await this._restartTask?.join();
1121
+ await this._stopCurrentState();
1122
+ this._restartTask = void 0;
1123
+ }
1124
+ async _restart() {
1125
+ log2(`restarting in ${this._restartAfter}ms`, {
1126
+ state: this._lifecycleState
1127
+ }, {
1128
+ F: __dxlog_file4,
1129
+ L: 90,
1130
+ S: this,
1131
+ C: (f, a) => f(...a)
1132
+ });
1133
+ await this._stopCurrentState();
1134
+ if (this._lifecycleState !== LifecycleState.OPEN) {
1135
+ return;
1136
+ }
1137
+ await cancelWithContext(this._ctx, sleep(this._restartAfter));
1138
+ this._restartAfter = Math.min(Math.max(this._restartAfter * 2, INIT_RESTART_DELAY), this._maxRestartDelay);
1139
+ await warnAfterTimeout2(5e3, "Connection establishment takes too long", async () => {
1140
+ this._currentState = await this._start();
1141
+ });
1142
+ this._restartAfter = 0;
1143
+ await this._onRestart?.();
1144
+ }
1145
+ async _stopCurrentState() {
1146
+ if (this._currentState) {
1147
+ try {
1148
+ await this._stop(this._currentState);
1149
+ } catch (err) {
1150
+ log2.catch(err, void 0, {
1151
+ F: __dxlog_file4,
1152
+ L: 112,
1153
+ S: this,
1154
+ C: (f, a) => f(...a)
1155
+ });
1156
+ }
1157
+ this._currentState = void 0;
1158
+ }
1159
+ }
1160
+ /**
1161
+ * Scheduling restart should be done from outside.
1162
+ */
1163
+ scheduleRestart() {
1164
+ if (this._lifecycleState !== LifecycleState.OPEN) {
1165
+ return;
1166
+ }
1167
+ this._restartTask.schedule();
1168
+ }
1169
+ };
1170
+ _ts_decorate([
1171
+ synchronized
1172
+ ], PersistentLifecycle.prototype, "_open", null);
1173
+ _ts_decorate([
1174
+ synchronized
1175
+ ], PersistentLifecycle.prototype, "scheduleRestart", null);
1176
+
1177
+ // packages/common/async/src/sink.ts
1178
+ var sink = (emitter, event, count = 1) => {
1179
+ const [getPromise, resolve] = trigger();
1180
+ let counter = 0;
1181
+ const listener = () => {
1182
+ if (++counter === count) {
1183
+ emitter.off(event, listener);
1184
+ resolve();
1185
+ }
1186
+ };
1187
+ emitter.on(event, listener);
1188
+ return getPromise();
1189
+ };
1190
+
1191
+ // packages/common/async/src/stream-to-array.ts
1192
+ var streamToArray = (stream) => {
1193
+ let deferred;
1194
+ if (!stream.readable) {
1195
+ deferred = Promise.resolve([]);
1196
+ } else {
1197
+ deferred = new Promise((resolve, reject) => {
1198
+ if (!stream.readable) {
1199
+ return resolve([]);
1200
+ }
1201
+ let arr = [];
1202
+ const onData = (doc) => {
1203
+ arr?.push(doc);
1204
+ };
1205
+ const onEnd = (err) => {
1206
+ if (err) {
1207
+ reject(err);
1208
+ } else {
1209
+ resolve(arr);
1210
+ }
1211
+ cleanup();
1212
+ };
1213
+ const onClose = () => {
1214
+ resolve(arr);
1215
+ cleanup();
1216
+ };
1217
+ const cleanup = () => {
1218
+ arr = [];
1219
+ stream.removeListener("data", onData);
1220
+ stream.removeListener("end", onEnd);
1221
+ stream.removeListener("error", onEnd);
1222
+ stream.removeListener("close", onClose);
1223
+ };
1224
+ stream.on("data", onData);
1225
+ stream.on("end", onEnd);
1226
+ stream.on("error", onEnd);
1227
+ stream.on("close", onClose);
1228
+ });
1229
+ }
1230
+ return deferred;
1231
+ };
1232
+
1187
1233
  // packages/common/async/src/test-stream.ts
1188
1234
  import { Duplex } from "node:stream";
1189
1235
  var TestStream = class extends Duplex {
@@ -1220,6 +1266,110 @@ var TestStream = class extends Duplex {
1220
1266
  }
1221
1267
  };
1222
1268
 
1269
+ // packages/common/async/src/testing.ts
1270
+ var waitForCondition = ({ condition, timeout = 0, interval = 10, error }) => {
1271
+ const stopTime = timeout ? Date.now() + timeout : 0;
1272
+ const trigger2 = new Trigger();
1273
+ const waiter = async () => {
1274
+ while (!stopTime || Date.now() < stopTime) {
1275
+ try {
1276
+ const value = await condition();
1277
+ if (value) {
1278
+ trigger2.wake(value);
1279
+ break;
1280
+ }
1281
+ } catch (err) {
1282
+ }
1283
+ await sleep(interval);
1284
+ }
1285
+ };
1286
+ setTimeout(waiter, 0);
1287
+ return timeout ? asyncTimeout(trigger2.wait(), timeout, error ?? new Error("Timeout")) : trigger2.wait();
1288
+ };
1289
+
1290
+ // packages/common/async/src/timer.ts
1291
+ var Timer = class {
1292
+ constructor(_callback) {
1293
+ this._callback = _callback;
1294
+ this._state = new Event();
1295
+ this._count = 0;
1296
+ }
1297
+ get state() {
1298
+ return this._state;
1299
+ }
1300
+ get running() {
1301
+ return !!this._timer;
1302
+ }
1303
+ start(options, cb) {
1304
+ if (isNaN(options.count) || isNaN(options.interval)) {
1305
+ throw new Error(`Invalid options: ${JSON.stringify(options)}`);
1306
+ }
1307
+ if (this.running) {
1308
+ this.stop();
1309
+ }
1310
+ const stop = () => {
1311
+ this.stop();
1312
+ cb?.();
1313
+ };
1314
+ const run = () => {
1315
+ if (this._count >= (options.count ?? 0)) {
1316
+ stop();
1317
+ } else {
1318
+ const interval = (options.interval ?? 0) + Math.random() * (options.jitter ?? 0);
1319
+ this._timer = setTimeout(async () => {
1320
+ await this._callback(this._count++);
1321
+ run();
1322
+ }, interval);
1323
+ }
1324
+ };
1325
+ this._state.emit(true);
1326
+ this._count = 0;
1327
+ setTimeout(run);
1328
+ return this;
1329
+ }
1330
+ stop() {
1331
+ clearInterval(this._timer);
1332
+ this._timer = void 0;
1333
+ this._state.emit(false);
1334
+ return this;
1335
+ }
1336
+ };
1337
+
1338
+ // packages/common/async/src/until.ts
1339
+ var until = (cb, timeout) => {
1340
+ return new Promise((resolve, reject) => {
1341
+ const t = timeout && setTimeout(() => {
1342
+ reject(new Error(`Timeout after ${t}ms`));
1343
+ }, timeout);
1344
+ setTimeout(async () => {
1345
+ try {
1346
+ await cb((value) => {
1347
+ t && clearTimeout(t);
1348
+ resolve(value);
1349
+ }, (error) => {
1350
+ t && clearTimeout(t);
1351
+ reject(error);
1352
+ });
1353
+ } catch (err) {
1354
+ reject(err);
1355
+ }
1356
+ });
1357
+ });
1358
+ };
1359
+ var untilPromise = (cb) => cb();
1360
+ var untilError = (cb) => {
1361
+ return new Promise((resolve, reject) => {
1362
+ setTimeout(async () => {
1363
+ try {
1364
+ await cb();
1365
+ reject(new Error("No error was thrown."));
1366
+ } catch (err) {
1367
+ resolve(err);
1368
+ }
1369
+ });
1370
+ });
1371
+ };
1372
+
1223
1373
  // packages/common/async/src/update-scheduler.ts
1224
1374
  var TIME_PERIOD = 1e3;
1225
1375
  var UpdateScheduler = class {
@@ -1301,6 +1451,7 @@ export {
1301
1451
  MutexGuard,
1302
1452
  Observable,
1303
1453
  ObservableProvider,
1454
+ PersistentLifecycle,
1304
1455
  PushStream,
1305
1456
  TestStream,
1306
1457
  TimeoutError,