@dxos/async 0.8.1 → 0.8.2-main.10c050d

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.
Files changed (56) hide show
  1. package/dist/lib/browser/index.mjs +79 -58
  2. package/dist/lib/browser/index.mjs.map +3 -3
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +82 -58
  5. package/dist/lib/node/index.cjs.map +3 -3
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +79 -58
  8. package/dist/lib/node-esm/index.mjs.map +3 -3
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/callback.d.ts.map +1 -1
  11. package/dist/types/src/chain.d.ts.map +1 -1
  12. package/dist/types/src/cleanup.d.ts +11 -0
  13. package/dist/types/src/cleanup.d.ts.map +1 -1
  14. package/dist/types/src/debounce.d.ts.map +1 -1
  15. package/dist/types/src/errors.d.ts.map +1 -1
  16. package/dist/types/src/event-emitter.d.ts.map +1 -1
  17. package/dist/types/src/events.d.ts +5 -0
  18. package/dist/types/src/events.d.ts.map +1 -1
  19. package/dist/types/src/latch.d.ts.map +1 -1
  20. package/dist/types/src/mutex.d.ts +1 -1
  21. package/dist/types/src/mutex.d.ts.map +1 -1
  22. package/dist/types/src/observable-value.d.ts.map +1 -1
  23. package/dist/types/src/observable.d.ts.map +1 -1
  24. package/dist/types/src/persistent-lifecycle.d.ts +1 -1
  25. package/dist/types/src/persistent-lifecycle.d.ts.map +1 -1
  26. package/dist/types/src/push-iterable.d.ts.map +1 -1
  27. package/dist/types/src/sink.d.ts.map +1 -1
  28. package/dist/types/src/stream-to-array.d.ts.map +1 -1
  29. package/dist/types/src/task-scheduling.d.ts.map +1 -1
  30. package/dist/types/src/test-stream.d.ts.map +1 -1
  31. package/dist/types/src/testing.d.ts +2 -1
  32. package/dist/types/src/testing.d.ts.map +1 -1
  33. package/dist/types/src/timeout.d.ts.map +1 -1
  34. package/dist/types/src/timer.d.ts.map +1 -1
  35. package/dist/types/src/track-leaks.d.ts.map +1 -1
  36. package/dist/types/src/trigger.d.ts.map +1 -1
  37. package/dist/types/src/until.d.ts.map +1 -1
  38. package/dist/types/src/update-scheduler.d.ts.map +1 -1
  39. package/dist/types/tsconfig.tsbuildinfo +1 -1
  40. package/package.json +7 -7
  41. package/src/cleanup.ts +32 -4
  42. package/src/events.ts +21 -13
  43. package/src/mutex.test.ts +2 -2
  44. package/src/mutex.ts +1 -1
  45. package/src/observable-value.ts +2 -2
  46. package/src/observable.ts +7 -4
  47. package/src/persistent-lifecycle.test.ts +2 -2
  48. package/src/persistent-lifecycle.ts +5 -5
  49. package/src/task-scheduling.ts +3 -3
  50. package/src/test-stream.ts +2 -2
  51. package/src/testing.test.ts +7 -1
  52. package/src/testing.ts +8 -4
  53. package/src/timeout.ts +1 -0
  54. package/src/timer.ts +2 -2
  55. package/src/trigger.ts +3 -3
  56. package/src/update-scheduler.ts +4 -4
package/src/observable.ts CHANGED
@@ -38,7 +38,10 @@ export class MulticastObservable<T> extends Observable<T> {
38
38
  this._observable.subscribe(this._handlers);
39
39
  }
40
40
 
