@sohanemon/utils 5.1.0 → 5.1.2

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.
@@ -1,4 +1,5 @@
1
1
  export * from './cookie';
2
2
  export * from './object';
3
3
  export * from './shield';
4
+ export * from './poll';
4
5
  export * from './utils';
@@ -1,4 +1,5 @@
1
1
  export * from './cookie';
2
2
  export * from './object';
3
3
  export * from './shield';
4
+ export * from './poll';
4
5
  export * from './utils';
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Repeatedly polls an async `cond` function UNTIL it returns a TRUTHY value,
3
+ * or until the operation times out or is aborted.
4
+ *
5
+ * Designed for waiting on async jobs, external state, or delayed availability.
6
+ *
7
+ * @template T The type of the successful result.
8
+ *
9
+ * @param cond
10
+ * A function returning a Promise that resolves to:
11
+ * - a truthy value `T` → stop polling and return it
12
+ * - falsy/null/undefined → continue polling
13
+ *
14
+ * @param options
15
+ * Configuration options:
16
+ * - `interval` (number) — Time between polls in ms (default: 5000 ms)
17
+ * - `timeout` (number) — Max total duration before failing (default: 5 min)
18
+ * - `jitter` (boolean) — Add small random offset (±10%) to intervals to avoid sync bursts (default: true)
19
+ * - `signal` (AbortSignal) — Optional abort signal to cancel polling
20
+ *
21
+ * @returns
22
+ * Resolves with the truthy value `T` when successful.
23
+ * Throws `AbortError` if aborted
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const job = await poll(async () => {
28
+ * const status = await getJobStatus();
29
+ * return status === 'done' ? status : null;
30
+ * }, { interval: 3000, timeout: 60000 });
31
+ * ```
32
+ */
33
+ export declare function poll<T>(cond: () => Promise<T | null | false | undefined>, { interval, timeout, jitter, signal, }?: Partial<{
34
+ interval: number;
35
+ timeout: number;
36
+ signal: AbortSignal;
37
+ jitter: boolean;
38
+ }>): Promise<T>;
@@ -0,0 +1,69 @@
1
+ import { sleep } from './utils';
2
+ /**
3
+ * Repeatedly polls an async `cond` function UNTIL it returns a TRUTHY value,
4
+ * or until the operation times out or is aborted.
5
+ *
6
+ * Designed for waiting on async jobs, external state, or delayed availability.
7
+ *
8
+ * @template T The type of the successful result.
9
+ *
10
+ * @param cond
11
+ * A function returning a Promise that resolves to:
12
+ * - a truthy value `T` → stop polling and return it
13
+ * - falsy/null/undefined → continue polling
14
+ *
15
+ * @param options
16
+ * Configuration options:
17
+ * - `interval` (number) — Time between polls in ms (default: 5000 ms)
18
+ * - `timeout` (number) — Max total duration before failing (default: 5 min)
19
+ * - `jitter` (boolean) — Add small random offset (±10%) to intervals to avoid sync bursts (default: true)
20
+ * - `signal` (AbortSignal) — Optional abort signal to cancel polling
21
+ *
22
+ * @returns
23
+ * Resolves with the truthy value `T` when successful.
24
+ * Throws `AbortError` if aborted
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * const job = await poll(async () => {
29
+ * const status = await getJobStatus();
30
+ * return status === 'done' ? status : null;
31
+ * }, { interval: 3000, timeout: 60000 });
32
+ * ```
33
+ */
34
+ export async function poll(cond, { interval = 5000, timeout = 5 * 60 * 1000, jitter = true, signal, } = {}) {
35
+ const start = Date.now();
36
+ let aborted = signal?.aborted ?? false;
37
+ // fast listener (avoids repeated property lookups)
38
+ const abortListener = () => {
39
+ aborted = true;
40
+ };
41
+ signal?.addEventListener('abort', abortListener, { once: true });
42
+ try {
43
+ for (let attempt = 0;; attempt++) {
44
+ // fast exit check
45
+ if (aborted)
46
+ throw new Error('Polling aborted');
47
+ const result = await cond();
48
+ if (result)
49
+ return result;
50
+ const elapsed = Date.now() - start;
51
+ if (elapsed >= timeout)
52
+ throw new Error('Polling timed out', {
53
+ cause: `Polling timed out after ${timeout}ms`,
54
+ });
55
+ // add jitter (±10%) for anti-sync
56
+ const delay = jitter
57
+ ? interval + (Math.random() - 0.5) * interval * 0.2
58
+ : interval;
59
+ await sleep(delay, signal);
60
+ }
61
+ }
62
+ catch (err) {
63
+ throw err; // stop polling on any error
64
+ }
65
+ finally {
66
+ // cleanup to avoid leaks
67
+ signal?.removeEventListener('abort', abortListener);
68
+ }
69
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sohanemon/utils",
3
- "version": "5.1.0",
3
+ "version": "5.1.2",
4
4
  "author": "Sohan Emon <sohanemon@outlook.com>",
5
5
  "description": "",
6
6
  "type": "module",