@depthbomb/common 1.3.1 → 2.0.0

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 (67) hide show
  1. package/README.md +286 -1
  2. package/dist/collections.cjs +1 -0
  3. package/dist/{queue.d.cts → collections.d.cts} +31 -5
  4. package/dist/{queue.d.mts → collections.d.mts} +31 -5
  5. package/dist/collections.mjs +1 -0
  6. package/dist/decorators.cjs +1 -1
  7. package/dist/decorators.d.cts +1 -1
  8. package/dist/decorators.d.mts +1 -1
  9. package/dist/decorators.mjs +1 -1
  10. package/dist/functional.cjs +1 -0
  11. package/dist/{fn.d.cts → functional.d.cts} +1 -1
  12. package/dist/{fn.d.mts → functional.d.mts} +1 -1
  13. package/dist/guards.cjs +1 -0
  14. package/dist/guards.d.cts +7 -0
  15. package/dist/guards.d.mts +7 -0
  16. package/dist/guards.mjs +1 -0
  17. package/dist/index.cjs +1 -1
  18. package/dist/index.d.cts +12 -7
  19. package/dist/index.d.mts +12 -7
  20. package/dist/index.mjs +1 -1
  21. package/dist/lazy.cjs +1 -1
  22. package/dist/lazy.d.cts +1 -5
  23. package/dist/lazy.d.mts +1 -5
  24. package/dist/lazy.mjs +1 -1
  25. package/dist/number.cjs +1 -0
  26. package/dist/number.d.cts +8 -0
  27. package/dist/number.d.mts +8 -0
  28. package/dist/number.mjs +1 -0
  29. package/dist/promise.cjs +1 -0
  30. package/dist/promise.d.cts +48 -0
  31. package/dist/promise.d.mts +48 -0
  32. package/dist/promise.mjs +1 -0
  33. package/dist/random.cjs +1 -0
  34. package/dist/random.d.cts +11 -0
  35. package/dist/random.d.mts +11 -0
  36. package/dist/random.mjs +1 -0
  37. package/dist/state.cjs +1 -0
  38. package/dist/state.d.cts +88 -0
  39. package/dist/state.d.mts +88 -0
  40. package/dist/state.mjs +1 -0
  41. package/dist/timing.cjs +1 -0
  42. package/dist/timing.d.cts +71 -0
  43. package/dist/timing.d.mts +71 -0
  44. package/dist/timing.mjs +1 -0
  45. package/dist/typing.cjs +1 -0
  46. package/dist/typing.d.cts +26 -0
  47. package/dist/typing.d.mts +26 -0
  48. package/dist/typing.mjs +1 -0
  49. package/dist/url.cjs +1 -0
  50. package/dist/{urllib.d.cts → url.d.cts} +12 -2
  51. package/dist/{urllib.d.mts → url.d.mts} +12 -2
  52. package/dist/url.mjs +1 -0
  53. package/package.json +103 -81
  54. package/dist/async.cjs +0 -1
  55. package/dist/async.d.cts +0 -44
  56. package/dist/async.d.mts +0 -44
  57. package/dist/async.mjs +0 -1
  58. package/dist/fn.cjs +0 -1
  59. package/dist/queue.cjs +0 -1
  60. package/dist/queue.mjs +0 -1
  61. package/dist/types.cjs +0 -1
  62. package/dist/types.d.cts +0 -9
  63. package/dist/types.d.mts +0 -9
  64. package/dist/types.mjs +0 -1
  65. package/dist/urllib.cjs +0 -1
  66. package/dist/urllib.mjs +0 -1
  67. /package/dist/{fn.mjs → functional.mjs} +0 -0
