@dxos/async 0.8.4-main.f9ba587 → 0.8.4-main.fd6878d

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 (61) hide show
  1. package/dist/lib/browser/index.mjs +177 -166
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +177 -166
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/callback.d.ts +2 -1
  8. package/dist/types/src/callback.d.ts.map +1 -1
  9. package/dist/types/src/chain.d.ts +1 -1
  10. package/dist/types/src/chain.d.ts.map +1 -1
  11. package/dist/types/src/cleanup.d.ts +1 -1
  12. package/dist/types/src/cleanup.d.ts.map +1 -1
  13. package/dist/types/src/debounce.d.ts +16 -2
  14. package/dist/types/src/debounce.d.ts.map +1 -1
  15. package/dist/types/src/index.d.ts +0 -5
  16. package/dist/types/src/index.d.ts.map +1 -1
  17. package/dist/types/src/task-scheduling.d.ts.map +1 -1
  18. package/dist/types/src/testing.d.ts +13 -0
  19. package/dist/types/src/testing.d.ts.map +1 -1
  20. package/dist/types/src/timeout.d.ts +1 -1
  21. package/dist/types/src/timeout.d.ts.map +1 -1
  22. package/dist/types/src/trigger.d.ts +11 -0
  23. package/dist/types/src/trigger.d.ts.map +1 -1
  24. package/dist/types/tsconfig.tsbuildinfo +1 -1
  25. package/package.json +9 -9
  26. package/src/callback.ts +3 -3
  27. package/src/chain.ts +1 -1
  28. package/src/cleanup.ts +3 -3
  29. package/src/debounce.test.ts +69 -12
  30. package/src/debounce.ts +32 -11
  31. package/src/event-emitter.test.ts +2 -1
  32. package/src/index.ts +0 -5
  33. package/src/observable-value.test.ts +1 -1
  34. package/src/persistent-lifecycle.test.ts +1 -1
  35. package/src/task-scheduling.ts +1 -1
  36. package/src/testing.test.ts +41 -1
  37. package/src/testing.ts +53 -0
  38. package/src/timeout.ts +23 -22
  39. package/src/trigger.ts +58 -1
  40. package/src/update-scheduler.ts +1 -1
  41. package/dist/types/src/latch.d.ts +0 -11
  42. package/dist/types/src/latch.d.ts.map +0 -1
  43. package/dist/types/src/sink.d.ts +0 -6
  44. package/dist/types/src/sink.d.ts.map +0 -1
  45. package/dist/types/src/throttle.d.ts +0 -2
  46. package/dist/types/src/throttle.d.ts.map +0 -1
  47. package/dist/types/src/throttle.test.d.ts +0 -2
  48. package/dist/types/src/throttle.test.d.ts.map +0 -1
  49. package/dist/types/src/types.d.ts +0 -2
  50. package/dist/types/src/types.d.ts.map +0 -1
  51. package/dist/types/src/until.d.ts +0 -14
  52. package/dist/types/src/until.d.ts.map +0 -1
  53. package/dist/types/src/until.test.d.ts +0 -2
  54. package/dist/types/src/until.test.d.ts.map +0 -1
  55. package/src/latch.ts +0 -60
  56. package/src/sink.ts +0 -26
  57. package/src/throttle.test.ts +0 -65
  58. package/src/throttle.ts +0 -14
  59. package/src/types.ts +0 -5
  60. package/src/until.test.ts +0 -47
  61. package/src/until.ts +0 -58
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/async",
3
- "version": "0.8.4-main.f9ba587",
3
+ "version": "0.8.4-main.fd6878d",
4
4
  "description": "Async utilities.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -10,12 +10,12 @@
10
10
  "type": "module",
11
11
  "exports": {
12
12
  ".": {
13
+ "types": "./dist/types/src/index.d.ts",
13
14
  "browser": "./dist/lib/browser/index.mjs",
14
15
  "node": {
15
16
  "require": "./dist/lib/node/index.cjs",
16
17
  "default": "./dist/lib/node-esm/index.mjs"
17
- },
18
- "types": "./dist/types/src/index.d.ts"
18
+ }
19
19
  }
