@backendkit-labs/result 0.1.0 → 0.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.
package/README.md CHANGED
@@ -587,7 +587,7 @@ const result = await retry(
587
587
 
588
588
  ### `retryWithBackoff(fn, options)`
589
589
 
590
- Exponential backoff: delay doubles on each retry, capped at `maxDelayMs`.
590
+ Exponential backoff: delay doubles on each retry, capped at `maxDelayMs`. Supports **jitter** to prevent thundering herd when multiple instances retry simultaneously.
591
591
 
592
592
  ```typescript
593
593
  import { retryWithBackoff, run } from '@backendkit-labs/result';
@@ -616,6 +616,37 @@ const result = await retryWithBackoff(
616
616
  );
617
617
  ```
618
618
 
619
+ #### Jitter
620
+
621
+ When many instances of your service fail at the same time (e.g. a downstream goes down), they all retry on the same schedule — creating a synchronized spike that can overwhelm the recovering service. Jitter spreads those retries across time.
622
+
623
+ ```typescript
624
+ // Full jitter — delay = random(0, computedDelay)
625
+ // Maximum spread. Best for high-concurrency scenarios (many parallel clients).
626
+ await retryWithBackoff(() => run(() => callApi()), {
627
+ attempts: 4,
628
+ delayMs: 500,
629
+ maxDelayMs: 10_000,
630
+ jitter: true,
631
+ });
632
+
633
+ // Partial jitter — delay ± (computedDelay × factor)
634
+ // Keeps delays close to the backoff curve while adding noise.
635
+ // 0.25 = ±25%: a computed 1000ms delay becomes 750ms–1250ms.
636
+ await retryWithBackoff(() => run(() => callApi()), {
637
+ attempts: 4,
638
+ delayMs: 500,
639
+ maxDelayMs: 10_000,
640
+ jitter: 0.25,
641
+ });
642
+ ```
643
+
644
+ | `jitter` value | Behaviour | Use when |
645
+ |---|---|---|
646
+ | `false` / omitted | No randomness — deterministic delays | Tests, single-instance services |
647
+ | `true` | Full jitter: `random(0, delay)` | Many parallel clients retrying the same service |
648
+ | `0.0–1.0` | Partial jitter: `delay ± (delay × factor)` | You want backoff shape preserved with light noise |
649
+
619
650
  ### `withTimeout(fn, ms, timeoutError)`
620
651
 
621
652
  Races a Result-returning function against a deadline.
@@ -0,0 +1,100 @@
1
+ 'use strict';
2
+
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __decorateClass = (decorators, target, key, kind) => {
6
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
7
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
8
+ if (decorator = decorators[i])
9
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
10
+ if (kind && result) __defProp(target, key, result);
11
+ return result;
12
+ };
13
+
14
+ // src/result/constructors.ts
15
+ var ok = (value) => ({ ok: true, value });
16
+ var fail = (error) => ({ ok: false, error });
17
+ function fromThrowable(fn, errorTransform) {
18
+ try {
19
+ return ok(fn());
20
+ } catch (caught) {
21
+ return fail(errorTransform ? errorTransform(caught) : caught);
22
+ }
23
+ }
24
+ async function fromPromise(promise, errorTransform) {
25
+ try {
26
+ return ok(await promise);
27
+ } catch (caught) {
28
+ return fail(errorTransform ? errorTransform(caught) : caught);
29
+ }
30
+ }
31
+ function fromNullable(value, error) {
32
+ return value != null ? ok(value) : fail(error);
33
+ }
34
+
35
+ // src/result/guards.ts
36
+ function isOk(result) {
37
+ return result.ok === true;
38
+ }
39
+ function isFail(result) {
40
+ return result.ok === false;
41
+ }
42
+ function isRich(result) {
43
+ return "durationMs" in result;
44
+ }
45
+
46
+ // src/result/run.ts
47
+ async function run(fn, errorTransform) {
48
+ try {
49
+ return ok(await fn());
50
+ } catch (caught) {
51
+ return fail(errorTransform ? errorTransform(caught) : caught);
52
+ }
53
+ }
54
+ async function track(fn, options) {
55
+ const start = performance.now();
56
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
57
+ const meta = {
58
+ durationMs: 0,
59
+ timestamp,
60
+ operation: options?.operation,
61
+ correlationId: options?.correlationId,
62
+ tags: options?.tags
63
+ };
64
+ try {
65
+ const value = await fn();
66
+ return { ok: true, value, ...meta, durationMs: Math.round(performance.now() - start) };
67
+ } catch (caught) {
68
+ const error = options?.errorTransform ? options.errorTransform(caught) : caught;
69
+ return { ok: false, error, ...meta, durationMs: Math.round(performance.now() - start) };
70
+ }
71
+ }
72
+ function enrich(result, options) {
73
+ return {
74
+ ...result,
75
+ durationMs: 0,
76
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
77
+ operation: options?.operation,
78
+ correlationId: options?.correlationId,
79
+ tags: options?.tags
80
+ };
81
+ }
82
+ function simplify(rich) {
83
+ return rich.ok ? { ok: true, value: rich.value } : { ok: false, error: rich.error };
84
+ }
85
+
86
+ exports.__decorateClass = __decorateClass;
87
+ exports.enrich = enrich;
88
+ exports.fail = fail;
89
+ exports.fromNullable = fromNullable;
90
+ exports.fromPromise = fromPromise;
91
+ exports.fromThrowable = fromThrowable;
92
+ exports.isFail = isFail;
93
+ exports.isOk = isOk;
94
+ exports.isRich = isRich;
95
+ exports.ok = ok;
96
+ exports.run = run;
97
+ exports.simplify = simplify;
98
+ exports.track = track;
99
+ //# sourceMappingURL=chunk-GCGL2Y6D.cjs.map
100
+ //# sourceMappingURL=chunk-GCGL2Y6D.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/result/constructors.ts","../src/result/guards.ts","../src/result/run.ts"],"names":[],"mappings":"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","file":"chunk-GCGL2Y6D.cjs","sourcesContent":["import type { Result } from './types.js';\n\n/** Creates a successful Result. */\nexport const ok = <T, E = never>(value: T): Result<T, E> =>\n ({ ok: true, value });\n\n/** Creates a failed Result. */\nexport const fail = <T = never, E = Error>(error: E): Result<T, E> =>\n ({ ok: false, error });\n\n/**\n * Wraps a synchronous throwable function. Catches any thrown value and\n * passes it through `errorTransform` (defaults to identity cast).\n *\n * @example\n * const result = fromThrowable(() => JSON.parse(raw), (e) => new ParseError(e));\n */\nexport function fromThrowable<T, E = Error>(\n fn: () => T,\n errorTransform?: (caught: unknown) => E,\n): Result<T, E> {\n try {\n return ok(fn());\n } catch (caught) {\n return fail(errorTransform ? errorTransform(caught) : (caught as E));\n }\n}\n\n/**\n * Converts a Promise to a `Promise<Result<T, E>>`, catching rejections.\n *\n * @example\n * const result = await fromPromise(fetch(url), (e) => new NetworkError(e));\n */\nexport async function fromPromise<T, E = Error>(\n promise: Promise<T>,\n errorTransform?: (caught: unknown) => E,\n): Promise<Result<T, E>> {\n try {\n return ok(await promise);\n } catch (caught) {\n return fail(errorTransform ? errorTransform(caught) : (caught as E));\n }\n}\n\n/**\n * Converts a nullable value to a Result.\n * Returns `ok(value)` if non-null/undefined, `fail(error)` otherwise.\n *\n * @example\n * const result = fromNullable(user, new NotFoundError('user'));\n */\nexport function fromNullable<T, E>(\n value: T | null | undefined,\n error: E,\n): Result<T, E> {\n return value != null ? ok(value) : fail(error);\n}\n","import type { Result, RichResult } from './types.js';\n\ntype OkResult<T, E> = Extract<Result<T, E>, { ok: true }>;\ntype FailResult<T, E> = Extract<Result<T, E>, { ok: false }>;\n\n/** Narrows a `Result<T, E>` to its success branch. */\nexport function isOk<T, E>(result: Result<T, E>): result is OkResult<T, E> {\n return result.ok === true;\n}\n\n/** Narrows a `Result<T, E>` to its failure branch. */\nexport function isFail<T, E>(result: Result<T, E>): result is FailResult<T, E> {\n return result.ok === false;\n}\n\n/** Returns `true` if the result carries observability metadata (`track()` output). */\nexport function isRich<T, E>(result: Result<T, E>): result is RichResult<T, E> {\n return 'durationMs' in result;\n}\n","import type { Result, RichResult, TrackOptions } from './types.js';\nimport { ok, fail } from './constructors.js';\n\n/**\n * Executes an async (or sync) function and captures any thrown exception,\n * returning a `Result<T, E>` instead of propagating the error.\n *\n * @example\n * const result = await run(() => fetchUser(id));\n * const result = await run(() => fetchUser(id), (e) => new UserError(e));\n */\nexport async function run<T, E = Error>(\n fn: () => T | Promise<T>,\n errorTransform?: (caught: unknown) => E,\n): Promise<Result<T, E>> {\n try {\n return ok(await fn());\n } catch (caught) {\n return fail(errorTransform ? errorTransform(caught) : (caught as E));\n }\n}\n\n/**\n * Like `run()` but also captures timing and metadata, returning a `RichResult<T, E>`.\n *\n * @example\n * const result = await track(() => fetchUser(id), { operation: 'user.fetch', tags: ['db'] });\n */\nexport async function track<T, E = Error>(\n fn: () => T | Promise<T>,\n options?: TrackOptions & { errorTransform?: (caught: unknown) => E },\n): Promise<RichResult<T, E>> {\n const start = performance.now();\n const timestamp = new Date().toISOString();\n const meta = {\n durationMs: 0,\n timestamp,\n operation: options?.operation,\n correlationId: options?.correlationId,\n tags: options?.tags,\n };\n\n try {\n const value = await fn();\n return { ok: true, value, ...meta, durationMs: Math.round(performance.now() - start) };\n } catch (caught) {\n const error = options?.errorTransform ? options.errorTransform(caught) : (caught as E);\n return { ok: false, error, ...meta, durationMs: Math.round(performance.now() - start) };\n }\n}\n\n/**\n * Promotes a plain `Result<T, E>` to a `RichResult<T, E>` with a zero-duration snapshot.\n * Useful when you already have a Result and want to attach metadata.\n */\nexport function enrich<T, E>(result: Result<T, E>, options?: TrackOptions): RichResult<T, E> {\n return {\n ...result,\n durationMs: 0,\n timestamp: new Date().toISOString(),\n operation: options?.operation,\n correlationId: options?.correlationId,\n tags: options?.tags,\n };\n}\n\n/**\n * Strips observability metadata from a `RichResult`, returning a plain `Result<T, E>`.\n */\nexport function simplify<T, E>(rich: RichResult<T, E>): Result<T, E> {\n return rich.ok\n ? { ok: true, value: rich.value }\n : { ok: false, error: rich.error };\n}\n"]}
@@ -0,0 +1,86 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result) __defProp(target, key, result);
9
+ return result;
10
+ };
11
+
12
+ // src/result/constructors.ts
13
+ var ok = (value) => ({ ok: true, value });
14
+ var fail = (error) => ({ ok: false, error });
15
+ function fromThrowable(fn, errorTransform) {
16
+ try {
17
+ return ok(fn());
18
+ } catch (caught) {
19
+ return fail(errorTransform ? errorTransform(caught) : caught);
20
+ }
21
+ }
22
+ async function fromPromise(promise, errorTransform) {
23
+ try {
24
+ return ok(await promise);
25
+ } catch (caught) {
26
+ return fail(errorTransform ? errorTransform(caught) : caught);
27
+ }
28
+ }
29
+ function fromNullable(value, error) {
30
+ return value != null ? ok(value) : fail(error);
31
+ }
32
+
33
+ // src/result/guards.ts
34
+ function isOk(result) {
35
+ return result.ok === true;
36
+ }
37
+ function isFail(result) {
38
+ return result.ok === false;
39
+ }
40
+ function isRich(result) {
41
+ return "durationMs" in result;
42
+ }
43
+
44
+ // src/result/run.ts
45
+ async function run(fn, errorTransform) {
46
+ try {
47
+ return ok(await fn());
48
+ } catch (caught) {
49
+ return fail(errorTransform ? errorTransform(caught) : caught);
50
+ }
51
+ }
52
+ async function track(fn, options) {
53
+ const start = performance.now();
54
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
55
+ const meta = {
56
+ durationMs: 0,
57
+ timestamp,
58
+ operation: options?.operation,
59
+ correlationId: options?.correlationId,
60
+ tags: options?.tags
61
+ };
62
+ try {
63
+ const value = await fn();
64
+ return { ok: true, value, ...meta, durationMs: Math.round(performance.now() - start) };
65
+ } catch (caught) {
66
+ const error = options?.errorTransform ? options.errorTransform(caught) : caught;
67
+ return { ok: false, error, ...meta, durationMs: Math.round(performance.now() - start) };
68
+ }
69
+ }
70
+ function enrich(result, options) {
71
+ return {
72
+ ...result,
73
+ durationMs: 0,
74
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
75
+ operation: options?.operation,
76
+ correlationId: options?.correlationId,
77
+ tags: options?.tags
78
+ };
79
+ }
80
+ function simplify(rich) {
81
+ return rich.ok ? { ok: true, value: rich.value } : { ok: false, error: rich.error };
82
+ }
83
+
84
+ export { __decorateClass, enrich, fail, fromNullable, fromPromise, fromThrowable, isFail, isOk, isRich, ok, run, simplify, track };
85
+ //# sourceMappingURL=chunk-XLOUAMAH.js.map
86
+ //# sourceMappingURL=chunk-XLOUAMAH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/result/constructors.ts","../src/result/guards.ts","../src/result/run.ts"],"names":[],"mappings":"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","file":"chunk-XLOUAMAH.js","sourcesContent":["import type { Result } from './types.js';\n\n/** Creates a successful Result. */\nexport const ok = <T, E = never>(value: T): Result<T, E> =>\n ({ ok: true, value });\n\n/** Creates a failed Result. */\nexport const fail = <T = never, E = Error>(error: E): Result<T, E> =>\n ({ ok: false, error });\n\n/**\n * Wraps a synchronous throwable function. Catches any thrown value and\n * passes it through `errorTransform` (defaults to identity cast).\n *\n * @example\n * const result = fromThrowable(() => JSON.parse(raw), (e) => new ParseError(e));\n */\nexport function fromThrowable<T, E = Error>(\n fn: () => T,\n errorTransform?: (caught: unknown) => E,\n): Result<T, E> {\n try {\n return ok(fn());\n } catch (caught) {\n return fail(errorTransform ? errorTransform(caught) : (caught as E));\n }\n}\n\n/**\n * Converts a Promise to a `Promise<Result<T, E>>`, catching rejections.\n *\n * @example\n * const result = await fromPromise(fetch(url), (e) => new NetworkError(e));\n */\nexport async function fromPromise<T, E = Error>(\n promise: Promise<T>,\n errorTransform?: (caught: unknown) => E,\n): Promise<Result<T, E>> {\n try {\n return ok(await promise);\n } catch (caught) {\n return fail(errorTransform ? errorTransform(caught) : (caught as E));\n }\n}\n\n/**\n * Converts a nullable value to a Result.\n * Returns `ok(value)` if non-null/undefined, `fail(error)` otherwise.\n *\n * @example\n * const result = fromNullable(user, new NotFoundError('user'));\n */\nexport function fromNullable<T, E>(\n value: T | null | undefined,\n error: E,\n): Result<T, E> {\n return value != null ? ok(value) : fail(error);\n}\n","import type { Result, RichResult } from './types.js';\n\ntype OkResult<T, E> = Extract<Result<T, E>, { ok: true }>;\ntype FailResult<T, E> = Extract<Result<T, E>, { ok: false }>;\n\n/** Narrows a `Result<T, E>` to its success branch. */\nexport function isOk<T, E>(result: Result<T, E>): result is OkResult<T, E> {\n return result.ok === true;\n}\n\n/** Narrows a `Result<T, E>` to its failure branch. */\nexport function isFail<T, E>(result: Result<T, E>): result is FailResult<T, E> {\n return result.ok === false;\n}\n\n/** Returns `true` if the result carries observability metadata (`track()` output). */\nexport function isRich<T, E>(result: Result<T, E>): result is RichResult<T, E> {\n return 'durationMs' in result;\n}\n","import type { Result, RichResult, TrackOptions } from './types.js';\nimport { ok, fail } from './constructors.js';\n\n/**\n * Executes an async (or sync) function and captures any thrown exception,\n * returning a `Result<T, E>` instead of propagating the error.\n *\n * @example\n * const result = await run(() => fetchUser(id));\n * const result = await run(() => fetchUser(id), (e) => new UserError(e));\n */\nexport async function run<T, E = Error>(\n fn: () => T | Promise<T>,\n errorTransform?: (caught: unknown) => E,\n): Promise<Result<T, E>> {\n try {\n return ok(await fn());\n } catch (caught) {\n return fail(errorTransform ? errorTransform(caught) : (caught as E));\n }\n}\n\n/**\n * Like `run()` but also captures timing and metadata, returning a `RichResult<T, E>`.\n *\n * @example\n * const result = await track(() => fetchUser(id), { operation: 'user.fetch', tags: ['db'] });\n */\nexport async function track<T, E = Error>(\n fn: () => T | Promise<T>,\n options?: TrackOptions & { errorTransform?: (caught: unknown) => E },\n): Promise<RichResult<T, E>> {\n const start = performance.now();\n const timestamp = new Date().toISOString();\n const meta = {\n durationMs: 0,\n timestamp,\n operation: options?.operation,\n correlationId: options?.correlationId,\n tags: options?.tags,\n };\n\n try {\n const value = await fn();\n return { ok: true, value, ...meta, durationMs: Math.round(performance.now() - start) };\n } catch (caught) {\n const error = options?.errorTransform ? options.errorTransform(caught) : (caught as E);\n return { ok: false, error, ...meta, durationMs: Math.round(performance.now() - start) };\n }\n}\n\n/**\n * Promotes a plain `Result<T, E>` to a `RichResult<T, E>` with a zero-duration snapshot.\n * Useful when you already have a Result and want to attach metadata.\n */\nexport function enrich<T, E>(result: Result<T, E>, options?: TrackOptions): RichResult<T, E> {\n return {\n ...result,\n durationMs: 0,\n timestamp: new Date().toISOString(),\n operation: options?.operation,\n correlationId: options?.correlationId,\n tags: options?.tags,\n };\n}\n\n/**\n * Strips observability metadata from a `RichResult`, returning a plain `Result<T, E>`.\n */\nexport function simplify<T, E>(rich: RichResult<T, E>): Result<T, E> {\n return rich.ok\n ? { ok: true, value: rich.value }\n : { ok: false, error: rich.error };\n}\n"]}
package/dist/index.cjs CHANGED
@@ -1,43 +1,13 @@
1
1
  'use strict';