@@ -0,0 +1,48 @@
1
+ import { Awaitable } from "./typing.cjs";
2
+
3
+ //#region src/promise.d.ts
4
+ interface IConcurrencyOptions {
5
+ concurrency?: number;
6
+ }
7
+ /**
8
+ * Waits for all promises to settle and returns an array of successful results.
9
+ *
10
+ * @param promises An array of promises to wait for
11
+ * @returns A promise that resolves to an array of successful results
12
+ */
13
+ declare function allSettledSuccessful<T>(promises: Array<Awaitable<T>>): Promise<T[]>;
14
+ interface SettledDetailed<T> {
15
+ results: Array<PromiseSettledResult<T>>;
16
+ fulfilled: T[];
17
+ rejected: unknown[];
18
+ }
19
+ /**
20
+ * Waits for all values to settle and returns full settled results plus split fulfilled/rejected lists.
21
+ *
22
+ * @param promises Values or promises to settle.
23
+ */
24
+ declare function allSettledDetailed<T>(promises: Array<Awaitable<T>>): Promise<SettledDetailed<T>>;
25
+ /**
26
+ * Executes an array of asynchronous tasks sequentially.
27
+ *
28
+ * @param tasks An array of functions that return promises
29
+ * @returns A promise that resolves to an array of results from the input tasks
30
+ */
31
+ declare function sequential<T>(tasks: Array<() => Awaitable<T>>): Promise<T[]>;
32
+ /**
33
+ * Runs asynchronous tasks with a concurrency limit while preserving result order.
34
+ *
35
+ * @param tasks Task functions to execute.
36
+ * @param options Concurrency options.
37
+ */
38
+ declare function pool<T>(tasks: Array<() => Awaitable<T>>, options?: IConcurrencyOptions): Promise<T[]>;
39
+ /**
40
+ * Maps values using an async mapper with a concurrency limit.
41
+ *
42
+ * @param values Input values.
43
+ * @param mapper Mapping function.
44
+ * @param options Concurrency options.
45
+ */
46
+ declare function pMap<T, U>(values: Iterable<T>, mapper: (value: T, index: number) => Awaitable<U>, options?: IConcurrencyOptions): Promise<U[]>;
47
+ //#endregion
48
+ export { IConcurrencyOptions, SettledDetailed, allSettledDetailed, allSettledSuccessful, pMap, pool, sequential };
@@ -0,0 +1,48 @@
1
+ import { Awaitable } from "./typing.mjs";
2
+
3
+ //#region src/promise.d.ts
4
+ interface IConcurrencyOptions {
5
+ concurrency?: number;
6
+ }
7
+ /**
8
+ * Waits for all promises to settle and returns an array of successful results.
9
+ *
10
+ * @param promises An array of promises to wait for
11
+ * @returns A promise that resolves to an array of successful results
12
+ */
13
+ declare function allSettledSuccessful<T>(promises: Array<Awaitable<T>>): Promise<T[]>;
14
+ interface SettledDetailed<T> {
15
+ results: Array<PromiseSettledResult<T>>;
16
+ fulfilled: T[];
17
+ rejected: unknown[];
18
+ }
19
+ /**
20
+ * Waits for all values to settle and returns full settled results plus split fulfilled/rejected lists.
21
+ *
22
+ * @param promises Values or promises to settle.
23
+ */
24
+ declare function allSettledDetailed<T>(promises: Array<Awaitable<T>>): Promise<SettledDetailed<T>>;
25
+ /**
26
+ * Executes an array of asynchronous tasks sequentially.
27
+ *
28
+ * @param tasks An array of functions that return promises
29
+ * @returns A promise that resolves to an array of results from the input tasks
30
+ */
31
+ declare function sequential<T>(tasks: Array<() => Awaitable<T>>): Promise<T[]>;
32
+ /**
33
+ * Runs asynchronous tasks with a concurrency limit while preserving result order.
34
+ *
35
+ * @param tasks Task functions to execute.
36
+ * @param options Concurrency options.
37
+ */
38
+ declare function pool<T>(tasks: Array<() => Awaitable<T>>, options?: IConcurrencyOptions): Promise<T[]>;
39
+ /**
40
+ * Maps values using an async mapper with a concurrency limit.
41
+ *
42
+ * @param values Input values.
43
+ * @param mapper Mapping function.
44
+ * @param options Concurrency options.
45
+ */
46
+ declare function pMap<T, U>(values: Iterable<T>, mapper: (value: T, index: number) => Awaitable<U>, options?: IConcurrencyOptions): Promise<U[]>;
47
+ //#endregion
48
+ export { IConcurrencyOptions, SettledDetailed, allSettledDetailed, allSettledSuccessful, pMap, pool, sequential };
@@ -0,0 +1 @@
1
+ async function e(e){return(await Promise.allSettled(e)).filter(e=>e.status===`fulfilled`).map(e=>e.value)}async function t(e){let t=await Promise.allSettled(e),n=[],r=[];for(let e of t){if(e.status===`fulfilled`){n.push(e.value);continue}r.push(e.reason)}return{results:t,fulfilled:n,rejected:r}}async function n(e){let t=[];for(let n of e)t.push(await n());return t}function r(e){if(!Number.isInteger(e)||e<1)throw Error(`concurrency must be an integer >= 1`);return e}async function i(e,t={}){if(e.length===0)return[];let n=r(t.concurrency??e.length),i=Array(e.length),a=0;async function o(){for(;;){let t=a++;if(t>=e.length)return;i[t]=await e[t]()}}let s=Math.min(n,e.length),c=Array.from({length:s},()=>o());return await Promise.all(c),i}async function a(e,t,n={}){let r=[],a=0;for(let n of e){let e=a++;r.push(()=>t(n,e))}return i(r,n)}export{t as allSettledDetailed,e as allSettledSuccessful,a as pMap,i as pool,n as sequential};
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e,t){if(!Number.isFinite(e)||!Number.isFinite(t))throw Error(`min and max must be finite numbers`);if(e>t)throw Error(`min must be <= max`)}function t(t=0,n=1){return e(t,n),Math.random()*(n-t)+t}function n(n,r){if(!Number.isInteger(n)||!Number.isInteger(r))throw Error(`min and max must be integers`);return e(n,r),Math.floor(t(n,r+1))}function r(e){if(e.length===0)throw Error(`cannot pick from empty array`);return e[n(0,e.length-1)]}function i(e){if(e.length===0)throw Error(`cannot pick from empty weighted items`);let n=0;for(let t of e){if(!Number.isFinite(t.weight)||t.weight<0)throw Error(`weights must be finite numbers >= 0`);n+=t.weight}if(n<=0)throw Error(`total weight must be > 0`);let r=t(0,n);for(let t of e)if(r-=t.weight,r<=0)return t.value;return e[e.length-1].value}exports.pickRandom=r,exports.pickWeighted=i,exports.randomFloat=t,exports.randomInt=n;
@@ -0,0 +1,11 @@
1
+ //#region src/random.d.ts
2
+ interface IWeightedItem<T> {
3
+ value: T;
4
+ weight: number;
5
+ }
6
+ declare function randomFloat(min?: number, max?: number): number;
7
+ declare function randomInt(min: number, max: number): number;
8
+ declare function pickRandom<T>(values: readonly T[]): T;
9
+ declare function pickWeighted<T>(items: Array<IWeightedItem<T>>): T;
10
+ //#endregion
11
+ export { IWeightedItem, pickRandom, pickWeighted, randomFloat, randomInt };
@@ -0,0 +1,11 @@
1
+ //#region src/random.d.ts
2
+ interface IWeightedItem<T> {
3
+ value: T;
4
+ weight: number;
5
+ }
6
+ declare function randomFloat(min?: number, max?: number): number;
7
+ declare function randomInt(min: number, max: number): number;
8
+ declare function pickRandom<T>(values: readonly T[]): T;
9
+ declare function pickWeighted<T>(items: Array<IWeightedItem<T>>): T;
10
+ //#endregion
11
+ export { IWeightedItem, pickRandom, pickWeighted, randomFloat, randomInt };
@@ -0,0 +1 @@
1
+ function e(e,t){if(!Number.isFinite(e)||!Number.isFinite(t))throw Error(`min and max must be finite numbers`);if(e>t)throw Error(`min must be <= max`)}function t(t=0,n=1){return e(t,n),Math.random()*(n-t)+t}function n(n,r){if(!Number.isInteger(n)||!Number.isInteger(r))throw Error(`min and max must be integers`);return e(n,r),Math.floor(t(n,r+1))}function r(e){if(e.length===0)throw Error(`cannot pick from empty array`);return e[n(0,e.length-1)]}function i(e){if(e.length===0)throw Error(`cannot pick from empty weighted items`);let n=0;for(let t of e){if(!Number.isFinite(t.weight)||t.weight<0)throw Error(`weights must be finite numbers >= 0`);n+=t.weight}if(n<=0)throw Error(`total weight must be > 0`);let r=t(0,n);for(let t of e)if(r-=t.weight,r<=0)return t.value;return e[e.length-1].value}export{r as pickRandom,i as pickWeighted,t as randomFloat,n as randomInt};
package/dist/state.cjs ADDED
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=class{value;#e;constructor(e){this.value=e,this.#e=e}set(e){this.value=e}reset(){this.value=this.#e}valueOf(){return this.value}toString(){return String(this.value)}},t=class extends e{constructor(e=!1){super(e)}get isTrue(){return this.value===!0}get isFalse(){return!this.isTrue}set(e){super.set(e)}setTrue(){this.value=!0}setFalse(){this.value=!1}toggle(){this.value=!this.value}};function n(e){let t,n=!1;function r(){return n||=(t=e(),!0),t}function i(){n=!1,t=void 0}return{get:r,reset:i}}function r(e){let t;function n(){return t||=e().catch(e=>{throw t=void 0,e}),t}function r(){t=void 0}return{get:n,reset:r}}exports.Flag=t,exports.ResettableValue=e,exports.resettableLazy=n,exports.resettableLazyAsync=r;
@@ -0,0 +1,88 @@
1
+ //#region src/state.d.ts
2
+ /**
3
+ * Holds a mutable value and remembers its initial value so it can be restored.
4
+ *
5
+ * @typeParam T Type of the held value.
6
+ */
7
+ declare class ResettableValue<T> {
8
+ #private;
9
+ /**
10
+ * The current value.
11
+ */
12
+ value: T;
13
+ /**
14
+ * Create a resettable value.
15
+ *
16
+ * @param value Initial value to store and reset back to.
17
+ */
18
+ constructor(value: T);
19
+ /**
20
+ * Set the current value.
21
+ *
22
+ * @param value New value to assign.
23
+ */
24
+ set(value: T): void;
25
+ /**
26
+ * Restore the value back to its initial constructor value.
27
+ */
28
+ reset(): void;
29
+ /**
30
+ * Return the current value for primitive coercion.
31
+ *
32
+ * @returns The current value.
33
+ */
34
+ valueOf(): T;
35
+ /**
36
+ * Convert the current value to a string.
37
+ *
38
+ * @returns The string representation of the current value.
39
+ */
40
+ toString(): string;
41
+ }
42
+ /**
43
+ * A resettable boolean helper with convenience setters and state checks.
44
+ */
45
+ declare class Flag extends ResettableValue<boolean> {
46
+ /**
47
+ * Create a new flag.
48
+ *
49
+ * @param value Initial flag value. Defaults to `false`.
50
+ */
51
+ constructor(value?: boolean);
52
+ /**
53
+ * Whether the flag is currently `true`.
54
+ */
55
+ get isTrue(): boolean;
56
+ /**
57
+ * Whether the flag is currently `false`.
58
+ */
59
+ get isFalse(): boolean;
60
+ /**
61
+ * Set the flag value.
62
+ *
63
+ * @param value Value to assign.
64
+ */
65
+ set(value: boolean): void;
66
+ /**
67
+ * Set the flag to `true`.
68
+ */
69
+ setTrue(): void;
70
+ /**
71
+ * Set the flag to `false`.
72
+ */
73
+ setFalse(): void;
74
+ /**
75
+ * Invert the current flag value.
76
+ */
77
+ toggle(): void;
78
+ }
79
+ declare function resettableLazy<T>(factory: () => T): {
80
+ get: () => T;
81
+ reset: () => void;
82
+ };
83
+ declare function resettableLazyAsync<T>(factory: () => Promise<T>): {
84
+ get: () => Promise<T>;
85
+ reset: () => void;
86
+ };
87
+ //#endregion
88
+ export { Flag, ResettableValue, resettableLazy, resettableLazyAsync };
@@ -0,0 +1,88 @@
1
+ //#region src/state.d.ts
2
+ /**
3
+ * Holds a mutable value and remembers its initial value so it can be restored.
4
+ *
5
+ * @typeParam T Type of the held value.
6
+ */
7
+ declare class ResettableValue<T> {
8
+ #private;
9
+ /**
10
+ * The current value.
11
+ */
12
+ value: T;
13
+ /**
14
+ * Create a resettable value.
15
+ *
16
+ * @param value Initial value to store and reset back to.
17
+ */
18
+ constructor(value: T);
19
+ /**
20
+ * Set the current value.
21
+ *
22
+ * @param value New value to assign.
23
+ */
24
+ set(value: T): void;
25
+ /**
26
+ * Restore the value back to its initial constructor value.
27
+ */
28
+ reset(): void;
29
+ /**
30
+ * Return the current value for primitive coercion.
31
+ *
32
+ * @returns The current value.
33
+ */
34
+ valueOf(): T;
35
+ /**
36
+ * Convert the current value to a string.
37
+ *
38
+ * @returns The string representation of the current value.
39
+ */
40
+ toString(): string;
41
+ }
42
+ /**
43
+ * A resettable boolean helper with convenience setters and state checks.
44
+ */
45
+ declare class Flag extends ResettableValue<boolean> {
46
+ /**
47
+ * Create a new flag.
48
+ *
49
+ * @param value Initial flag value. Defaults to `false`.
50
+ */
51
+ constructor(value?: boolean);
52
+ /**
53
+ * Whether the flag is currently `true`.
54
+ */
55
+ get isTrue(): boolean;
56
+ /**
57
+ * Whether the flag is currently `false`.
58
+ */
59
+ get isFalse(): boolean;
60
+ /**
61
+ * Set the flag value.
62
+ *
63
+ * @param value Value to assign.
64
+ */
65
+ set(value: boolean): void;
66
+ /**
67
+ * Set the flag to `true`.
68
+ */
69
+ setTrue(): void;
70
+ /**
71
+ * Set the flag to `false`.
72
+ */
73
+ setFalse(): void;
74
+ /**
75
+ * Invert the current flag value.
76
+ */
77
+ toggle(): void;
78
+ }
79
+ declare function resettableLazy<T>(factory: () => T): {
80
+ get: () => T;
81
+ reset: () => void;
82
+ };
83
+ declare function resettableLazyAsync<T>(factory: () => Promise<T>): {
84
+ get: () => Promise<T>;
85
+ reset: () => void;
86
+ };
87
+ //#endregion
88
+ export { Flag, ResettableValue, resettableLazy, resettableLazyAsync };
package/dist/state.mjs ADDED
@@ -0,0 +1 @@
1
+ var e=class{value;#e;constructor(e){this.value=e,this.#e=e}set(e){this.value=e}reset(){this.value=this.#e}valueOf(){return this.value}toString(){return String(this.value)}},t=class extends e{constructor(e=!1){super(e)}get isTrue(){return this.value===!0}get isFalse(){return!this.isTrue}set(e){super.set(e)}setTrue(){this.value=!0}setFalse(){this.value=!1}toggle(){this.value=!this.value}};function n(e){let t,n=!1;function r(){return n||=(t=e(),!0),t}function i(){n=!1,t=void 0}return{get:r,reset:i}}function r(e){let t;function n(){return t||=e().catch(e=>{throw t=void 0,e}),t}function r(){t=void 0}return{get:n,reset:r}}export{t as Flag,e as ResettableValue,n as resettableLazy,r as resettableLazyAsync};
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=function(e){return e[e.None=0]=`None`,e[e.Full=1]=`Full`,e[e.Equal=2]=`Equal`,e}({});function t(e){return new Promise(t=>setTimeout(t,e))}function n(e){return new Promise((t,n)=>setTimeout(n,e))}async function r(e,n=100,r=5e3){let i=Date.now();for(;!await e();){if(Date.now()-i>r)throw Error(`Timeout exceeded`);await t(n)}}async function i(e,t){let n;try{return await Promise.race([e,new Promise((e,r)=>{n=setTimeout(()=>r(Error(`Operation timed out`)),t)})])}finally{n!==void 0&&clearTimeout(n)}}function a(){let e=Error(`Aborted`);return e.name=`AbortError`,e}function o(e){if(e?.aborted)throw a()}async function s(e,t){if(e<=0){o(t);return}await new Promise((n,r)=>{let i=setTimeout(()=>{t&&t.removeEventListener(`abort`,o),n()},e);function o(){clearTimeout(i),t?.removeEventListener(`abort`,o),r(a())}t&&t.addEventListener(`abort`,o,{once:!0})})}function c(e){if(!Number.isFinite(e)||e<0)throw Error(`ms must be a finite number >= 0`);let t=new AbortController,n=setTimeout(()=>t.abort(),e);return t.signal.addEventListener(`abort`,()=>clearTimeout(n),{once:!0}),t.signal}function l(...e){let t=e.filter(e=>e!==void 0),n=new AbortController,r=new Map,i=()=>{if(!n.signal.aborted){n.abort();for(let[e,t]of r)e.removeEventListener(`abort`,t);r.clear()}};for(let e of t){if(e.aborted){i();break}let t=()=>i();r.set(e,t),e.addEventListener(`abort`,t,{once:!0})}return n.signal}async function u(e,t){return o(t),await new Promise((n,r)=>{function i(){t.removeEventListener(`abort`,i),r(a())}t.addEventListener(`abort`,i,{once:!0}),Promise.resolve(e).then(e=>{t.removeEventListener(`abort`,i),n(e)},e=>{t.removeEventListener(`abort`,i),r(e)})})}function d(t,n){return n===e.None?t:n===e.Full?Math.floor(Math.random()*t):Math.floor(t/2+t/2*Math.random())}async function f(t,n={}){let r=n.attempts??3,i=n.baseMs??100,a=n.maxMs??1/0,c=n.jitter??e.None;if(!Number.isInteger(r)||r<1)throw Error(`attempts must be an integer >= 1`);if(i<0||!Number.isFinite(i))throw Error(`baseMs must be a finite number >= 0`);if(a<0||Number.isNaN(a))throw Error(`maxMs must be a number >= 0`);for(let e=1;e<=r;e++){o(n.signal);try{return await t(e)}catch(t){if(e>=r||n.shouldRetry&&!await n.shouldRetry(t,e))throw t;await s(d(Math.min(i*2**(e-1),a),c),n.signal)}}throw Error(`Unreachable`)}exports.RetryJitter=e,exports.abortAfter=c,exports.pollUntil=r,exports.raceSignals=l,exports.rejectionTimeout=n,exports.retry=f,exports.timeout=t,exports.withAbort=u,exports.withTimeout=i;
@@ -0,0 +1,71 @@
1
+ import { Awaitable } from "./typing.cjs";
2
+
3
+ //#region src/timing.d.ts
4
+ interface IRetryOptions {
5
+ attempts?: number;
6
+ baseMs?: number;
7
+ maxMs?: number;
8
+ jitter?: RetryJitter;
9
+ signal?: AbortSignal;
10
+ shouldRetry?: (error: unknown, attempt: number) => Awaitable<boolean>;
11
+ }
12
+ declare const enum RetryJitter {
13
+ None = 0,
14
+ Full = 1,
15
+ Equal = 2
16
+ }
17
+ /**
18
+ * Returns a promise after the provided {@link ms} has passed
19
+ * @param ms The number of milliseconds to wait
20
+ */
21
+ declare function timeout(ms: number): Promise<unknown>;
22
+ /**
23
+ * Rejects a promise after the provided {@link ms} has passed
24
+ * @param ms The number of milliseconds to wait
25
+ */
26
+ declare function rejectionTimeout(ms: number): Promise<unknown>;
27
+ /**
28
+ * Polls until the provided condition is met, or the timeout is exceeded.
29
+ *
30
+ * @param condition A function that returns a boolean or a promise that resolves to a boolean
31
+ * @param interval The interval in milliseconds to wait between checks
32
+ * @param timeoutMs The maximum time in milliseconds to wait before throwing an error
33
+ */
34
+ declare function pollUntil(condition: () => Awaitable<boolean>, interval?: number, timeoutMs?: number): Promise<void>;
35
+ /**
36
+ * Wraps a promise with a timeout. If the promise does not resolve within the specified time, an error is thrown.
37
+ *
38
+ * @param promise The promise to wrap with a timeout
39
+ * @param ms The number of milliseconds to wait before timing out
40
+ *
41
+ * @returns The result of the promise if it resolves before the timeout, otherwise throws an error
42
+ */
43
+ declare function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T>;
44
+ /**
45
+ * Returns an AbortSignal that aborts automatically after the given number of milliseconds.
46
+ *
47
+ * @param ms Delay before automatic abort.
48
+ */
49
+ declare function abortAfter(ms: number): AbortSignal;
50
+ /**
51
+ * Returns a signal that aborts when any of the input signals aborts.
52
+ *
53
+ * @param signals Input abort signals.
54
+ */
55
+ declare function raceSignals(...signals: Array<AbortSignal | undefined>): AbortSignal;
56
+ /**
57
+ * Wraps a promise and rejects when the signal aborts before completion.
58
+ *
59
+ * @param promise Promise or value to await.
60
+ * @param signal Abort signal to monitor.
61
+ */
62
+ declare function withAbort<T>(promise: Awaitable<T>, signal: AbortSignal): Promise<T>;
63
+ /**
64
+ * Retries an operation with exponential backoff.
65
+ *
66
+ * @param fn Operation to run for each attempt.
67
+ * @param options Retry options controlling attempts, backoff, jitter, and cancellation.
68
+ */
69
+ declare function retry<T>(fn: (attempt: number) => Awaitable<T>, options?: IRetryOptions): Promise<T>;
70
+ //#endregion
71
+ export { IRetryOptions, RetryJitter, abortAfter, pollUntil, raceSignals, rejectionTimeout, retry, timeout, withAbort, withTimeout };
@@ -0,0 +1,71 @@
1
+ import { Awaitable } from "./typing.mjs";
2
+
3
+ //#region src/timing.d.ts
4
+ interface IRetryOptions {
5
+ attempts?: number;
6
+ baseMs?: number;
7
+ maxMs?: number;
8
+ jitter?: RetryJitter;
9
+ signal?: AbortSignal;
10
+ shouldRetry?: (error: unknown, attempt: number) => Awaitable<boolean>;
11
+ }
12
+ declare const enum RetryJitter {
13
+ None = 0,
14
+ Full = 1,
15
+ Equal = 2
16
+ }
17
+ /**
18
+ * Returns a promise after the provided {@link ms} has passed
19
+ * @param ms The number of milliseconds to wait
20
+ */
21
+ declare function timeout(ms: number): Promise<unknown>;
22
+ /**
23
+ * Rejects a promise after the provided {@link ms} has passed
24
+ * @param ms The number of milliseconds to wait
25
+ */
26
+ declare function rejectionTimeout(ms: number): Promise<unknown>;
27
+ /**
28
+ * Polls until the provided condition is met, or the timeout is exceeded.
29
+ *
30
+ * @param condition A function that returns a boolean or a promise that resolves to a boolean
31
+ * @param interval The interval in milliseconds to wait between checks
32
+ * @param timeoutMs The maximum time in milliseconds to wait before throwing an error
33
+ */
34
+ declare function pollUntil(condition: () => Awaitable<boolean>, interval?: number, timeoutMs?: number): Promise<void>;
35
+ /**
36
+ * Wraps a promise with a timeout. If the promise does not resolve within the specified time, an error is thrown.
37
+ *
38
+ * @param promise The promise to wrap with a timeout
39
+ * @param ms The number of milliseconds to wait before timing out
40
+ *
41
+ * @returns The result of the promise if it resolves before the timeout, otherwise throws an error
42
+ */
43
+ declare function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T>;
44
+ /**
45
+ * Returns an AbortSignal that aborts automatically after the given number of milliseconds.
46
+ *
47
+ * @param ms Delay before automatic abort.
48
+ */
49
+ declare function abortAfter(ms: number): AbortSignal;
50
+ /**
51
+ * Returns a signal that aborts when any of the input signals aborts.
52
+ *
53
+ * @param signals Input abort signals.
54
+ */
55
+ declare function raceSignals(...signals: Array<AbortSignal | undefined>): AbortSignal;
56
+ /**
57
+ * Wraps a promise and rejects when the signal aborts before completion.
58
+ *
59
+ * @param promise Promise or value to await.
60
+ * @param signal Abort signal to monitor.
61
+ */
62
+ declare function withAbort<T>(promise: Awaitable<T>, signal: AbortSignal): Promise<T>;
63
+ /**
64
+ * Retries an operation with exponential backoff.
65
+ *
66
+ * @param fn Operation to run for each attempt.
67
+ * @param options Retry options controlling attempts, backoff, jitter, and cancellation.
68
+ */
69
+ declare function retry<T>(fn: (attempt: number) => Awaitable<T>, options?: IRetryOptions): Promise<T>;
70
+ //#endregion
71
+ export { IRetryOptions, RetryJitter, abortAfter, pollUntil, raceSignals, rejectionTimeout, retry, timeout, withAbort, withTimeout };
@@ -0,0 +1 @@
1
+ let e=function(e){return e[e.None=0]=`None`,e[e.Full=1]=`Full`,e[e.Equal=2]=`Equal`,e}({});function t(e){return new Promise(t=>setTimeout(t,e))}function n(e){return new Promise((t,n)=>setTimeout(n,e))}async function r(e,n=100,r=5e3){let i=Date.now();for(;!await e();){if(Date.now()-i>r)throw Error(`Timeout exceeded`);await t(n)}}async function i(e,t){let n;try{return await Promise.race([e,new Promise((e,r)=>{n=setTimeout(()=>r(Error(`Operation timed out`)),t)})])}finally{n!==void 0&&clearTimeout(n)}}function a(){let e=Error(`Aborted`);return e.name=`AbortError`,e}function o(e){if(e?.aborted)throw a()}async function s(e,t){if(e<=0){o(t);return}await new Promise((n,r)=>{let i=setTimeout(()=>{t&&t.removeEventListener(`abort`,o),n()},e);function o(){clearTimeout(i),t?.removeEventListener(`abort`,o),r(a())}t&&t.addEventListener(`abort`,o,{once:!0})})}function c(e){if(!Number.isFinite(e)||e<0)throw Error(`ms must be a finite number >= 0`);let t=new AbortController,n=setTimeout(()=>t.abort(),e);return t.signal.addEventListener(`abort`,()=>clearTimeout(n),{once:!0}),t.signal}function l(...e){let t=e.filter(e=>e!==void 0),n=new AbortController,r=new Map,i=()=>{if(!n.signal.aborted){n.abort();for(let[e,t]of r)e.removeEventListener(`abort`,t);r.clear()}};for(let e of t){if(e.aborted){i();break}let t=()=>i();r.set(e,t),e.addEventListener(`abort`,t,{once:!0})}return n.signal}async function u(e,t){return o(t),await new Promise((n,r)=>{function i(){t.removeEventListener(`abort`,i),r(a())}t.addEventListener(`abort`,i,{once:!0}),Promise.resolve(e).then(e=>{t.removeEventListener(`abort`,i),n(e)},e=>{t.removeEventListener(`abort`,i),r(e)})})}function d(t,n){return n===e.None?t:n===e.Full?Math.floor(Math.random()*t):Math.floor(t/2+t/2*Math.random())}async function f(t,n={}){let r=n.attempts??3,i=n.baseMs??100,a=n.maxMs??1/0,c=n.jitter??e.None;if(!Number.isInteger(r)||r<1)throw Error(`attempts must be an integer >= 1`);if(i<0||!Number.isFinite(i))throw Error(`baseMs must be a finite number >= 0`);if(a<0||Number.isNaN(a))throw Error(`maxMs must be a number >= 0`);for(let e=1;e<=r;e++){o(n.signal);try{return await t(e)}catch(t){if(e>=r||n.shouldRetry&&!await n.shouldRetry(t,e))throw t;await s(d(Math.min(i*2**(e-1),a),c),n.signal)}}throw Error(`Unreachable`)}export{e as RetryJitter,c as abortAfter,r as pollUntil,l as raceSignals,n as rejectionTimeout,f as retry,t as timeout,u as withAbort,i as withTimeout};
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=e=>e;function t(e){}function n(e){return Object.entries(e)}function r(e){return{ok:!0,value:e}}function i(e){return{ok:!1,error:e}}function a(e){return e.ok}function o(e,t){return e.ok?r(t(e.value)):e}function s(e,t){return e.ok?e:i(t(e.error))}async function c(e,t){try{return r(await e())}catch(e){return i(t?t(e):e)}}exports.assume=t,exports.cast=e,exports.err=i,exports.isOk=a,exports.mapErr=s,exports.mapOk=o,exports.ok=r,exports.tryCatchAsync=c,exports.typedEntries=n;
@@ -0,0 +1,26 @@
1
+ //#region src/typing.d.ts
2
+ type Awaitable<T> = PromiseLike<T> | T;
3
+ type Maybe<T> = T | undefined;
4
+ type Nullable<T> = T | null;
5
+ type Result<T, E = unknown> = {
6
+ ok: true;
7
+ value: T;
8
+ } | {
9
+ ok: false;
10
+ error: E;
11
+ };
12
+ declare const cast: <T, U extends T>(value: U) => U;
13
+ declare function assume<T>(value: unknown): asserts value is T;
14
+ declare function typedEntries<T extends object>(obj: T): { [K in keyof T]: [K, T[K]] }[keyof T][];
15
+ declare function ok<T>(value: T): Result<T, never>;
16
+ declare function err<E>(error: E): Result<never, E>;
17
+ declare function isOk<T, E>(result: Result<T, E>): result is {
18
+ ok: true;
19
+ value: T;
20
+ };
21
+ declare function mapOk<T, U, E>(result: Result<T, E>, mapper: (value: T) => U): Result<U, E>;
22
+ declare function mapErr<T, E, F>(result: Result<T, E>, mapper: (error: E) => F): Result<T, F>;
23
+ declare function tryCatchAsync<T>(operation: () => Awaitable<T>): Promise<Result<T, unknown>>;
24
+ declare function tryCatchAsync<T, E>(operation: () => Awaitable<T>, mapError: (error: unknown) => E): Promise<Result<T, E>>;
25
+ //#endregion
26
+ export { Awaitable, Maybe, Nullable, Result, assume, cast, err, isOk, mapErr, mapOk, ok, tryCatchAsync, typedEntries };
@@ -0,0 +1,26 @@
1
+ //#region src/typing.d.ts
2
+ type Awaitable<T> = PromiseLike<T> | T;
3
+ type Maybe<T> = T | undefined;
4
+ type Nullable<T> = T | null;
5
+ type Result<T, E = unknown> = {
6
+ ok: true;
7
+ value: T;
8
+ } | {
9
+ ok: false;
10
+ error: E;
11
+ };
12
+ declare const cast: <T, U extends T>(value: U) => U;
13
+ declare function assume<T>(value: unknown): asserts value is T;
14
+ declare function typedEntries<T extends object>(obj: T): { [K in keyof T]: [K, T[K]] }[keyof T][];
15
+ declare function ok<T>(value: T): Result<T, never>;
16
+ declare function err<E>(error: E): Result<never, E>;
17
+ declare function isOk<T, E>(result: Result<T, E>): result is {
18
+ ok: true;
19
+ value: T;
20
+ };
21
+ declare function mapOk<T, U, E>(result: Result<T, E>, mapper: (value: T) => U): Result<U, E>;
22
+ declare function mapErr<T, E, F>(result: Result<T, E>, mapper: (error: E) => F): Result<T, F>;
23
+ declare function tryCatchAsync<T>(operation: () => Awaitable<T>): Promise<Result<T, unknown>>;
24
+ declare function tryCatchAsync<T, E>(operation: () => Awaitable<T>, mapError: (error: unknown) => E): Promise<Result<T, E>>;
25
+ //#endregion
26
+ export { Awaitable, Maybe, Nullable, Result, assume, cast, err, isOk, mapErr, mapOk, ok, tryCatchAsync, typedEntries };
@@ -0,0 +1 @@
1
+ const e=e=>e;function t(e){}function n(e){return Object.entries(e)}function r(e){return{ok:!0,value:e}}function i(e){return{ok:!1,error:e}}function a(e){return e.ok}function o(e,t){return e.ok?r(t(e.value)):e}function s(e,t){return e.ok?e:i(t(e.error))}async function c(e,t){try{return r(await e())}catch(e){return i(t?t(e):e)}}export{t as assume,e as cast,i as err,a as isOk,s as mapErr,o as mapOk,r as ok,c as tryCatchAsync,n as typedEntries};
package/dist/url.cjs ADDED
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e,...t){let n=``;for(let r=0;r<e.length;r++)n+=e[r],r<t.length&&(n+=encodeURIComponent(String(t[r])));return n}function t(e,n,r){if(r!=null){if(Array.isArray(r)){for(let i of r)t(e,n,i);return}if(typeof r==`object`){try{e.append(n,JSON.stringify(r))}catch{e.append(n,String(r))}return}e.append(n,String(r))}}var n=class e{#e;constructor(t,n){t instanceof e||t instanceof URL?this.#e=new URL(t.toString()):n?this.#e=new URL(t,n.toString()):this.#e=new URL(t)}get protocol(){return this.#e.protocol}get host(){return this.#e.host}get hostname(){return this.#e.hostname}get port(){return this.#e.port}get origin(){return this.#e.origin}get username(){return this.#e.username}get password(){return this.#e.password}get hash(){return this.#e.hash}get search(){return this.#e.search}get searchParams(){return new URLSearchParams(this.#e.search)}get pathname(){return this.#e.pathname}get parts(){return this.#e.pathname.split(`/`).filter(Boolean).map(decodeURIComponent)}get name(){return this.parts.at(-1)??``}get suffix(){let e=this.name,t=e.lastIndexOf(`.`);return t>=0?e.slice(t):``}get stem(){let e=this.name,t=e.lastIndexOf(`.`);return t>=0?e.slice(0,t):e}get parent(){let e=this.parts.slice(0,-1);return this.withPath(e)}joinpath(...e){let t=[...this.parts,...e.map(e=>e.replace(/^\/+|\/+$/g,``))];return this.withPath(t)}div(...e){return this.joinpath(...e)}withPath(t){let n=new URL(this.#e.toString());return n.pathname=`/`+t.map(encodeURIComponent).join(`/`),new e(n)}withQuery(n){let r=new URL(this.#e.toString());for(let[e,i]of Object.entries(n))r.searchParams.delete(e),t(r.searchParams,e,i);return new e(r)}withQueryPatch(e){return this.withQuery(e)}appendQuery(n){let r=new URL(this.#e.toString());for(let[e,i]of Object.entries(n))t(r.searchParams,e,i);return new e(r)}withoutEmptyQuery(){let t=new URL(this.#e.toString()),n=new Set;for(let e of t.searchParams.keys())n.has(e)||(n.add(e),t.searchParams.getAll(e).every(e=>e===``)&&t.searchParams.delete(e));return new e(t)}withoutQuery(...t){let n=new URL(this.#e.toString());for(let e of t)n.searchParams.delete(e);return new e(n)}withHash(t){let n=new URL(this.#e.toString());return n.hash=t.startsWith(`#`)?t:`#${t}`,new e(n)}withoutHash(){let t=new URL(this.#e.toString());return t.hash=``,new e(t)}async fetch(e){return fetch(this.#e,e)}resolve(t){return new e(t,this)}equals(t){return this.toString()===new e(t).toString()}toURL(){return new URL(this.#e.toString())}toString(){return this.#e.toString()}valueOf(){return this.toString()}[Symbol.toPrimitive](){return this.toString()}static from(t,n){return new e(t,n)}static parse(t){return new e(t)}};exports.URLPath=n,exports.url=e;
@@ -1,7 +1,14 @@
1
- //#region src/urllib.d.ts
1
+ //#region src/url.d.ts
2
2
  type URLLike = string | URL | URLPath;
3
3
  type QueryValue = string | number | undefined | null | boolean | Array<QueryValue> | Record<string, any>;
4
4
  type QueryObject = Record<string, QueryValue | QueryValue[]>;
5
+ /**
6
+ * Tagged-template helper for encoded URL path segments.
7
+ *
8
+ * @example
9
+ * const path = url`/users/${userId}/posts/${postId}`;
10
+ */
11
+ declare function url(strings: TemplateStringsArray, ...values: unknown[]): string;
5
12
  declare class URLPath {
6
13
  #private;
7
14
  constructor(input: URLLike, base?: URLLike);
@@ -25,6 +32,9 @@ declare class URLPath {
25
32
  div(...segments: string[]): URLPath;
26
33
  private withPath;
27
34
  withQuery(params: QueryObject): URLPath;
35
+ withQueryPatch(params: QueryObject): URLPath;
36
+ appendQuery(params: QueryObject): URLPath;
37
+ withoutEmptyQuery(): URLPath;
28
38
  withoutQuery(...keys: string[]): URLPath;
29
39
  withHash(hash: string): URLPath;
30
40
  withoutHash(): URLPath;
@@ -39,4 +49,4 @@ declare class URLPath {
39
49
  static parse(input: string): URLPath;
40
50
  }
41
51
  //#endregion
42
- export { QueryObject, QueryValue, URLLike, URLPath };
52
+ export { QueryObject, QueryValue, URLLike, URLPath, url };
@@ -1,7 +1,14 @@
1
- //#region src/urllib.d.ts
1
+ //#region src/url.d.ts
2
2
  type URLLike = string | URL | URLPath;
3
3
  type QueryValue = string | number | undefined | null | boolean | Array<QueryValue> | Record<string, any>;
4
4
  type QueryObject = Record<string, QueryValue | QueryValue[]>;
5
+ /**
6
+ * Tagged-template helper for encoded URL path segments.
7
+ *
8
+ * @example
9
+ * const path = url`/users/${userId}/posts/${postId}`;
10
+ */
11
+ declare function url(strings: TemplateStringsArray, ...values: unknown[]): string;
5
12
  declare class URLPath {
6
13
  #private;
7
14
  constructor(input: URLLike, base?: URLLike);
@@ -25,6 +32,9 @@ declare class URLPath {
25
32
  div(...segments: string[]): URLPath;
26
33
  private withPath;
27
34
  withQuery(params: QueryObject): URLPath;
35
+ withQueryPatch(params: QueryObject): URLPath;
36
+ appendQuery(params: QueryObject): URLPath;
37
+ withoutEmptyQuery(): URLPath;
28
38
  withoutQuery(...keys: string[]): URLPath;
29
39
  withHash(hash: string): URLPath;
30
40
  withoutHash(): URLPath;
@@ -39,4 +49,4 @@ declare class URLPath {
39
49
  static parse(input: string): URLPath;
40
50
  }
41
51
  //#endregion
42
- export { QueryObject, QueryValue, URLLike, URLPath };
52
+ export { QueryObject, QueryValue, URLLike, URLPath, url };
package/dist/url.mjs ADDED
@@ -0,0 +1 @@
1
+ function e(e,...t){let n=``;for(let r=0;r<e.length;r++)n+=e[r],r<t.length&&(n+=encodeURIComponent(String(t[r])));return n}function t(e,n,r){if(r!=null){if(Array.isArray(r)){for(let i of r)t(e,n,i);return}if(typeof r==`object`){try{e.append(n,JSON.stringify(r))}catch{e.append(n,String(r))}return}e.append(n,String(r))}}var n=class e{#e;constructor(t,n){t instanceof e||t instanceof URL?this.#e=new URL(t.toString()):n?this.#e=new URL(t,n.toString()):this.#e=new URL(t)}get protocol(){return this.#e.protocol}get host(){return this.#e.host}get hostname(){return this.#e.hostname}get port(){return this.#e.port}get origin(){return this.#e.origin}get username(){return this.#e.username}get password(){return this.#e.password}get hash(){return this.#e.hash}get search(){return this.#e.search}get searchParams(){return new URLSearchParams(this.#e.search)}get pathname(){return this.#e.pathname}get parts(){return this.#e.pathname.split(`/`).filter(Boolean).map(decodeURIComponent)}get name(){return this.parts.at(-1)??``}get suffix(){let e=this.name,t=e.lastIndexOf(`.`);return t>=0?e.slice(t):``}get stem(){let e=this.name,t=e.lastIndexOf(`.`);return t>=0?e.slice(0,t):e}get parent(){let e=this.parts.slice(0,-1);return this.withPath(e)}joinpath(...e){let t=[...this.parts,...e.map(e=>e.replace(/^\/+|\/+$/g,``))];return this.withPath(t)}div(...e){return this.joinpath(...e)}withPath(t){let n=new URL(this.#e.toString());return n.pathname=`/`+t.map(encodeURIComponent).join(`/`),new e(n)}withQuery(n){let r=new URL(this.#e.toString());for(let[e,i]of Object.entries(n))r.searchParams.delete(e),t(r.searchParams,e,i);return new e(r)}withQueryPatch(e){return this.withQuery(e)}appendQuery(n){let r=new URL(this.#e.toString());for(let[e,i]of Object.entries(n))t(r.searchParams,e,i);return new e(r)}withoutEmptyQuery(){let t=new URL(this.#e.toString()),n=new Set;for(let e of t.searchParams.keys())n.has(e)||(n.add(e),t.searchParams.getAll(e).every(e=>e===``)&&t.searchParams.delete(e));return new e(t)}withoutQuery(...t){let n=new URL(this.#e.toString());for(let e of t)n.searchParams.delete(e);return new e(n)}withHash(t){let n=new URL(this.#e.toString());return n.hash=t.startsWith(`#`)?t:`#${t}`,new e(n)}withoutHash(){let t=new URL(this.#e.toString());return t.hash=``,new e(t)}async fetch(e){return fetch(this.#e,e)}resolve(t){return new e(t,this)}equals(t){return this.toString()===new e(t).toString()}toURL(){return new URL(this.#e.toString())}toString(){return this.#e.toString()}valueOf(){return this.toString()}[Symbol.toPrimitive](){return this.toString()}static from(t,n){return new e(t,n)}static parse(t){return new e(t)}};export{n as URLPath,e as url};