20
20
  },
21
21
  "types": "dist/types/src/index.d.ts",
@@ -29,12 +29,12 @@
29
29
  "dependencies": {
30
30
  "zen-observable": "^0.10.0",
31
31
  "zen-push": "^0.3.1",
32
- "@dxos/context": "0.8.4-main.f9ba587",
33
- "@dxos/debug": "0.8.4-main.f9ba587",
34
- "@dxos/invariant": "0.8.4-main.f9ba587",
35
- "@dxos/log": "0.8.4-main.f9ba587",
36
- "@dxos/node-std": "0.8.4-main.f9ba587",
37
- "@dxos/util": "0.8.4-main.f9ba587"
32
+ "@dxos/context": "0.8.4-main.fd6878d",
33
+ "@dxos/debug": "0.8.4-main.fd6878d",
34
+ "@dxos/invariant": "0.8.4-main.fd6878d",
35
+ "@dxos/log": "0.8.4-main.fd6878d",
36
+ "@dxos/util": "0.8.4-main.fd6878d",
37
+ "@dxos/node-std": "0.8.4-main.fd6878d"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/zen-observable": "^0.8.3"
package/src/callback.ts CHANGED
@@ -2,12 +2,12 @@
2
2
  // Copyright 2020 DXOS.org
3
3
  //
4
4
 
5
+ export type Awaited<T> = T extends Promise<infer U> ? U : T;
6
+
5
7
  /**
6
8
  * Helper to convert a callback based API into a promise based API.
7
9
  */
8
- export const createPromiseFromCallback = <T = void>(
9
- run: (cb: (error?: Error, value?: T) => void) => void,
10
- ): Promise<T> =>
10
+ export const promiseFromCallback = <T = void>(run: (cb: (error?: Error, value?: T) => void) => void): Promise<T> =>
11
11
  new Promise((resolve, reject) => {
12
12
  run((error, value) => {
13
13
  if (error) {
package/src/chain.ts CHANGED
@@ -7,7 +7,7 @@ type Transform = (...args: any) => Promise<any>;
7
7
  /**
8
8
  * Async reducer iteratively applies functions to the given array of elements.
9
9
  */
10
- export const asyncChain =
10
+ export const chain =
11
11
  <T>(chain: Transform[]) =>
12
12
  async (elements: Promise<T[]>) => {
13
13
  let result = await elements;
package/src/cleanup.ts CHANGED
@@ -38,15 +38,15 @@ type EventMap<T> = T extends Window
38
38
  * Add the event listener and return a cleanup function.
39
39
  * Can be used in effect hooks in conjunction with `combine`.
40
40
  */
41
- export function addEventListener<T extends EventTarget, K extends keyof EventMap<T>>(
41
+ export const addEventListener = <T extends EventTarget, K extends keyof EventMap<T>>(
42
42
  target: T,
43
43
  type: K,
44
44
  listener: (this: T, ev: EventMap<T>[K]) => any,
45
45
  options?: boolean | AddEventListenerOptions,
46
- ): CleanupFn {
46
+ ): CleanupFn => {
47
47
  target.addEventListener(type as string, listener as EventListener, options);
48
48
  return () => target.removeEventListener(type as string, listener as EventListener, options);
49
- }
49
+ };
50
50
 
51
51
  export class SubscriptionList {
52
52
  private readonly _cleanups: CleanupFn[] = [];
@@ -4,25 +4,82 @@
4
4
 
5
5
  import { describe, expect, test } from 'vitest';
6
6
 
7
- import { debounce } from './debounce';
7
+ import { debounce, throttle } from './debounce';
8
8
  import { sleep } from './timeout';
9
9
 
10
+ describe('throttle', () => {
11
+ test('throttles function calls', async () => {
12
+ let count = 0;
13
+ const fn = throttle(() => count++, 100);
14
+
15
+ // First call should execute immediately.
16
+ fn();
17
+ expect(count).toBe(1);
18
+
19
+ // Second call within throttle window should not execute.
20
+ fn();
21
+ expect(count).toBe(1);
22
+
23
+ // Wait for throttle window to pass.
24
+ await sleep(150);
25
+
26
+ // Next call should execute.
27
+ fn();
28
+ expect(count).toBe(2);
29
+ });
30
+
31
+ test('passes arguments to throttled function', async () => {
32
+ let lastArgs: any[] = [];
33
+ const fn = throttle((...args: any[]) => {
34
+ lastArgs = args;
35
+ }, 100);
36
+
37
+ fn('test', 123);
38
+ expect(lastArgs).toEqual(['test', 123]);
39
+
40
+ // Call with different args within throttle window.
41
+ fn('different', 456);
42
+ expect(lastArgs).toEqual(['test', 123]); // Should not update.
43
+
44
+ await sleep(150);
45
+ fn('new', 789);
46
+ expect(lastArgs).toEqual(['new', 789]);
47
+ });
48
+
49
+ test('handles multiple rapid calls', async () => {
50
+ let count = 0;
51
+ const fn = throttle(() => count++, 100);
52
+
53
+ // Make multiple rapid calls.
54
+ for (let i = 0; i < 5; i++) {
55
+ fn();
56
+ }
57
+ expect(count).toBe(1); // Only first call should execute.
58
+
59
+ await sleep(150);
60
+ expect(count).toBe(1); // Still only one execution.
61
+
62
+ fn();
63
+ expect(count).toBe(2); // Next call after wait should execute.
64
+ });
65
+ });
66
+
10
67
  describe('debounce', () => {
11
68
  test('debounces function calls', async () => {
12
69
  let count = 0;
13
70
  const fn = debounce(() => count++, 100);
14
71
 
15
- // First call should not execute immediately
72
+ // First call should not execute immediately.
16
73
  fn();
17
74
  expect(count).toBe(0);
18
75
 
19
- // Second call should reset the timer
76
+ // Second call should reset the timer.
20
77
  fn();
21
78
  expect(count).toBe(0);
22
79
 
23
- // Wait for debounce window to pass
80
+ // Wait for debounce window to pass.
24
81
  await sleep(150);
25
- expect(count).toBe(1); // Only the last call should execute
82
+ expect(count).toBe(1); // Only the last call should execute.
26
83
  });
27
84
 
28
85
  test('passes arguments to debounced function', async () => {
@@ -32,27 +89,27 @@ describe('debounce', () => {
32
89
  }, 100);
33
90
 
34
91
  fn('test', 123);
35
- expect(lastArgs).toEqual([]); // Should not execute immediately
92
+ expect(lastArgs).toEqual([]); // Should not execute immediately.
36
93
 
37
- // Call with different args
94
+ // Call with different args.
38
95
  fn('different', 456);
39
- expect(lastArgs).toEqual([]); // Should not execute immediately
96
+ expect(lastArgs).toEqual([]); // Should not execute immediately.
40
97
 
41
98
  await sleep(150);
42
- expect(lastArgs).toEqual(['different', 456]); // Should execute with last args
99
+ expect(lastArgs).toEqual(['different', 456]); // Should execute with last args.
43
100
  });
44
101
 
45
102
  test('handles multiple rapid calls', async () => {
46
103
  let count = 0;
47
104
  const fn = debounce(() => count++, 100);
48
105
 
49
- // Make multiple rapid calls
106
+ // Make multiple rapid calls.
50
107
  for (let i = 0; i < 5; i++) {
51
108
  fn();
52
109
  }
53
- expect(count).toBe(0); // Should not execute immediately
110
+ expect(count).toBe(0); // Should not execute immediately.
54
111
 
55
112
  await sleep(150);
56
- expect(count).toBe(1); // Should execute only once after wait
113
+ expect(count).toBe(1); // Should execute only once after wait.
57
114
  });
58
115
  });
package/src/debounce.ts CHANGED
@@ -2,28 +2,49 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { throttle } from './throttle';
5
+ type Callback = (...args: any[]) => void;
6
6
 
7
7
  /**
8
8
  * Debounce callback.
9
+ *
10
+ * @param cb Callback to invoke.
11
+ * @param delay Time window to wait before allowing calls.
12
+ * @returns A new function that wraps the callback and ensures that the callback is only invoked after the time window has passed and no new calls have been made.
9
13
  */
10
- export const debounce = (cb: (...args: any[]) => void, wait = 100): ((...args: any[]) => void) => {
14
+ export const debounce = <CB extends Callback>(cb: CB, delay = 100): CB => {
11
15
  let t: ReturnType<typeof setTimeout>;
12
- return (...args: any[]) => {
16
+ return ((...args: any[]) => {
13
17
  clearTimeout(t);
14
- t = setTimeout(() => cb(...args), wait);
15
- };
18
+ t = setTimeout(() => cb(...args), delay);
19
+ }) as CB;
16
20
  };
17
21
 
18
22
  /**
19
- * Debounce and throttle callback.
23
+ * Throttle callback.
24
+ *
25
+ * @param cb Callback to invoke.
26
+ * @param delay Time window to allow calls in.
27
+ * @returns A new function that wraps the callback and prevents multiple invocations within the time window.
20
28
  */
21
- export const debounceAndThrottle = (cb: (...args: any[]) => void, wait = 100): ((...args: any[]) => void) => {
22
- const debounced = debounce(cb, wait);
23
- const throttled = throttle(cb, wait);
29
+ export const throttle = <CB extends Callback>(cb: CB, delay = 100): CB => {
30
+ let lastCall = 0;
31
+ return ((...args: any[]) => {
32
+ const now = Date.now();
33
+ if (now - lastCall >= delay) {
34
+ cb(...args);
35
+ lastCall = now;
36
+ }
37
+ }) as CB;
38
+ };
24
39
 
25
- return (...args: any[]) => {
40
+ /**
41
+ * Debounce and throttle callback.
42
+ */
43
+ export const debounceAndThrottle = <CB extends Callback>(cb: CB, delay = 100): CB => {
44
+ const debounced = debounce(cb, delay);
45
+ const throttled = throttle(cb, delay);
46
+ return ((...args: any[]) => {
26
47
  debounced(...args);
27
48
  throttled(...args);
28
- };
49
+ }) as CB;
29
50
  };
@@ -3,11 +3,12 @@
3
3
  //
4
4
 
5
5
  import { EventEmitter } from 'node:events';
6
+
6
7
  import { describe, expect, test } from 'vitest';
7
8
 
8
9
  import { onEvent, waitForEvent } from './event-emitter';
9
- import { latch } from './latch';
10
10
  import { asyncTimeout } from './timeout';
11
+ import { latch } from './trigger';
11
12
 
12
13
  describe('event-emitter', () => {
13
14
  test('onEvent', async () => {
package/src/index.ts CHANGED
@@ -9,22 +9,17 @@ export * from './debounce';
9
9
  export * from './errors';
10
10
  export * from './event-emitter';
11
11
  export * from './events';
12
- export * from './latch';
13
12
  export * from './mutex';
14
13
  export * from './observable';
15
14
  export * from './observable-value';
16
15
  export * from './persistent-lifecycle';
17
16
  export * from './push-iterable';
18
- export * from './sink';
19
17
  export * from './stream-to-array';
20
18
  export * from './task-scheduling';
21
19
  export * from './test-stream';
22
20
  export * from './testing';
23
- export * from './throttle';
24
21
  export * from './timeout';
25
22
  export * from './timer';
26
23
  export * from './track-leaks';
27
24
  export * from './trigger';
28
- export * from './types';
29
- export * from './until';
30
25
  export * from './update-scheduler';
@@ -5,12 +5,12 @@
5
5
  import { describe, expect, test } from 'vitest';
6
6
 
7
7
  import { type AsyncEvents, TimeoutError } from './errors';
8
- import { latch } from './latch';
9
8
  import {
10
9
  type CancellableObservable,
11
10
  type CancellableObservableEvents,
12
11
  CancellableObservableProvider,
13
12
  } from './observable-value';
13
+ import { latch } from './trigger';
14
14
 
15
15
  interface ConnectionEvents extends AsyncEvents, CancellableObservableEvents {
16
16
  onConnected(connectionId: string): void;
@@ -2,7 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { describe, expect, test, onTestFinished } from 'vitest';
5
+ import { describe, expect, onTestFinished, test } from 'vitest';
6
6
 
7
7
  import { log } from '@dxos/log';
8
8
 
@@ -2,7 +2,7 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- import { ContextDisposedError, type Context } from '@dxos/context';
5
+ import { type Context, ContextDisposedError } from '@dxos/context';
6
6
  import { StackTrace } from '@dxos/debug';
7
7
  import { type MaybePromise } from '@dxos/util';
8
8
 
@@ -6,7 +6,8 @@ import { describe, expect, test } from 'vitest';
6
6
 
7
7
  import { expectToThrow, raise } from '@dxos/debug';
8
8
 
9
- import { waitForCondition } from './testing';
9
+ import { until, waitForCondition } from './testing';
10
+ import { sleep } from './timeout';
10
11
 
11
12
  describe('waitForCondition', () => {
12
13
  test('succeeds', async () => {
@@ -27,3 +28,42 @@ describe('waitForCondition', () => {
27
28
  ).rejects.toThrow('test');
28
29
  });
29
30
  });
31
+
32
+ describe('until', () => {
33
+ test('success', async () => {
34
+ const value = await until<number>(async (resolve) => {
35
+ await sleep(100);
36
+ resolve(100);
37
+ return 1;
38
+ });
39
+
40
+ expect(value).to.equal(100);
41
+ });
42
+
43
+ test('error', async () => {
44
+ await expect(async () => {
45
+ await until(async (resolve, reject) => {
46
+ await sleep(100);
47
+ reject(new Error());
48
+ });
49
+ }).rejects.toThrowError();
50
+ });
51
+
52
+ test('catch', async () => {
53
+ await expect(async () => {
54
+ await until(async () => {
55
+ await sleep(100);
56
+ throw new Error();
57
+ });
58
+ }).rejects.toThrowError();
59
+ });
60
+
61
+ test('timeout', async () => {
62
+ await expect(async () => {
63
+ await until(async (resolve) => {
64
+ await sleep(500);
65
+ resolve();
66
+ }, 100); // Timeout before complete.
67
+ }).rejects.toThrowError();
68
+ });
69
+ });
package/src/testing.ts CHANGED
@@ -54,3 +54,56 @@ export const waitForCondition = <FunctionType extends (...args: any) => any>({
54
54
 
55
55
  return trigger.wait({ timeout });
56
56
  };
57
+
58
+ export type UntilCallback<T> = (resolve: (value: T) => void, reject: (error: Error) => void) => Promise<T> | void;
59
+
60
+ /**
61
+ * Awaits promise.
62
+ */
63
+ export const until = <T = void>(cb: UntilCallback<T>, timeout?: number): Promise<T> => {
64
+ return new Promise((resolve, reject) => {
65
+ const t =
66
+ timeout &&
67
+ setTimeout(() => {
68
+ reject(new Error(`Timeout after ${t}ms`));
69
+ }, timeout);
70
+
71
+ setTimeout(async () => {
72
+ try {
73
+ await cb(
74
+ (value: T) => {
75
+ t && clearTimeout(t);
76
+ resolve(value);
77
+ },
78
+ (error: Error) => {
79
+ t && clearTimeout(t);
80
+ reject(error);
81
+ },
82
+ );
83
+ } catch (err) {
84
+ reject(err);
85
+ }
86
+ });
87
+ });
88
+ };
89
+
90
+ /**
91
+ * Wait until promise resolves.
92
+ */
93
+ export const untilPromise = <T = void>(cb: () => Promise<T>) => cb();
94
+
95
+ /**
96
+ * Wait until error is thrown.
97
+ */
98
+ export const untilError = (cb: () => Promise<any>) => {
99
+ return new Promise((resolve, reject) => {
100
+ setTimeout(async () => {
101
+ try {
102
+ await cb();
103
+ reject(new Error('No error was thrown.'));
104
+ } catch (err) {
105
+ resolve(err);
106
+ }
107
+ });
108
+ });
109
+ };
package/src/timeout.ts CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { type Context, ContextDisposedError } from '@dxos/context';
6
6
 
7
- import { createPromiseFromCallback } from './callback';
7
+ import { promiseFromCallback } from './callback';
8
8
  import { TimeoutError } from './errors';
9
9
 
10
10
  /**
@@ -28,6 +28,27 @@ export const sleep = (ms: number) => {
28
28
  });
29
29
  };
30
30
 
31
+ // TODO(burdon): Reconcile with sleep.
32
+ export const sleepWithContext = (ctx: Context, ms: number) => {
33
+ const error = new ContextDisposedError();
34
+ return new Promise<void>((resolve, reject) => {
35
+ if (ctx.disposed) {
36
+ reject(error);
37
+ return;
38
+ }
39
+
40
+ const timeout = setTimeout(() => {
41
+ clearDispose();
42
+ resolve();
43
+ }, ms);
44
+
45
+ const clearDispose = ctx.onDispose(() => {
46
+ clearTimeout(timeout);
47
+ reject(error);
48
+ });
49
+ });
50
+ };
51
+
31
52
  /**
32
53
  * Can be used in long-running tasks to let other callbacks be invoked.
33
54
  */
@@ -52,7 +73,7 @@ export const asyncTimeout = async <T>(
52
73
  unrefTimeout(timeoutId);
53
74
  });
54
75
 
55
- const conditionTimeout = typeof promise === 'function' ? createPromiseFromCallback<T>(promise) : promise;
76
+ const conditionTimeout = typeof promise === 'function' ? promiseFromCallback<T>(promise) : promise;
56
77
  return await Promise.race([conditionTimeout, timeoutPromise]).finally(() => {
57
78
  clearTimeout(timeoutId);
58
79
  });
@@ -67,23 +88,3 @@ export const unrefTimeout = (timeoutId: NodeJS.Timeout) => {
67
88
  timeoutId.unref();
68
89
  }
69
90
  };
70
-
71
- export const sleepWithContext = (ctx: Context, ms: number) => {
72
- const error = new ContextDisposedError();
73
- return new Promise<void>((resolve, reject) => {
74
- if (ctx.disposed) {
75
- reject(error);
76
- return;
77
- }
78
-
79
- const timeout = setTimeout(() => {
80
- clearDispose();
81
- resolve();
82
- }, ms);
83
-
84
- const clearDispose = ctx.onDispose(() => {
85
- clearTimeout(timeout);
86
- reject(error);
87
- });
88
- });
89
- };
package/src/trigger.ts CHANGED
@@ -2,6 +2,8 @@
2
2
  // Copyright 2020 DXOS.org
3
3
  //
4
4
 
5
+ import { invariant } from '@dxos/invariant';
6
+
5
7
  import { TimeoutError } from './errors';
6
8
  import { asyncTimeout } from './timeout';
7
9
 
@@ -10,7 +12,7 @@ import { asyncTimeout } from './timeout';
10
12
  * @deprecated Use `Trigger` instead.
11
13
  */
12
14
  export const trigger = <T = void>(timeout?: number): [() => Promise<T>, (arg: T) => void] => {
13
- // eslint-disable-line @stayradiated/prefer-arrow-functions/prefer-arrow-functions
15
+ // eslint-disable-line prefer-arrow-functions/prefer-arrow-functions
14
16
  let callback: (arg: T) => void;
15
17
 
16
18
  const promise = new Promise<T>((resolve, reject) => {
@@ -121,3 +123,58 @@ export class Trigger<T = void> {
121
123
  return this;
122
124
  }
123
125
  }
126
+
127
+ type LatchProps = {
128
+ count?: number;
129
+ timeout?: number;
130
+ };
131
+
132
+ type LatchResult = [() => Promise<number>, () => number, (err: Error) => void];
133
+
134
+ /**
135
+ * Returns a callback and a promise that's resolved when the callback is called n times.
136
+ * @deprecated Use `Trigger` instead.
137
+ */
138
+ export const latch = ({ count = 1, timeout }: LatchProps = {}): LatchResult => {
139
+ invariant(count >= 0);
140
+
141
+ let t: ReturnType<typeof setTimeout>;
142
+ let doResolve: (value: number) => void;
143
+ let doReject: (err: Error) => void;
144
+ const promise = new Promise<number>((resolve, reject) => {
145
+ doResolve = (value) => {
146
+ clearTimeout(t);
147
+ resolve(value);
148
+ };
149
+
150
+ doReject = (err) => {
151
+ clearTimeout(t);
152
+ reject(err);
153
+ };
154
+ });
155
+
156
+ if (count === 0) {
157
+ setTimeout(() => {
158
+ doResolve(0);
159
+ });
160
+ } else {
161
+ if (timeout) {
162
+ t = setTimeout(() => {
163
+ doReject(new Error(`Timed out after ${timeout.toLocaleString()}ms`));
164
+ }, timeout);
165
+ }
166
+ }
167
+
168
+ let i = 0;
169
+ return [
170
+ async () => await promise,
171
+ () => {
172
+ if (++i === count) {
173
+ doResolve(i);
174
+ }
175
+
176
+ return i;
177
+ },
178
+ (err: Error) => doReject(err),
179
+ ];
180
+ };
@@ -16,7 +16,7 @@ export type UpdateSchedulerOptions = {
16
16
  /**
17
17
  * Time period for update counting.
18
18
  */
19
- const TIME_PERIOD = 1000;
19
+ const TIME_PERIOD = 1_000;
20
20
 
21
21
  export class UpdateScheduler {
22
22
  /**
@@ -1,11 +0,0 @@
1
- type LatchProps = {
2
- count?: number;
3
- timeout?: number;
4
- };
5
- type LatchResult = [() => Promise<number>, () => number, (err: Error) => void];
6
- /**
7
- * Returns a callback and a promise that's resolved when the callback is called n times.
8
- */
9
- export declare const latch: ({ count, timeout }?: LatchProps) => LatchResult;
10
- export {};
11
- //# sourceMappingURL=latch.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"latch.d.ts","sourceRoot":"","sources":["../../../src/latch.ts"],"names":[],"mappings":"AAMA,KAAK,UAAU,GAAG;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,KAAK,WAAW,GAAG,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,MAAM,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC,CAAC;AAE/E;;GAEG;AAEH,eAAO,MAAM,KAAK,GAAI,qBAAwB,UAAe,KAAG,WA0C/D,CAAC"}
@@ -1,6 +0,0 @@
1
- import { type EventEmitter } from 'node:events';
2
- /**
3
- * Waits for the specified number of events from the given emitter.
4
- */
5
- export declare const sink: (emitter: EventEmitter, event: string, count?: number) => Promise<void>;
6
- //# sourceMappingURL=sink.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sink.d.ts","sourceRoot":"","sources":["../../../src/sink.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhD;;GAEG;AACH,eAAO,MAAM,IAAI,GAAI,SAAS,YAAY,EAAE,OAAO,MAAM,EAAE,cAAS,KAAG,OAAO,CAAC,IAAI,CAclF,CAAC"}
@@ -1,2 +0,0 @@
1
- export declare const throttle: (cb: (...args: any[]) => void, wait?: number) => ((...args: any[]) => void);
2
- //# sourceMappingURL=throttle.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"throttle.d.ts","sourceRoot":"","sources":["../../../src/throttle.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,QAAQ,GAAI,IAAI,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,EAAE,aAAU,KAAG,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAS5F,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=throttle.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"throttle.test.d.ts","sourceRoot":"","sources":["../../../src/throttle.test.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export type Awaited<T> = T extends Promise<infer U> ? U : T;
2
- //# sourceMappingURL=types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/types.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC"}