2
2
 
3
- // src/result/constructors.ts
4
- var ok = (value) => ({ ok: true, value });
5
- var fail = (error) => ({ ok: false, error });
6
- function fromThrowable(fn, errorTransform) {
7
- try {
8
- return ok(fn());
9
- } catch (caught) {
10
- return fail(errorTransform ? errorTransform(caught) : caught);
11
- }
12
- }
13
- async function fromPromise(promise, errorTransform) {
14
- try {
15
- return ok(await promise);
16
- } catch (caught) {
17
- return fail(errorTransform ? errorTransform(caught) : caught);
18
- }
19
- }
20
- function fromNullable(value, error) {
21
- return value != null ? ok(value) : fail(error);
22
- }
23
-
24
- // src/result/guards.ts
25
- function isOk(result) {
26
- return result.ok === true;
27
- }
28
- function isFail(result) {
29
- return result.ok === false;
30
- }
31
- function isRich(result) {
32
- return "durationMs" in result;
33
- }
3
+ var chunkGCGL2Y6D_cjs = require('./chunk-GCGL2Y6D.cjs');
34
4
 
35
5
  // src/result/operations.ts
36
6
  function map(result, fn) {
37
- return result.ok ? ok(fn(result.value)) : result;
7
+ return result.ok ? chunkGCGL2Y6D_cjs.ok(fn(result.value)) : result;
38
8
  }
