@dxos/async 0.7.5-labs.e27f9b9 → 0.7.5-labs.f400bbc

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.
@@ -505,6 +505,98 @@ var latch = ({ count = 1, timeout } = {}) => {
505
505
  ];
506
506
  };
507
507
 
508
+ // packages/common/async/src/mutex.ts
509
+ import "@dxos/util";
510
+ import { warnAfterTimeout } from "@dxos/debug";
511
+ var Mutex = class {
512
+ constructor() {
513
+ this._queue = Promise.resolve();
514
+ this._queueLength = 0;
515
+ this._tag = null;
516
+ }
517
+ get tag() {
518
+ return this._tag;
519
+ }
520
+ isLocked() {
521
+ return this._queueLength > 0;
522
+ }
523
+ /**
524
+ * Acquires the lock.
525
+ * Caller is responsible for releasing the lock using the returned callback.
526
+ * NOTE: Using `executeSynchronized` is preferred over using `acquire` directly.
527
+ * @returns Release callback
528
+ */
529
+ async acquire(tag) {
530
+ const prev = this._queue;
531
+ let guard;
532
+ this._queueLength++;
533
+ this._queue = new Promise((resolve) => {
534
+ guard = new MutexGuard(() => {
535
+ this._queueLength--;
536
+ this._tag = null;
537
+ resolve();
538
+ });
539
+ });
540
+ await prev;
541
+ if (tag !== void 0) {
542
+ this._tag = tag;
543
+ }
544
+ return guard;
545
+ }
546
+ /**
547
+ * Waits for all previous executions to complete and then executes a given function.
548
+ * Only a single function can be executed at a time.
549
+ * Function are executed in the same order as `executeSynchronized` is called.
550
+ * WARNING: Calling `executeSynchronized` inside of `executeSynchronized` on the same lock instance is a deadlock.
551
+ */
552
+ async executeSynchronized(fun) {
553
+ const guard = await this.acquire();
554
+ try {
555
+ return await fun();
556
+ } finally {
557
+ guard.release();
558
+ }
559
+ }
560
+ };
561
+ var MutexGuard = class {
562
+ constructor(_release) {
563
+ this._release = _release;
564
+ }
565
+ /**
566
+ * Releases the lock.
567
+ */
568
+ release() {
569
+ this._release();
570
+ }
571
+ [Symbol.dispose]() {
572
+ this.release();
573
+ }
574
+ };
575
+ var classMutexSymbol = Symbol("class-mutex");
576
+ var FORCE_DISABLE_WARNING = false;
577
+ var enableWarning = !FORCE_DISABLE_WARNING && globalThis.mochaExecutor;
578
+ var synchronized = (target, propertyName, descriptor) => {
579
+ const method = descriptor.value;
580
+ descriptor.value = async function synchronizedMethod(...args) {
581
+ const mutex = this[classMutexSymbol] ??= new Mutex();
582
+ const tag = `${target.constructor.name}.${propertyName}`;
583
+ let guard;
584
+ if (!enableWarning) {
585
+ guard = await mutex.acquire(tag);
586
+ } else {
587
+ guard = await warnAfterTimeout(1e4, `lock on ${tag} (taken by ${mutex.tag})`, () => mutex.acquire(tag));
588
+ }
589
+ try {
590
+ return await method.apply(this, args);
591
+ } finally {
592
+ guard.release();
593
+ }
594
+ };
595
+ Object.defineProperty(descriptor.value, "name", {
596
+ value: propertyName + "$synchronized"
597
+ });
598
+ };
599
+
508
600
  // packages/common/async/src/observable.ts
509
601
  import Observable from "zen-observable";
510
602
  import PushStream from "zen-push";
@@ -750,98 +842,336 @@ var CancellableObservableProvider = class extends ObservableProvider {
750
842
  }
751
843
  };
752
844
 