41
- static override from<T>(value: Observable<T> | ObservableLike<T> | ArrayLike<T> | Event<T>, initialValue?: T) {
41
+ static override from<T>(
42
+ value: Observable<T> | ObservableLike<T> | ArrayLike<T> | Event<T>,
43
+ initialValue?: T,
44
+ ): MulticastObservable<T> {
42
45
  if ('emit' in value) {
43
46
  return new MulticastObservable((observer) => {
44
47
  // TODO(wittjosiah): Do error/complete matter for events?
@@ -52,14 +55,14 @@ export class MulticastObservable<T> extends Observable<T> {
52
55
  return new MulticastObservable(observable, initialValue);
53
56
  }
54
57
 
55
- static override of<T>(...items: T[]) {
58
+ static override of<T>(...items: T[]): MulticastObservable<T> {
56
59
  return new MulticastObservable(Observable.of(...items.slice(1)), items[0]);
57
60
  }
58
61
 
59
62
  /**
60
63
  * @returns Stable reference to an observable that always returns `undefined`.
61
64
  */
62
- static empty() {
65
+ static empty(): MulticastObservable<null> {
63
66
  return EMPTY_OBSERVABLE;
64
67
  }
65
68
 
@@ -137,7 +140,7 @@ export class MulticastObservable<T> extends Observable<T> {
137
140
  return new MulticastObservable(this._observable.concat(...observables), value);
138
141
  }
139
142
 
140
- private _subscribe(observer: Observer<T>) {
143
+ private _subscribe(observer: Observer<T>): () => void {
141
144
  if (!this._observers.has(observer)) {
142
145
  this._observers.add(observer);
143
146
  }
@@ -25,7 +25,7 @@ describe('ConnectionState', () => {
25
25
  });
26
26
 
27
27
  const triggerTimestamp = Date.now();
28
- persistentLifecycle.scheduleRestart();
28
+ void persistentLifecycle.scheduleRestart();
29
29
  const timeToTrigger = (await triggerCall.wait({ timeout: 1000 })) - triggerTimestamp;
30
30
  expect(timeToTrigger).to.be.lessThan(50);
31
31
  });
@@ -69,7 +69,7 @@ describe('ConnectionState', () => {
69
69
 
70
70
  await persistentLifecycle.open();
71
71
 
72
- persistentLifecycle.scheduleRestart();
72
+ void persistentLifecycle.scheduleRestart();
73
73
  await sleep(10);
74
74
  await persistentLifecycle.close();
75
75
  expect(restarted).to.be.true;
@@ -64,7 +64,7 @@ export class PersistentLifecycle<T> extends Resource {
64
64
  }
65
65
 
66
66
  @synchronized
67
- protected override async _open() {
67
+ protected override async _open(): Promise<void> {
68
68
  this._restartTask = new DeferredTask(this._ctx, async () => {
69
69
  try {
70
70
  await this._restart();
@@ -80,13 +80,13 @@ export class PersistentLifecycle<T> extends Resource {
80
80
  });
81
81
  }
82
82
 
83
- protected override async _close() {
83
+ protected override async _close(): Promise<void> {
84
84
  await this._restartTask?.join();
85
85
  await this._stopCurrentState();
86
86
  this._restartTask = undefined;
87
87
  }
88
88
 
89
- private async _restart() {
89
+ private async _restart(): Promise<void> {
90
90
  log(`restarting in ${this._restartAfter}ms`, { state: this._lifecycleState });
91
91
  await this._stopCurrentState();
92
92
  if (this._lifecycleState !== LifecycleState.OPEN) {
@@ -104,7 +104,7 @@ export class PersistentLifecycle<T> extends Resource {
104
104
  await this._onRestart?.();
105
105
  }
106
106
 
107
- private async _stopCurrentState() {
107
+ private async _stopCurrentState(): Promise<void> {
108
108
  if (this._currentState) {
109
109
  try {
110
110
  await this._stop(this._currentState);
@@ -119,7 +119,7 @@ export class PersistentLifecycle<T> extends Resource {
119
119
  * Scheduling restart should be done from outside.
120
120
  */
121
121
  @synchronized
122
- scheduleRestart() {
122
+ async scheduleRestart(): Promise<void> {
123
123
  if (this._lifecycleState !== LifecycleState.OPEN) {
124
124
  return;
125
125
  }
@@ -33,7 +33,7 @@ export class DeferredTask {
33
33
  /**
34
34
  * Schedule the task to run asynchronously.
35
35
  */
36
- schedule() {
36
+ schedule(): void {
37
37
  if (this._scheduled) {
38
38
  return; // Already scheduled.
39
39
  }
@@ -59,7 +59,7 @@ export class DeferredTask {
59
59
  /**
60
60
  * Schedule the task to run and wait for it to finish.
61
61
  */
62
- async runBlocking() {
62
+ async runBlocking(): Promise<void> {
63
63
  if (this._ctx.disposed) {
64
64
  throw new ContextDisposedError();
65
65
  }
@@ -72,7 +72,7 @@ export class DeferredTask {
72
72
  * Waits for the current task to finish if it is running.
73
73
  * Does not schedule a new task.
74
74
  */
75
- async join() {
75
+ async join(): Promise<void> {
76
76
  await this._currentTask;
77
77
  }
78
78
  }
@@ -16,7 +16,7 @@ export class TestStream extends Duplex {
16
16
  stream1: TestStream,
17
17
  stream2: TestStream,
18
18
  { timeout = 200 }: { timeout?: number } = {},
19
- ) {
19
+ ): Promise<void> {
20
20
  stream1.push('ping');
21
21
  stream2.push('pong');
22
22
 
@@ -39,7 +39,7 @@ export class TestStream extends Duplex {
39
39
  // noop
40
40
  }
41
41
 
42
- assertReceivedAsync(data: Buffer | string, { timeout = 200 }: { timeout?: number } = {}) {
42
+ assertReceivedAsync(data: Buffer | string, { timeout = 200 }: { timeout?: number } = {}): Promise<void> {
43
43
  const dataBuffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
44
44
  return asyncTimeout(
45
45
  this._onWrite.waitForCondition(() => this._received.equals(dataBuffer)),
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { describe, expect, test } from 'vitest';
6
6
 
7
- import { expectToThrow } from '@dxos/debug';
7
+ import { expectToThrow, raise } from '@dxos/debug';
8
8
 
9
9
  import { waitForCondition } from './testing';
10
10
 
@@ -20,4 +20,10 @@ describe('waitForCondition', () => {
20
20
  const stop = Date.now() + 200;
21
21
  await expectToThrow(() => waitForCondition({ condition: () => Date.now() > stop, timeout: 100 }));
22
22
  });
23
+
24
+ test('breakOnError', async () => {
25
+ await expect(() =>
26
+ waitForCondition({ condition: () => raise(new Error('test')), timeout: 100, breakOnError: true }),
27
+ ).rejects.toThrow('test');
28
+ });
23
29
  });
package/src/testing.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  // Copyright 2020 DXOS.org
3
3
  //
4
4
 
5
- import { asyncTimeout, sleep } from './timeout';
5
+ import { sleep } from './timeout';
6
6
  import { Trigger } from './trigger';
7
7
 
8
8
  /**
@@ -19,11 +19,13 @@ export const waitForCondition = <FunctionType extends (...args: any) => any>({
19
19
  timeout = 0,
20
20
  interval = 10,
21
21
  error,
22
+ breakOnError = false,
22
23
  }: {
23
24
  condition: FunctionType;
24
25
  timeout?: number;
25
26
  interval?: number;
26
27
  error?: Error;
28
+ breakOnError?: boolean;
27
29
  }) => {
28
30
  const stopTime = timeout ? Date.now() + timeout : 0;
29
31
  const trigger = new Trigger<ReturnType<FunctionType>>();
@@ -37,8 +39,10 @@ export const waitForCondition = <FunctionType extends (...args: any) => any>({
37
39
  trigger.wake(value);
38
40
  break;
39
41
  }
40
- } catch (err) {
41
- // Pass...
42
+ } catch (err: any) {
43
+ if (breakOnError === true) {
44
+ trigger.throw(err);
45
+ }
42
46
  }
43
47
 
44
48
  // eslint-disable-next-line no-await-in-loop
@@ -48,5 +52,5 @@ export const waitForCondition = <FunctionType extends (...args: any) => any>({
48
52
 
49
53
  setTimeout(waiter, 0);
50
54
 
51
- return timeout ? asyncTimeout(trigger.wait(), timeout, error ?? new Error('Timeout')) : trigger.wait();
55
+ return trigger.wait({ timeout });
52
56
  };
package/src/timeout.ts CHANGED
@@ -37,6 +37,7 @@ export const asyncReturn = () => sleep(0);
37
37
  * Wait for promise or throw error.
38
38
  */
39
39
  export const asyncTimeout = async <T>(
40
+ // TODO(dmaretskyi): This callback API is unintuitive and leads to bugs.
40
41
  promise: Promise<T> | (() => Promise<T>),
41
42
  timeout: number,
42
43
  err?: Error | string,
package/src/timer.ts CHANGED
@@ -27,7 +27,7 @@ export class Timer {
27
27
  return !!this._timer;
28
28
  }
29
29
 
30
- start(options: TimerOptions, cb?: () => void) {
30
+ start(options: TimerOptions, cb?: () => void): this {
31
31
  if (isNaN(options.count) || isNaN(options.interval)) {
32
32
  throw new Error(`Invalid options: ${JSON.stringify(options)}`);
33
33
  }
@@ -61,7 +61,7 @@ export class Timer {
61
61
  return this;
62
62
  }
63
63
 
64
- stop() {
64
+ stop(): this {
65
65
  clearInterval(this._timer);
66
66
  this._timer = undefined;
67
67
  this._state.emit(false);
package/src/trigger.ts CHANGED
@@ -77,7 +77,7 @@ export class Trigger<T = void> {
77
77
  * Wake blocked callers (if any).
78
78
  * NOOP if the trigger is already resolved.
79
79
  */
80
- wake(value: T) {
80
+ wake(value: T): this {
81
81
  if (this._state !== TriggerState.WAITING) {
82
82
  return this;
83
83
  }
@@ -93,7 +93,7 @@ export class Trigger<T = void> {
93
93
  /**
94
94
  * Reset promise (new waiters will wait).
95
95
  */
96
- reset() {
96
+ reset(): this {
97
97
  this._state = TriggerState.WAITING;
98
98
  this._promise = new Promise<T>((resolve, reject) => {
99
99
  this._resolve = resolve;
@@ -108,7 +108,7 @@ export class Trigger<T = void> {
108
108
  * Throw error to blocked callers (if any).
109
109
  * NOOP if the trigger is already resolved.
110
110
  */
111
- throw(error: Error) {
111
+ throw(error: Error): this {
112
112
  if (this._state !== TriggerState.WAITING) {
113
113
  return this;
114
114
  }
@@ -38,7 +38,7 @@ export class UpdateScheduler {
38
38
  });
39
39
  }
40
40
 
41
- trigger() {
41
+ trigger(): void {
42
42
  if (this._scheduled) {
43
43
  return;
44
44
  }
@@ -87,7 +87,7 @@ export class UpdateScheduler {
87
87
  this._scheduled = true;
88
88
  }
89
89
 
90
- forceTrigger() {
90
+ forceTrigger(): void {
91
91
  scheduleMicroTask(this._ctx, async () => {
92
92
  this._callback().catch((err) => this._ctx.raise(err));
93
93
  });
@@ -97,14 +97,14 @@ export class UpdateScheduler {
97
97
  * Waits for the current task to finish if it is running.
98
98
  * Does not schedule a new task.
99
99
  */
100
- async join() {
100
+ async join(): Promise<void> {
101
101
  await this._promise;
102
102
  }
103
103
 
104
104
  /**
105
105
  * Force schedule the task to run and wait for it to finish.
106
106
  */
107
- async runBlocking() {
107
+ async runBlocking(): Promise<void> {
108
108
  // The previous task might still be running, so we need to wait for it to finish.
109
109
  await this._promise; // Can't be rejected.
110
110
  this._promise = this._callback();