39
9
  function mapError(result, fn) {
40
- return result.ok ? result : fail(fn(result.error));
10
+ return result.ok ? result : chunkGCGL2Y6D_cjs.fail(fn(result.error));
41
11
  }
42
12
  function flatMap(result, fn) {
43
13
  return result.ok ? fn(result.value) : result;
@@ -47,7 +17,7 @@ async function flatMapAsync(result, fn) {
47
17
  }
48
18
  async function mapAsync(result, fn) {
49
19
  if (!result.ok) return Promise.resolve(result);
50
- return ok(await fn(result.value));
20
+ return chunkGCGL2Y6D_cjs.ok(await fn(result.value));
51
21
  }
52
22
  function match(result, handlers) {
53
23
  return result.ok ? handlers.ok(result.value) : handlers.fail(result.error);
@@ -89,46 +59,6 @@ function toUndefined(result) {
89
59
  return result.ok ? result.value : void 0;
90
60
  }
91
61
 
92
- // src/result/run.ts
93
- async function run(fn, errorTransform) {
94
- try {
95
- return ok(await fn());
96
- } catch (caught) {
97
- return fail(errorTransform ? errorTransform(caught) : caught);
98
- }
99
- }
100
- async function track(fn, options) {
101
- const start = performance.now();
102
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
103
- const meta = {
104
- durationMs: 0,
105
- timestamp,
106
- operation: options?.operation,
107
- correlationId: options?.correlationId,
108
- tags: options?.tags
109
- };
110
- try {
111
- const value = await fn();
112
- return { ok: true, value, ...meta, durationMs: Math.round(performance.now() - start) };
113
- } catch (caught) {
114
- const error = options?.errorTransform ? options.errorTransform(caught) : caught;
115
- return { ok: false, error, ...meta, durationMs: Math.round(performance.now() - start) };
116
- }
117
- }
118
- function enrich(result, options) {
119
- return {
120
- ...result,
121
- durationMs: 0,
122
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
123
- operation: options?.operation,
124
- correlationId: options?.correlationId,
125
- tags: options?.tags
126
- };
127
- }
128
- function simplify(rich) {
129
- return rich.ok ? { ok: true, value: rich.value } : { ok: false, error: rich.error };
130
- }
131
-
132
62
  // src/result/resilience.ts
133
63
  async function retry(fn, options) {
134
64
  let last;
@@ -150,20 +80,27 @@ async function retryWithBackoff(fn, options) {
150
80
  if (attempt === options.attempts) break;
151
81
  if (options.shouldRetry && !options.shouldRetry(last.error, attempt)) break;
152
82
  options.onRetry?.(last.error, attempt);
153
- const delay = Math.min(
154
- (options.delayMs ?? 100) * Math.pow(2, attempt - 1),
155
- options.maxDelayMs ?? 3e4
156
- );
157
- await sleep(delay);
83
+ await sleep(computeBackoffDelay(attempt, options));
158
84
  }
159
85
  return last;
160
86
  }
161
87
  async function withTimeout(fn, ms, timeoutError) {
162
88
  const timer = new Promise(
163
- (resolve) => setTimeout(() => resolve(fail(timeoutError)), ms)
89
+ (resolve) => setTimeout(() => resolve(chunkGCGL2Y6D_cjs.fail(timeoutError)), ms)
164
90
  );
165
91
  return Promise.race([fn(), timer]);
166
92
  }
93
+ function computeBackoffDelay(attempt, options) {
94
+ const base = (options.delayMs ?? 100) * Math.pow(2, attempt - 1);
95
+ const capped = Math.min(base, options.maxDelayMs ?? 3e4);
96
+ const { jitter } = options;
97
+ if (!jitter) return capped;
98
+ if (jitter === true) {
99
+ return Math.random() * capped;
100
+ }
101
+ const noise = (Math.random() * 2 - 1) * capped * jitter;
102
+ return Math.max(0, Math.min(capped + noise, options.maxDelayMs ?? 3e4));
103
+ }
167
104
  var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
168
105
 
169
106
  // src/result/combinators.ts
@@ -173,7 +110,7 @@ function all(results) {
173
110
  if (!r.ok) return r;
174
111
  values.push(r.value);
175
112
  }
176
- return ok(values);
113
+ return chunkGCGL2Y6D_cjs.ok(values);
177
114
  }
178
115
  async function any(operations) {
179
116
  let last;
@@ -210,13 +147,13 @@ function traverse(items, fn) {
210
147
  function combine2(r1, r2) {
211
148
  if (!r1.ok) return r1;
212
149
  if (!r2.ok) return r2;
213
- return ok([r1.value, r2.value]);
150
+ return chunkGCGL2Y6D_cjs.ok([r1.value, r2.value]);
214
151
  }
215
152
  function combine3(r1, r2, r3) {
216
153
  if (!r1.ok) return r1;
217
154
  if (!r2.ok) return r2;
218
155
  if (!r3.ok) return r3;
219
- return ok([r1.value, r2.value, r3.value]);
156
+ return chunkGCGL2Y6D_cjs.ok([r1.value, r2.value, r3.value]);
220
157
  }
221
158
 
222
159
  // src/result/flow.ts
@@ -231,17 +168,17 @@ var Flow = class _Flow {
231
168
  }
232
169
  /** Start an empty pipeline (value is `undefined`). */
233
170
  static start() {
234
- return new _Flow(ok(void 0));
171
+ return new _Flow(chunkGCGL2Y6D_cjs.ok(void 0));
235
172
  }
236
173
  /** Maps the success value. Skipped on failure. */
237
174
  map(fn) {
238
175
  if (!this._result.ok) return new _Flow(this._result);
239
- return new _Flow(ok(fn(this._result.value)));
176
+ return new _Flow(chunkGCGL2Y6D_cjs.ok(fn(this._result.value)));
240
177
  }
241
178
  /** Maps the error value. Skipped on success. */
242
179
  mapError(fn) {
243
180
  if (this._result.ok) return new _Flow(this._result);
244
- return new _Flow(fail(fn(this._result.error)));
181
+ return new _Flow(chunkGCGL2Y6D_cjs.fail(fn(this._result.error)));
245
182
  }
246
183
  /** Chains a Result-returning function. Skipped on failure. */
247
184
  flatMap(fn) {
@@ -251,7 +188,7 @@ var Flow = class _Flow {
251
188
  /** Filters the success value. Becomes `fail(error)` if predicate is false. */
252
189
  filter(pred, error) {
253
190
  if (!this._result.ok) return this;
254
- return pred(this._result.value) ? this : new _Flow(fail(error));
191
+ return pred(this._result.value) ? this : new _Flow(chunkGCGL2Y6D_cjs.fail(error));
255
192
  }
256
193
  /** Runs a side effect on success; returns `this` unchanged. */
257
194
  tap(fn) {
@@ -269,7 +206,7 @@ var Flow = class _Flow {
269
206
  */
270
207
  recover(fn) {
271
208
  if (this._result.ok) return new _Flow(this._result);
272
- return new _Flow(ok(fn(this._result.error)));
209
+ return new _Flow(chunkGCGL2Y6D_cjs.ok(fn(this._result.error)));
273
210
  }
274
211
  /** Exhaustive pattern match — always produces a value. */
275
212
  match(handlers) {
@@ -284,7 +221,7 @@ var Flow = class _Flow {
284
221
  * Throws if the result has no observability metadata.
285
222
  */
286
223
  getRichResult() {
287
- if (!isRich(this._result)) throw new Error("Result is not a RichResult");
224
+ if (!chunkGCGL2Y6D_cjs.isRich(this._result)) throw new Error("Result is not a RichResult");
288
225
  return this._result;
289
226
  }
290
227
  isOk() {
@@ -295,41 +232,77 @@ var Flow = class _Flow {
295
232
  }
296
233
  };
297
234
 
235
+ Object.defineProperty(exports, "enrich", {
236
+ enumerable: true,
237
+ get: function () { return chunkGCGL2Y6D_cjs.enrich; }
238
+ });
239
+ Object.defineProperty(exports, "fail", {
240
+ enumerable: true,
241
+ get: function () { return chunkGCGL2Y6D_cjs.fail; }
242
+ });
243
+ Object.defineProperty(exports, "fromNullable", {
244
+ enumerable: true,
245
+ get: function () { return chunkGCGL2Y6D_cjs.fromNullable; }
246
+ });
247
+ Object.defineProperty(exports, "fromPromise", {
248
+ enumerable: true,
249
+ get: function () { return chunkGCGL2Y6D_cjs.fromPromise; }
250
+ });
251
+ Object.defineProperty(exports, "fromThrowable", {
252
+ enumerable: true,
253
+ get: function () { return chunkGCGL2Y6D_cjs.fromThrowable; }
254
+ });
255
+ Object.defineProperty(exports, "isFail", {
256
+ enumerable: true,
257
+ get: function () { return chunkGCGL2Y6D_cjs.isFail; }
258
+ });
259
+ Object.defineProperty(exports, "isOk", {
260
+ enumerable: true,
261
+ get: function () { return chunkGCGL2Y6D_cjs.isOk; }
262
+ });
263
+ Object.defineProperty(exports, "isRich", {
264
+ enumerable: true,
265
+ get: function () { return chunkGCGL2Y6D_cjs.isRich; }
266
+ });
267
+ Object.defineProperty(exports, "ok", {
268
+ enumerable: true,
269
+ get: function () { return chunkGCGL2Y6D_cjs.ok; }
270
+ });
271
+ Object.defineProperty(exports, "run", {
272
+ enumerable: true,
273
+ get: function () { return chunkGCGL2Y6D_cjs.run; }
274
+ });
275
+ Object.defineProperty(exports, "simplify", {
276
+ enumerable: true,
277
+ get: function () { return chunkGCGL2Y6D_cjs.simplify; }
278
+ });
279
+ Object.defineProperty(exports, "track", {
280
+ enumerable: true,
281
+ get: function () { return chunkGCGL2Y6D_cjs.track; }
282
+ });
298
283
  exports.Flow = Flow;
299
284
  exports.all = all;
300
285
  exports.any = any;
301
286
  exports.collect = collect;
302
287
  exports.combine2 = combine2;
303
288
  exports.combine3 = combine3;
304
- exports.enrich = enrich;
305
289
  exports.expect = expect;
306
- exports.fail = fail;
307
290
  exports.flatMap = flatMap;
308
291
  exports.flatMapAsync = flatMapAsync;
309
292
  exports.fold = fold;
310
- exports.fromNullable = fromNullable;
311
- exports.fromPromise = fromPromise;
312
- exports.fromThrowable = fromThrowable;
313
- exports.isFail = isFail;
314
- exports.isOk = isOk;
315
- exports.isRich = isRich;
316
293
  exports.map = map;
317
294
  exports.mapAsync = mapAsync;
318
295
  exports.mapError = mapError;
319
296
  exports.match = match;
320
- exports.ok = ok;
321
297
  exports.parallel = parallel;
322
298
  exports.partition = partition;
323
299
  exports.retry = retry;
324
300
  exports.retryWithBackoff = retryWithBackoff;
325
- exports.run = run;
326
- exports.simplify = simplify;
327
301
  exports.tap = tap;
328
302
  exports.tapError = tapError;
329
303
  exports.toNullable = toNullable;
330
304
  exports.toPromise = toPromise;
331
305
  exports.toUndefined = toUndefined;
332
- exports.track = track;
333
306
  exports.traverse = traverse;
334
307
  exports.unwrap = unwrap;
335
308
  exports.unwrapError = unwrapError;