753
- // packages/common/async/src/mutex.ts
754
- import "@dxos/util";
755
- import { warnAfterTimeout } from "@dxos/debug";
756
- var Mutex = class {
757
- constructor() {
758
- this._queue = Promise.resolve();
759
- this._queueLength = 0;
760
- this._tag = null;
845
+ // packages/common/async/src/persistent-lifecycle.ts
846
+ import { LifecycleState, Resource, cancelWithContext } from "@dxos/context";
847
+ import { warnAfterTimeout as warnAfterTimeout2 } from "@dxos/debug";
848
+ import { log as log2 } from "@dxos/log";
849
+
850
+ // packages/common/async/src/task-scheduling.ts
851
+ import { ContextDisposedError as ContextDisposedError2 } from "@dxos/context";
852
+ import { StackTrace as StackTrace2 } from "@dxos/debug";
853
+
854
+ // packages/common/async/src/track-leaks.ts
855
+ import { StackTrace } from "@dxos/debug";
856
+ import { log } from "@dxos/log";
857
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/common/async/src/track-leaks.ts";
858
+ var enabled = typeof process !== "undefined" && !!process.env.DX_TRACK_LEAKS;
859
+ var openResources = /* @__PURE__ */ new Set();
860
+ var handleSymbol = Symbol("checkLeaksHandle");
861
+ var trackResource = (resourceProvider) => {
862
+ if (!enabled) {
863
+ return () => {
864
+ };
761
865
  }
762
- get tag() {
763
- return this._tag;
866
+ const resource = resourceProvider();
867
+ openResources.add(resource);
868
+ return () => {
869
+ openResources.delete(resource);
870
+ };
871
+ };
872
+ var trackLeaks = (open, close) => (target) => {
873
+ if (!enabled) {
874
+ return;
764
875
  }
765
- isLocked() {
766
- return this._queueLength > 0;
876
+ const openMethod = target.prototype[open];
877
+ const closeMethod = target.prototype[close];
878
+ if (!openMethod || !closeMethod) {
879
+ throw new Error(`Cannot find ${open} or ${close} method in ${target.name}`);
880
+ }
881
+ {
882
+ target.prototype[open] = async function(...args) {
883
+ this[handleSymbol] = trackResource(() => ({
884
+ name: target.name,
885
+ openStack: new StackTrace()
886
+ }));
887
+ return openMethod.apply(this, args);
888
+ };
889
+ Object.defineProperty(target.prototype[open], "name", {
890
+ value: open + "$checkLeaks"
891
+ });
892
+ }
893
+ {
894
+ target.prototype[close] = async function(...args) {
895
+ this[handleSymbol]?.();
896
+ return closeMethod.apply(this, args);
897
+ };
898
+ Object.defineProperty(target.prototype[close], "name", {
899
+ value: close + "$checkLeaks"
900
+ });
901
+ }
902
+ };
903
+ var dumpLeaks = () => {
904
+ if (!enabled) {
905
+ return;
906
+ }
907
+ log.info(`Leaked resources ${openResources.size}:`, void 0, {
908
+ F: __dxlog_file3,
909
+ L: 82,
910
+ S: void 0,
911
+ C: (f, a) => f(...a)
912
+ });
913
+ for (const resource of openResources) {
914
+ log.info(`- ${resource.name} at`, void 0, {
915
+ F: __dxlog_file3,
916
+ L: 84,
917
+ S: void 0,
918
+ C: (f, a) => f(...a)
919
+ });
920
+ log.info(resource.openStack.getStack(1), void 0, {
921
+ F: __dxlog_file3,
922
+ L: 85,
923
+ S: void 0,
924
+ C: (f, a) => f(...a)
925
+ });
926
+ log.info("\n", void 0, {
927
+ F: __dxlog_file3,
928
+ L: 86,
929
+ S: void 0,
930
+ C: (f, a) => f(...a)
931
+ });
932
+ }
933
+ };
934
+ if (enabled) {
935
+ global.dxDumpLeaks = dumpLeaks;
936
+ }
937
+
938
+ // packages/common/async/src/task-scheduling.ts
939
+ var DeferredTask = class {
940
+ constructor(_ctx, _callback) {
941
+ this._ctx = _ctx;
942
+ this._callback = _callback;
943
+ this._scheduled = false;
944
+ this._currentTask = null;
945
+ this._nextTask = new Trigger();
946
+ }
947
+ get scheduled() {
948
+ return this._scheduled;
767
949
  }
768
950
  /**
769
- * Acquires the lock.
770
- * Caller is responsible for releasing the lock using the returned callback.
771
- * NOTE: Using `executeSynchronized` is preferred over using `acquire` directly.
772
- * @returns Release callback
951
+ * Schedule the task to run asynchronously.
773
952
  */
774
- async acquire(tag) {
775
- const prev = this._queue;
776
- let guard;
777
- this._queueLength++;
778
- this._queue = new Promise((resolve) => {
779
- guard = new MutexGuard(() => {
780
- this._queueLength--;
781
- this._tag = null;
782
- resolve();
953
+ schedule() {
954
+ if (this._scheduled) {
955
+ return;
956
+ }
957
+ scheduleTask(this._ctx, async () => {
958
+ await this._currentTask;
959
+ this._scheduled = false;
960
+ const completionTrigger = this._nextTask;
961
+ this._nextTask = new Trigger();
962
+ this._currentTask = runInContextAsync(this._ctx, () => this._callback()).then(() => {
963
+ completionTrigger.wake();
783
964
  });
784
965
  });
785
- await prev;
786
- if (tag !== void 0) {
787
- this._tag = tag;
788
- }
789
- return guard;
966
+ this._scheduled = true;
790
967
  }
791
968
  /**
792
- * Waits for all previous executions to complete and then executes a given function.
793
- * Only a single function can be executed at a time.
794
- * Function are executed in the same order as `executeSynchronized` is called.
795
- * WARNING: Calling `executeSynchronized` inside of `executeSynchronized` on the same lock instance is a deadlock.
969
+ * Schedule the task to run and wait for it to finish.
796
970
  */
797
- async executeSynchronized(fun) {
798
- const guard = await this.acquire();
799
- try {
800
- return await fun();
801
- } finally {
802
- guard.release();
971
+ async runBlocking() {
972
+ if (this._ctx.disposed) {
973
+ throw new ContextDisposedError2();
803
974
  }
804
- }
805
- };
806
- var MutexGuard = class {
807
- constructor(_release) {
808
- this._release = _release;
975
+ this.schedule();
976
+ await this._nextTask.wait();
809
977
  }
810
978
  /**
811
- * Releases the lock.
979
+ * Waits for the current task to finish if it is running.
980
+ * Does not schedule a new task.
812
981
  */
813
- release() {
814
- this._release();
982
+ async join() {
983
+ await this._currentTask;
815
984
  }
816
- [Symbol.dispose]() {
817
- this.release();
985
+ };
986
+ var runInContext = (ctx, fn) => {
987
+ try {
988
+ fn();
989
+ } catch (err) {
990
+ ctx.raise(err);
818
991
  }
819
992
  };
820
- var classMutexSymbol = Symbol("class-mutex");
821
- var FORCE_DISABLE_WARNING = false;
822
- var enableWarning = !FORCE_DISABLE_WARNING && globalThis.mochaExecutor;
823
- var synchronized = (target, propertyName, descriptor) => {
824
- const method = descriptor.value;
825
- descriptor.value = async function synchronizedMethod(...args) {
826
- const mutex = this[classMutexSymbol] ??= new Mutex();
827
- const tag = `${target.constructor.name}.${propertyName}`;
828
- let guard;
829
- if (!enableWarning) {
830
- guard = await mutex.acquire(tag);
831
- } else {
832
- guard = await warnAfterTimeout(1e4, `lock on ${tag} (taken by ${mutex.tag})`, () => mutex.acquire(tag));
993
+ var runInContextAsync = async (ctx, fn) => {
994
+ try {
995
+ await fn();
996
+ } catch (err) {
997
+ ctx.raise(err);
998
+ }
999
+ };
1000
+ var scheduleMicroTask = (ctx, fn) => {
1001
+ queueMicrotask(async () => {
1002
+ if (ctx.disposed) {
1003
+ return;
833
1004
  }
834
- try {
835
- return await method.apply(this, args);
836
- } finally {
837
- guard.release();
1005
+ await runInContextAsync(ctx, fn);
1006
+ });
1007
+ };
1008
+ var scheduleTask = (ctx, fn, afterMs) => {
1009
+ const clearTracking = trackResource(() => ({
1010
+ name: `task (${fn.name || "anonymous"})`,
1011
+ openStack: new StackTrace2()
1012
+ }));
1013
+ const timeout = setTimeout(async () => {
1014
+ clearDispose();
1015
+ await runInContextAsync(ctx, fn);
1016
+ clearTracking();
1017
+ }, afterMs);
1018
+ const clearDispose = ctx.onDispose(() => {
1019
+ clearTracking();
1020
+ clearTimeout(timeout);
1021
+ });
1022
+ };
1023
+ var scheduleTaskInterval = (ctx, task, interval) => {
1024
+ const clearTracking = trackResource(() => ({
1025
+ name: `repeating task (${task.name || "anonymous"})`,
1026
+ openStack: new StackTrace2()
1027
+ }));
1028
+ let timeoutId;
1029
+ const run = async () => {
1030
+ await runInContextAsync(ctx, task);
1031
+ if (ctx.disposed) {
1032
+ return;
838
1033
  }
1034
+ timeoutId = setTimeout(run, interval);
839
1035
  };
840
- Object.defineProperty(descriptor.value, "name", {
841
- value: propertyName + "$synchronized"
1036
+ timeoutId = setTimeout(run, interval);
1037
+ ctx.onDispose(() => {
1038
+ clearTracking();
1039
+ clearTimeout(timeoutId);
1040
+ });
1041
+ };
1042
+ var scheduleExponentialBackoffTaskInterval = (ctx, task, initialInterval) => {
1043
+ const clearTracking = trackResource(() => ({
1044
+ name: `repeating task (${task.name || "anonymous"})`,
1045
+ openStack: new StackTrace2()
1046
+ }));
1047
+ let timeoutId;
1048
+ let interval = initialInterval;
1049
+ const repeat = async () => {
1050
+ await runInContextAsync(ctx, task);
1051
+ if (ctx.disposed) {
1052
+ return;
1053
+ }
1054
+ interval *= 2;
1055
+ timeoutId = setTimeout(repeat, interval);
1056
+ };
1057
+ timeoutId = setTimeout(repeat, interval);
1058
+ ctx.onDispose(() => {
1059
+ clearTracking();
1060
+ clearTimeout(timeoutId);
842
1061
  });
843
1062
  };
844
1063
 
1064
+ // packages/common/async/src/persistent-lifecycle.ts
1065
+ function _ts_decorate(decorators, target, key, desc) {
1066
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1067
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1068
+ 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;
1069
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1070
+ }
1071
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/common/async/src/persistent-lifecycle.ts";
1072
+ var INIT_RESTART_DELAY = 100;
1073
+ var DEFAULT_MAX_RESTART_DELAY = 5e3;
1074
+ var PersistentLifecycle = class extends Resource {
1075
+ constructor({ start, stop, onRestart, maxRestartDelay = DEFAULT_MAX_RESTART_DELAY }) {
1076
+ super();
1077
+ this._currentState = void 0;
1078
+ this._restartTask = void 0;
1079
+ this._restartAfter = 0;
1080
+ this._start = start;
1081
+ this._stop = stop;
1082
+ this._onRestart = onRestart;
1083
+ this._maxRestartDelay = maxRestartDelay;
1084
+ }
1085
+ get state() {
1086
+ return this._currentState;
1087
+ }
1088
+ async _open() {
1089
+ this._restartTask = new DeferredTask(this._ctx, async () => {
1090
+ try {
1091
+ await this._restart();
1092
+ } catch (err) {
1093
+ log2.warn("Restart failed", {
1094
+ err
1095
+ }, {
1096
+ F: __dxlog_file4,
1097
+ L: 72,
1098
+ S: this,
1099
+ C: (f, a) => f(...a)
1100
+ });
1101
+ this._restartTask?.schedule();
1102
+ }
1103
+ });
1104
+ this._currentState = await this._start().catch((err) => {
1105
+ log2.warn("Start failed", {
1106
+ err
1107
+ }, {
1108
+ F: __dxlog_file4,
1109
+ L: 77,
1110
+ S: this,
1111
+ C: (f, a) => f(...a)
1112
+ });
1113
+ this._restartTask?.schedule();
1114
+ return void 0;
1115
+ });
1116
+ }
1117
+ async _close() {
1118
+ await this._restartTask?.join();
1119
+ await this._stopCurrentState();
1120
+ this._restartTask = void 0;
1121
+ }
1122
+ async _restart() {
1123
+ log2(`restarting in ${this._restartAfter}ms`, {
1124
+ state: this._lifecycleState
1125
+ }, {
1126
+ F: __dxlog_file4,
1127
+ L: 90,
1128
+ S: this,
1129
+ C: (f, a) => f(...a)
1130
+ });
1131
+ await this._stopCurrentState();
1132
+ if (this._lifecycleState !== LifecycleState.OPEN) {
1133
+ return;
1134
+ }
1135
+ await cancelWithContext(this._ctx, sleep(this._restartAfter));
1136
+ this._restartAfter = Math.min(Math.max(this._restartAfter * 2, INIT_RESTART_DELAY), this._maxRestartDelay);
1137
+ await warnAfterTimeout2(5e3, "Connection establishment takes too long", async () => {
1138
+ this._currentState = await this._start();
1139
+ });
1140
+ this._restartAfter = 0;
1141
+ await this._onRestart?.();
1142
+ }
1143
+ async _stopCurrentState() {
1144
+ if (this._currentState) {
1145
+ try {
1146
+ await this._stop(this._currentState);
1147
+ } catch (err) {
1148
+ log2.catch(err, void 0, {
1149
+ F: __dxlog_file4,
1150
+ L: 112,
1151
+ S: this,
1152
+ C: (f, a) => f(...a)
1153
+ });
1154
+ }
1155
+ this._currentState = void 0;
1156
+ }
1157
+ }
1158
+ /**
1159
+ * Scheduling restart should be done from outside.
1160
+ */
1161
+ scheduleRestart() {
1162
+ if (this._lifecycleState !== LifecycleState.OPEN) {
1163
+ return;
1164
+ }
1165
+ this._restartTask.schedule();
1166
+ }
1167
+ };
1168
+ _ts_decorate([
1169
+ synchronized
1170
+ ], PersistentLifecycle.prototype, "_open", null);
1171
+ _ts_decorate([
1172
+ synchronized
1173
+ ], PersistentLifecycle.prototype, "scheduleRestart", null);
1174
+
845
1175
  // packages/common/async/src/sink.ts
846
1176
  var sink = (emitter, event, count = 1) => {
847
1177
  const [getPromise, resolve] = trigger();
@@ -898,6 +1228,63 @@ var streamToArray = (stream) => {
898
1228
  return deferred;
899
1229
  };
900
1230
 
1231
+ // packages/common/async/src/test-stream.ts
1232
+ import { Duplex } from "@dxos/node-std/stream";
1233
+ var TestStream = class extends Duplex {
1234
+ constructor() {
1235
+ super(...arguments);
1236
+ this._received = Buffer.alloc(0);
1237
+ this._onWrite = new Event();
1238
+ }
1239
+ static async assertConnectivity(stream1, stream2, { timeout = 200 } = {}) {
1240
+ stream1.push("ping");
1241
+ stream2.push("pong");
1242
+ await Promise.all([
1243
+ stream2.assertReceivedAsync("ping", {
1244
+ timeout
1245
+ }),
1246
+ stream1.assertReceivedAsync("pong", {
1247
+ timeout
1248
+ })
1249
+ ]);
1250
+ }
1251
+ _write(chunk, encoding, callback) {
1252
+ this._received = Buffer.concat([
1253
+ this._received,
1254
+ chunk
1255
+ ]);
1256
+ this._onWrite.emit();
1257
+ callback();
1258
+ }
1259
+ _read(size) {
1260
+ }
1261
+ assertReceivedAsync(data, { timeout = 200 } = {}) {
1262
+ const dataBuffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
1263
+ return asyncTimeout(this._onWrite.waitForCondition(() => this._received.equals(dataBuffer)), timeout);
1264
+ }
1265
+ };
1266
+
1267
+ // packages/common/async/src/testing.ts
1268
+ var waitForCondition = ({ condition, timeout = 0, interval = 10, error }) => {
1269
+ const stopTime = timeout ? Date.now() + timeout : 0;
1270
+ const trigger2 = new Trigger();
1271
+ const waiter = async () => {
1272
+ while (!stopTime || Date.now() < stopTime) {
1273
+ try {
1274
+ const value = await condition();
1275
+ if (value) {
1276
+ trigger2.wake(value);
1277
+ break;
1278
+ }
1279
+ } catch (err) {
1280
+ }
1281
+ await sleep(interval);
1282
+ }
1283
+ };
1284
+ setTimeout(waiter, 0);
1285
+ return timeout ? asyncTimeout(trigger2.wait(), timeout, error ?? new Error("Timeout")) : trigger2.wait();
1286
+ };
1287
+
901
1288
  // packages/common/async/src/timer.ts
902
1289
  var Timer = class {
903
1290
  constructor(_callback) {
@@ -946,27 +1333,6 @@ var Timer = class {
946
1333
  }
947
1334
  };
948
1335
 
949
- // packages/common/async/src/testing.ts
950
- var waitForCondition = ({ condition, timeout = 0, interval = 10, error }) => {
951
- const stopTime = timeout ? Date.now() + timeout : 0;
952
- const trigger2 = new Trigger();
953
- const waiter = async () => {
954
- while (!stopTime || Date.now() < stopTime) {
955
- try {
956
- const value = await condition();
957
- if (value) {
958
- trigger2.wake(value);
959
- break;
960
- }
961
- } catch (err) {
962
- }
963
- await sleep(interval);
964
- }
965
- };
966
- setTimeout(waiter, 0);
967
- return timeout ? asyncTimeout(trigger2.wait(), timeout, error ?? new Error("Timeout")) : trigger2.wait();
968
- };
969
-
970
1336
  // packages/common/async/src/until.ts
971
1337
  var until = (cb, timeout) => {
972
1338
  return new Promise((resolve, reject) => {
@@ -1002,253 +1368,6 @@ var untilError = (cb) => {
1002
1368
  });
1003
1369
  };
1004
1370
 
1005
- // packages/common/async/src/task-scheduling.ts
1006
- import { ContextDisposedError as ContextDisposedError2 } from "@dxos/context";
1007
- import { StackTrace as StackTrace2 } from "@dxos/debug";
1008
-
1009
- // packages/common/async/src/track-leaks.ts
1010
- import { StackTrace } from "@dxos/debug";
1011
- import { log } from "@dxos/log";
1012
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/common/async/src/track-leaks.ts";
1013
- var enabled = typeof process !== "undefined" && !!process.env.DX_TRACK_LEAKS;
1014
- var openResources = /* @__PURE__ */ new Set();
1015
- var handleSymbol = Symbol("checkLeaksHandle");
1016
- var trackResource = (resourceProvider) => {
1017
- if (!enabled) {
1018
- return () => {
1019
- };
1020
- }
1021
- const resource = resourceProvider();
1022
- openResources.add(resource);
1023
- return () => {
1024
- openResources.delete(resource);
1025
- };
1026
- };
1027
- var trackLeaks = (open, close) => (target) => {
1028
- if (!enabled) {
1029
- return;
1030
- }
1031
- const openMethod = target.prototype[open];
1032
- const closeMethod = target.prototype[close];
1033
- if (!openMethod || !closeMethod) {
1034
- throw new Error(`Cannot find ${open} or ${close} method in ${target.name}`);
1035
- }
1036
- {
1037
- target.prototype[open] = async function(...args) {
1038
- this[handleSymbol] = trackResource(() => ({
1039
- name: target.name,
1040
- openStack: new StackTrace()
1041
- }));
1042
- return openMethod.apply(this, args);
1043
- };
1044
- Object.defineProperty(target.prototype[open], "name", {
1045
- value: open + "$checkLeaks"
1046
- });
1047
- }
1048
- {
1049
- target.prototype[close] = async function(...args) {
1050
- this[handleSymbol]?.();
1051
- return closeMethod.apply(this, args);
1052
- };
1053
- Object.defineProperty(target.prototype[close], "name", {
1054
- value: close + "$checkLeaks"
1055
- });
1056
- }
1057
- };
1058
- var dumpLeaks = () => {
1059
- if (!enabled) {
1060
- return;
1061
- }
1062
- log.info(`Leaked resources ${openResources.size}:`, void 0, {
1063
- F: __dxlog_file3,
1064
- L: 82,
1065
- S: void 0,
1066
- C: (f, a) => f(...a)
1067
- });
1068
- for (const resource of openResources) {
1069
- log.info(`- ${resource.name} at`, void 0, {
1070
- F: __dxlog_file3,
1071
- L: 84,
1072
- S: void 0,
1073
- C: (f, a) => f(...a)
1074
- });
1075
- log.info(resource.openStack.getStack(1), void 0, {
1076
- F: __dxlog_file3,
1077
- L: 85,
1078
- S: void 0,
1079
- C: (f, a) => f(...a)
1080
- });
1081
- log.info("\n", void 0, {
1082
- F: __dxlog_file3,
1083
- L: 86,
1084
- S: void 0,
1085
- C: (f, a) => f(...a)
1086
- });
1087
- }
1088
- };
1089
- if (enabled) {
1090
- global.dxDumpLeaks = dumpLeaks;
1091
- }
1092
-
1093
- // packages/common/async/src/task-scheduling.ts
1094
- var DeferredTask = class {
1095
- constructor(_ctx, _callback) {
1096
- this._ctx = _ctx;
1097
- this._callback = _callback;
1098
- this._scheduled = false;
1099
- this._currentTask = null;
1100
- this._nextTask = new Trigger();
1101
- }
1102
- /**
1103
- * Schedule the task to run asynchronously.
1104
- */
1105
- schedule() {
1106
- if (this._scheduled) {
1107
- return;
1108
- }
1109
- scheduleTask(this._ctx, async () => {
1110
- await this._currentTask;
1111
- this._scheduled = false;
1112
- const completionTrigger = this._nextTask;
1113
- this._nextTask = new Trigger();
1114
- this._currentTask = runInContextAsync(this._ctx, () => this._callback()).then(() => {
1115
- completionTrigger.wake();
1116
- });
1117
- });
1118
- this._scheduled = true;
1119
- }
1120
- /**
1121
- * Schedule the task to run and wait for it to finish.
1122
- */
1123
- async runBlocking() {
1124
- if (this._ctx.disposed) {
1125
- throw new ContextDisposedError2();
1126
- }
1127
- this.schedule();
1128
- await this._nextTask.wait();
1129
- }
1130
- /**
1131
- * Waits for the current task to finish if it is running.
1132
- * Does not schedule a new task.
1133
- */
1134
- async join() {
1135
- await this._currentTask;
1136
- }
1137
- };
1138
- var runInContext = (ctx, fn) => {
1139
- try {
1140
- fn();
1141
- } catch (err) {
1142
- ctx.raise(err);
1143
- }
1144
- };
1145
- var runInContextAsync = async (ctx, fn) => {
1146
- try {
1147
- await fn();
1148
- } catch (err) {
1149
- ctx.raise(err);
1150
- }
1151
- };
1152
- var scheduleMicroTask = (ctx, fn) => {
1153
- queueMicrotask(async () => {
1154
- if (ctx.disposed) {
1155
- return;
1156
- }
1157
- await runInContextAsync(ctx, fn);
1158
- });
1159
- };
1160
- var scheduleTask = (ctx, fn, afterMs) => {
1161
- const clearTracking = trackResource(() => ({
1162
- name: `task (${fn.name || "anonymous"})`,
1163
- openStack: new StackTrace2()
1164
- }));
1165
- const timeout = setTimeout(async () => {
1166
- clearDispose();
1167
- await runInContextAsync(ctx, fn);
1168
- clearTracking();
1169
- }, afterMs);
1170
- const clearDispose = ctx.onDispose(() => {
1171
- clearTracking();
1172
- clearTimeout(timeout);
1173
- });
1174
- };
1175
- var scheduleTaskInterval = (ctx, task, interval) => {
1176
- const clearTracking = trackResource(() => ({
1177
- name: `repeating task (${task.name || "anonymous"})`,
1178
- openStack: new StackTrace2()
1179
- }));
1180
- let timeoutId;
1181
- const run = async () => {
1182
- await runInContextAsync(ctx, task);
1183
- if (ctx.disposed) {
1184
- return;
1185
- }
1186
- timeoutId = setTimeout(run, interval);
1187
- };
1188
- timeoutId = setTimeout(run, interval);
1189
- ctx.onDispose(() => {
1190
- clearTracking();
1191
- clearTimeout(timeoutId);
1192
- });
1193
- };
1194
- var scheduleExponentialBackoffTaskInterval = (ctx, task, initialInterval) => {
1195
- const clearTracking = trackResource(() => ({
1196
- name: `repeating task (${task.name || "anonymous"})`,
1197
- openStack: new StackTrace2()
1198
- }));
1199
- let timeoutId;
1200
- let interval = initialInterval;
1201
- const repeat = async () => {
1202
- await runInContextAsync(ctx, task);
1203
- if (ctx.disposed) {
1204
- return;
1205
- }
1206
- interval *= 2;
1207
- timeoutId = setTimeout(repeat, interval);
1208
- };
1209
- timeoutId = setTimeout(repeat, interval);
1210
- ctx.onDispose(() => {
1211
- clearTracking();
1212
- clearTimeout(timeoutId);
1213
- });
1214
- };
1215
-
1216
- // packages/common/async/src/test-stream.ts
1217
- import { Duplex } from "@dxos/node-std/stream";
1218
- var TestStream = class extends Duplex {
1219
- constructor() {
1220
- super(...arguments);
1221
- this._received = Buffer.alloc(0);
1222
- this._onWrite = new Event();
1223
- }
1224
- static async assertConnectivity(stream1, stream2, { timeout = 200 } = {}) {
1225
- stream1.push("ping");
1226
- stream2.push("pong");
1227
- await Promise.all([
1228
- stream2.assertReceivedAsync("ping", {
1229
- timeout
1230
- }),
1231
- stream1.assertReceivedAsync("pong", {
1232
- timeout
1233
- })
1234
- ]);
1235
- }
1236
- _write(chunk, encoding, callback) {
1237
- this._received = Buffer.concat([
1238
- this._received,
1239
- chunk
1240
- ]);
1241
- this._onWrite.emit();
1242
- callback();
1243
- }
1244
- _read(size) {
1245
- }
1246
- assertReceivedAsync(data, { timeout = 200 } = {}) {
1247
- const dataBuffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
1248
- return asyncTimeout(this._onWrite.waitForCondition(() => this._received.equals(dataBuffer)), timeout);
1249
- }
1250
- };
1251
-
1252
1371
  // packages/common/async/src/update-scheduler.ts
1253
1372
  var TIME_PERIOD = 1e3;
1254
1373
  var UpdateScheduler = class {
@@ -1330,6 +1449,7 @@ export {
1330
1449
  MutexGuard,
1331
1450
  Observable,
1332
1451
  ObservableProvider,
1452
+ PersistentLifecycle,
1333
1453
  PushStream,
1334
1454
  TestStream,
1335
1455
  TimeoutError,