awaitly 2.0.0 → 3.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 (88) hide show
  1. package/dist/di-Biw_plBn.d.cts +15 -0
  2. package/dist/di-DxyH2N3i.d.ts +15 -0
  3. package/dist/durable.cjs +4670 -0
  4. package/dist/durable.cjs.map +1 -0
  5. package/dist/durable.d.cts +9 -0
  6. package/dist/durable.d.ts +9 -0
  7. package/dist/durable.js +4610 -0
  8. package/dist/durable.js.map +1 -0
  9. package/dist/{di-BbFFfO8y.d.ts → duration-BjVn3QpB.d.cts} +1 -15
  10. package/dist/{di-BDlT7InM.d.cts → duration-BjVn3QpB.d.ts} +1 -15
  11. package/dist/engine.cjs +4501 -0
  12. package/dist/engine.cjs.map +1 -0
  13. package/dist/engine.d.cts +113 -0
  14. package/dist/engine.d.ts +113 -0
  15. package/dist/engine.js +4474 -0
  16. package/dist/engine.js.map +1 -0
  17. package/dist/{errors-DtXvrCiO.d.cts → errors-sDSeaZBO.d.cts} +1 -1
  18. package/dist/{errors-DtXvrCiO.d.ts → errors-sDSeaZBO.d.ts} +1 -1
  19. package/dist/guards-CwQZro1F.d.ts +72 -0
  20. package/dist/guards-DhhOJZda.d.cts +72 -0
  21. package/dist/hitl-BnnnLzh2.d.cts +468 -0
  22. package/dist/hitl-pYfkQMv_.d.ts +468 -0
  23. package/dist/hitl.cjs +646 -0
  24. package/dist/hitl.cjs.map +1 -0
  25. package/dist/hitl.d.cts +440 -0
  26. package/dist/hitl.d.ts +440 -0
  27. package/dist/hitl.js +605 -0
  28. package/dist/hitl.js.map +1 -0
  29. package/dist/index-Bew12SZ8.d.ts +417 -0
  30. package/dist/index-Bwt-iz50.d.cts +417 -0
  31. package/dist/{types-B8NfNRGX.d.ts → index-Cv4K_3sZ.d.ts} +2 -1162
  32. package/dist/{types-BZ2f4MRR.d.cts → index-ICmfQi08.d.cts} +2 -1162
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +11 -1527
  35. package/dist/index.d.ts +11 -1527
  36. package/dist/persistence.cjs +552 -0
  37. package/dist/persistence.cjs.map +1 -0
  38. package/dist/persistence.d.cts +254 -0
  39. package/dist/persistence.d.ts +254 -0
  40. package/dist/persistence.js +499 -0
  41. package/dist/persistence.js.map +1 -0
  42. package/dist/reliability.cjs +1651 -0
  43. package/dist/reliability.cjs.map +1 -0
  44. package/dist/reliability.d.cts +1442 -0
  45. package/dist/reliability.d.ts +1442 -0
  46. package/dist/reliability.js +1589 -0
  47. package/dist/reliability.js.map +1 -0
  48. package/dist/result.d.cts +1 -1
  49. package/dist/result.d.ts +1 -1
  50. package/dist/run.cjs +2283 -0
  51. package/dist/run.cjs.map +1 -0
  52. package/dist/run.d.cts +90 -0
  53. package/dist/run.d.ts +90 -0
  54. package/dist/run.js +2247 -0
  55. package/dist/run.js.map +1 -0
  56. package/dist/saga.cjs +3699 -0
  57. package/dist/saga.cjs.map +1 -0
  58. package/dist/saga.d.cts +162 -0
  59. package/dist/saga.d.ts +162 -0
  60. package/dist/saga.js +3670 -0
  61. package/dist/saga.js.map +1 -0
  62. package/dist/store-contract-BI98VYmX.d.ts +66 -0
  63. package/dist/store-contract-C2HyR_o6.d.cts +66 -0
  64. package/dist/streaming.cjs +895 -0
  65. package/dist/streaming.cjs.map +1 -0
  66. package/dist/streaming.d.cts +594 -0
  67. package/dist/streaming.d.ts +594 -0
  68. package/dist/streaming.js +832 -0
  69. package/dist/streaming.js.map +1 -0
  70. package/dist/testing.d.cts +4 -2
  71. package/dist/testing.d.ts +4 -2
  72. package/dist/types-BDTxgKKc.d.ts +845 -0
  73. package/dist/types-C9Y71dua.d.cts +845 -0
  74. package/dist/types-d8q8iQlk.d.cts +323 -0
  75. package/dist/types-sObbY4mX.d.ts +323 -0
  76. package/dist/webhook.cjs +461 -0
  77. package/dist/webhook.cjs.map +1 -0
  78. package/dist/webhook.d.cts +497 -0
  79. package/dist/webhook.d.ts +497 -0
  80. package/dist/webhook.js +422 -0
  81. package/dist/webhook.js.map +1 -0
  82. package/dist/workflow.cjs +2 -2614
  83. package/dist/workflow.cjs.map +1 -1
  84. package/dist/workflow.d.cts +12 -3023
  85. package/dist/workflow.d.ts +12 -3023
  86. package/dist/workflow.js +2 -2535
  87. package/dist/workflow.js.map +1 -1
  88. package/package.json +46 -1
package/dist/index.d.ts CHANGED
@@ -1,96 +1,15 @@
1
- import { AsyncResult, ErrorOf } from './result.js';
2
- export { AWAITLY_CANCELLED, AWAITLY_TIMEOUT, AWAITLY_UNEXPECTED, CauseOf, DESERIALIZATION_ERROR, DeserializationError, EmptyInputError, Err, Errors, ErrorsOf, ExtractCause, ExtractError, ExtractValue, MatchErrorHandlers, MaybeAsyncResult, Ok, PROMISE_REJECTED, PromiseRejectedError, PromiseRejectionCause, Result, SerializedResult, SettledError, UnwrapError, all, allAsync, allSettled, allSettledAsync, andThen, any, anyAsync, bimap, deserialize, err, flatten, from, fromNullable, fromPromise, hydrate, isErr, isOk, isPromiseRejectedError, isSerializedResult, isUnexpectedError, map, mapError, mapErrorTry, mapTry, match, matchError, matchErrorPartial, ok, orElse, orElseAsync, partition, recover, recoverAsync, runOrNull, runOrThrow, runOrThrowAsync, runOrUndefined, serialize, tags, tap, tapError, tryAsync, unwrap, unwrapOr, unwrapOrElse, zip, zipAsync } from './result.js';
3
- import { D as Duration } from './di-BbFFfO8y.js';
4
- export { a as add, c as clamp, d as days, b as divide, e as equals, f as format, g as greaterThan, h as greaterThanOrEqual, i as hours, j as infinity, k as isDuration, l as isFinite, m as isInfinite, n as isZero, o as lessThan, p as lessThanOrEqual, q as max, r as millis, s as min, t as minutes, u as multiply, v as parse, w as seconds, x as subtract, y as toDays, z as toHours, A as toMillis, B as toMinutes, C as toSeconds, E as withDeps, F as zero } from './di-BbFFfO8y.js';
5
- import { U as UnexpectedError, T as TimeoutError } from './errors-DtXvrCiO.js';
6
- export { A as ALL_SLUGS, a as AWAITLY_SLUGS, b as AWAITLY_SYSTEM_ERROR_CLASSES, c as AwaitlyError, d as AwaitlySlug, e as AwaitlySlugCategory, f as AwaitlySystemError, C as CircuitBreakerOpenError, g as CompensationError, E as ErrorByTag, N as NetworkError, h as NotFoundError, P as PropsOf, R as RateLimitError, i as RetryExhaustedError, j as TagOf, k as TaggedError, l as TaggedErrorBase, m as TaggedErrorConstructor, n as TaggedErrorCreateOptions, o as TaggedErrorOptions, p as UnauthorizedError, V as ValidationError, q as isAwaitlyError, r as isAwaitlySlug, s as isCircuitBreakerOpenError, t as isCompensationError, u as isNetworkError, v as isNotFoundError, w as isRateLimitError, x as isRetryExhaustedError, y as isTimeoutError, z as isUnauthorizedError, B as isValidationError, D as makeError, F as slugCategory, G as slugDocsUrl } from './errors-DtXvrCiO.js';
7
- import { D as DepValueOfReturn, R as Result, A as AsyncResult$1, S as StepOptions, a as RetryOptions, T as TimeoutOptions, W as WorkflowEvent } from './types-B8NfNRGX.js';
8
- export { B as BackoffStrategy, b as BoundSteps, E as EARLY_EXIT_SYMBOL, c as EarlyExit, d as RunOptions, e as RunOptionsWithCatch, f as RunOptionsWithoutCatch, g as RunStep, h as STEP_TIMEOUT_MARKER, i as ScopeType, j as StepFailureMeta, k as StepTimeoutError, l as StepTimeoutMarkerMeta, m as createEarlyExit, n as getStepTimeoutMeta, o as isEarlyExit, p as isStepTimeoutError, r as run } from './types-B8NfNRGX.js';
1
+ export { AWAITLY_CANCELLED, AWAITLY_TIMEOUT, AWAITLY_UNEXPECTED, AsyncResult, CauseOf, DESERIALIZATION_ERROR, DeserializationError, EmptyInputError, Err, ErrorOf, Errors, ErrorsOf, ExtractCause, ExtractError, ExtractValue, MatchErrorHandlers, MaybeAsyncResult, Ok, PROMISE_REJECTED, PromiseRejectedError, PromiseRejectionCause, Result, SerializedResult, SettledError, UnwrapError, all, allAsync, allSettled, allSettledAsync, andThen, any, anyAsync, bimap, deserialize, err, flatten, from, fromNullable, fromPromise, hydrate, isErr, isOk, isPromiseRejectedError, isSerializedResult, isUnexpectedError, map, mapError, mapErrorTry, mapTry, match, matchError, matchErrorPartial, ok, orElse, orElseAsync, partition, recover, recoverAsync, runOrNull, runOrThrow, runOrThrowAsync, runOrUndefined, serialize, tags, tap, tapError, tryAsync, unwrap, unwrapOr, unwrapOrElse, zip, zipAsync } from './result.js';
2
+ export { w as withDeps } from './di-DxyH2N3i.js';
3
+ export { A as ALL_SLUGS, a as AWAITLY_SLUGS, b as AWAITLY_SYSTEM_ERROR_CLASSES, c as AwaitlyError, d as AwaitlySlug, e as AwaitlySlugCategory, f as AwaitlySystemError, C as CircuitBreakerOpenError, g as CompensationError, E as ErrorByTag, N as NetworkError, h as NotFoundError, P as PropsOf, R as RateLimitError, i as RetryExhaustedError, T as TagOf, j as TaggedError, k as TaggedErrorBase, l as TaggedErrorConstructor, m as TaggedErrorCreateOptions, n as TaggedErrorOptions, o as TimeoutError, p as UnauthorizedError, U as UnexpectedError, V as ValidationError, q as isAwaitlyError, r as isAwaitlySlug, s as isCircuitBreakerOpenError, t as isCompensationError, u as isNetworkError, v as isNotFoundError, w as isRateLimitError, x as isRetryExhaustedError, y as isTimeoutError, z as isUnauthorizedError, B as isValidationError, D as makeError, F as slugCategory, G as slugDocsUrl } from './errors-sDSeaZBO.js';
4
+ import { W as WorkflowEvent } from './index-Cv4K_3sZ.js';
5
+ export { B as BackoffStrategy, b as BoundSteps, E as EARLY_EXIT_SYMBOL, c as EarlyExit, d as RetryOptions, e as RunOptions, f as RunOptionsWithCatch, g as RunOptionsWithoutCatch, a as RunStep, S as STEP_TIMEOUT_MARKER, h as ScopeType, i as StepFailureMeta, j as StepOptions, k as StepTimeoutError, l as StepTimeoutMarkerMeta, T as TimeoutOptions, m as createEarlyExit, n as getStepTimeoutMeta, o as isEarlyExit, p as isStepTimeoutError, r as run } from './index-Cv4K_3sZ.js';
6
+ export { PolicyDelay, PolicyFn, RetryPolicyOptions, fallback, retry, timeout } from './run.js';
7
+ export { D as Duration, D as DurationType, a as add, c as clamp, d as days, b as divide, e as equals, f as format, g as greaterThan, h as greaterThanOrEqual, i as hours, j as infinity, k as isDuration, l as isFinite, m as isInfinite, n as isZero, o as lessThan, p as lessThanOrEqual, q as max, r as millis, s as min, t as minutes, u as multiply, v as parse, w as seconds, x as subtract, y as toDays, z as toHours, A as toMillis, B as toMinutes, C as toSeconds, E as zero } from './duration-BjVn3QpB.js';
8
+ export { Cache, CacheConfig, CacheEntry, CacheOptions, CacheStats, CachedFunctionOptions, CircuitBreaker, CircuitBreakerConfig, CircuitBreakerStats, CircuitOpenError, CircuitState, CombinedLimiterConfig, ConcurrencyLimiter, ConcurrencyLimiterConfig, ConcurrencyLimiterStats, CostBasedRateLimiter, CostBasedRateLimiterConfig, CostBasedRateLimiterStats, DurationInput, FixedWindowLimiter, FixedWindowLimiterConfig, FixedWindowLimiterStats, MemoizedFunction, NamedPolicy, OnceFunction, Policy, PolicyFactory, PolicyRegistry, QueueFullError, RateLimitExceededError, RateLimiter, RateLimiterConfig, RateLimiterStats, SingleflightOptions, StepOptionsBuilder, WithPoliciesOptions, cached, cachedFunction, cachedWithTTL, circuitBreakerPresets, conditionalPolicy, createCache, createCircuitBreaker, createCombinedLimiter, createConcurrencyLimiter, createCostBasedRateLimiter, createFixedWindowLimiter, createPolicyApplier, createPolicyBundle, createPolicyRegistry, createRateLimiter, createSingleflightGroup, envPolicy, isCircuitOpenError, isQueueFullError, isRateLimitExceededError, mergePolicies, once, rateLimiterPresets, retryPolicies, retryPolicy, servicePolicies, singleflight, stepOptions, timeoutPolicies, timeoutPolicy, withPolicies, withPolicy } from './reliability.js';
9
+ import './types-BDTxgKKc.js';
10
+ import './types-sObbY4mX.js';
9
11
  import '@standard-schema/spec';
10
12
 
11
- /**
12
- * Per-dependency policies: retry, timeout, fallback.
13
- *
14
- * Policies are value-level function wrappers declared where dependencies
15
- * are declared — in the deps object — so call sites stay pristine and the
16
- * policy is statically visible in the deps literal (the analyzer reads it
17
- * as fact, not inference):
18
- *
19
- * ```typescript
20
- * const result = await run(
21
- * {
22
- * getUser,
23
- * charge: retry(timeout(charge, 5000), { attempts: 3 }),
24
- * sendEmail: fallback(sendEmail, () => ({ queued: true })),
25
- * },
26
- * async (s) => {
27
- * const user = await s.getUser(userId); // call sites unchanged
28
- * const payment = await s.charge(user.id);
29
- * return s.sendEmail(user.id);
30
- * }
31
- * );
32
- * ```
33
- *
34
- * Every policy returns a Result-returning function with exact error-union
35
- * math:
36
- * - `retry(fn, opts)` — same errors as `fn` (the last failure propagates)
37
- * - `timeout(fn, ms)` — errors of `fn` plus `TimeoutError`
38
- * - `fallback(fn, fb)` — errors of `fn` are consumed; only `fb`'s errors remain
39
- *
40
- * Plain (non-Result) functions are valid inputs: their values are
41
- * normalized to `ok()`, and their throws keep throwing (so they surface as
42
- * `UnexpectedError` at the run/workflow layer, same as unwrapped deps).
43
- */
44
-
45
- type AnyFunction = (...args: never[]) => unknown;
46
- /** Milliseconds or a Duration value. */
47
- type PolicyDelay = number | Duration;
48
- /** The unwrapped success value a policy resolves to for a given function. */
49
- type PolicyValue<F extends AnyFunction> = DepValueOfReturn<ReturnType<F>>;
50
- /** A function wrapped by a policy: same arguments, Result-returning. */
51
- type PolicyFn<F extends AnyFunction, E> = (...args: Parameters<F>) => AsyncResult<PolicyValue<F>, E>;
52
- interface RetryPolicyOptions {
53
- /** Total attempts including the first call (minimum 1). */
54
- attempts: number;
55
- /** Base delay between attempts. Default: no delay. */
56
- delay?: PolicyDelay;
57
- /** How the delay grows per attempt. Default: "fixed". */
58
- backoff?: "fixed" | "linear" | "exponential";
59
- /** Upper bound for the computed delay. */
60
- maxDelay?: PolicyDelay;
61
- /**
62
- * Decide whether a failure is retryable. Receives the Result error, or
63
- * the thrown value for plain functions. Default: retry everything.
64
- */
65
- retryIf?: (failure: unknown) => boolean;
66
- /** Observer invoked before each re-attempt. */
67
- onRetry?: (info: {
68
- attempt: number;
69
- failure: unknown;
70
- }) => void;
71
- }
72
- /**
73
- * Retry a dependency. The error union is unchanged: if all attempts fail,
74
- * the last failure propagates exactly as it would have without the policy
75
- * (typed err for Result functions, throw for plain functions).
76
- */
77
- declare function retry<F extends AnyFunction>(fn: F, options: RetryPolicyOptions): PolicyFn<F, ErrorOf<F>>;
78
- /**
79
- * Bound a dependency's execution time. On timeout, resolves to
80
- * `err(TimeoutError)` — adding `TimeoutError` to the error union. The
81
- * underlying operation is not cancelled (no AbortSignal is threaded);
82
- * its eventual result is discarded.
83
- */
84
- declare function timeout<F extends AnyFunction>(fn: F, after: PolicyDelay): PolicyFn<F, ErrorOf<F> | TimeoutError>;
85
- /**
86
- * Recover from a dependency's failure. The handler receives the failure
87
- * (the typed Result error, or `UnexpectedError` wrapping a throw) plus the
88
- * original arguments, and its result becomes the outcome. The base
89
- * function's errors are consumed; only the handler's errors remain in the
90
- * union — `fallback(fn, () => defaultValue)` has no typed errors at all.
91
- */
92
- declare function fallback<F extends AnyFunction, FB extends (failure: ErrorOf<F> | UnexpectedError, ...args: Parameters<F>) => unknown>(fn: F, onFailure: FB): (...args: Parameters<F>) => AsyncResult<PolicyValue<F> | DepValueOfReturn<ReturnType<FB>>, ErrorOf<FB>>;
93
-
94
13
  /**
95
14
  * awaitly/match
96
15
  *
@@ -299,1441 +218,6 @@ declare const Match: {
299
218
  readonly isOneOf: typeof isOneOf;
300
219
  };
301
220
 
302
- /**
303
- * Circuit Breaker for Steps
304
- *
305
- * Prevents cascading failures by tracking step failure rates and
306
- * short-circuiting calls when a threshold is exceeded.
307
- *
308
- * Uses the circuit breaker pattern with three states:
309
- * - CLOSED: Normal operation (steps executing)
310
- * - OPEN: Fast-fail mode (steps blocked)
311
- * - HALF_OPEN: Testing if service recovered
312
- *
313
- * @example
314
- * ```typescript
315
- * import { createCircuitBreaker } from 'awaitly';
316
- *
317
- * const breaker = createCircuitBreaker({
318
- * failureThreshold: 5,
319
- * resetTimeout: 30000,
320
- * halfOpenMax: 3,
321
- * });
322
- *
323
- * const result = await workflow(async ({ step }) => {
324
- * const data = await breaker.execute(
325
- * () => step(() => callExternalApi()),
326
- * { name: 'external-api' }
327
- * );
328
- * return data;
329
- * });
330
- * ```
331
- */
332
-
333
- /**
334
- * Circuit breaker state.
335
- */
336
- type CircuitState = "CLOSED" | "OPEN" | "HALF_OPEN";
337
- /**
338
- * Configuration for circuit breaker behavior.
339
- */
340
- interface CircuitBreakerConfig {
341
- /**
342
- * Number of failures within the window before opening the circuit.
343
- * @default 5
344
- */
345
- failureThreshold: number;
346
- /**
347
- * Time in ms to wait before transitioning from OPEN to HALF_OPEN.
348
- * @default 30000 (30 seconds)
349
- */
350
- resetTimeout: number;
351
- /**
352
- * Time window in ms for counting failures.
353
- * Failures older than this are discarded.
354
- * @default 60000 (1 minute)
355
- */
356
- windowSize: number;
357
- /**
358
- * Maximum number of test requests allowed in HALF_OPEN state.
359
- * If all succeed, circuit closes. If any fail, circuit reopens.
360
- * @default 3
361
- */
362
- halfOpenMax: number;
363
- /**
364
- * Optional callback when circuit state changes.
365
- */
366
- onStateChange?: (from: CircuitState, to: CircuitState, name?: string) => void;
367
- }
368
- /**
369
- * Error thrown when the circuit is open and calls are blocked.
370
- */
371
- declare class CircuitOpenError extends Error {
372
- readonly type: "CIRCUIT_OPEN";
373
- readonly circuitName: string;
374
- readonly state: CircuitState;
375
- readonly retryAfterMs: number;
376
- constructor(options: {
377
- circuitName: string;
378
- state: CircuitState;
379
- retryAfterMs: number;
380
- message?: string;
381
- });
382
- }
383
- /**
384
- * Type guard for CircuitOpenError.
385
- */
386
- declare function isCircuitOpenError(error: unknown): error is CircuitOpenError;
387
- /**
388
- * Circuit breaker statistics.
389
- */
390
- interface CircuitBreakerStats {
391
- state: CircuitState;
392
- failureCount: number;
393
- successCount: number;
394
- lastFailureTime: number | null;
395
- lastSuccessTime: number | null;
396
- halfOpenSuccesses: number;
397
- }
398
- /**
399
- * Circuit breaker instance for protecting external calls.
400
- */
401
- interface CircuitBreaker {
402
- /**
403
- * Execute an operation with circuit breaker protection.
404
- * Throws CircuitOpenError if the circuit is open.
405
- *
406
- * @param operation - The operation to execute
407
- * @param options - Optional name for logging/metrics
408
- * @returns The operation result
409
- * @throws CircuitOpenError if circuit is open
410
- */
411
- execute<T>(operation: () => T | Promise<T>, options?: {
412
- name?: string;
413
- }): Promise<T>;
414
- /**
415
- * Execute a Result-returning operation with circuit breaker protection.
416
- * Returns a CircuitOpenError result instead of throwing.
417
- *
418
- * @param operation - The operation returning a Result
419
- * @param options - Optional name for logging/metrics
420
- * @returns Result with the value or CircuitOpenError
421
- */
422
- executeResult<T, E>(operation: () => Result<T, E> | AsyncResult$1<T, E>, options?: {
423
- name?: string;
424
- }): AsyncResult$1<T, E | CircuitOpenError>;
425
- /**
426
- * Get current circuit state.
427
- */
428
- getState(): CircuitState;
429
- /**
430
- * Get circuit breaker statistics.
431
- */
432
- getStats(): CircuitBreakerStats;
433
- /**
434
- * Manually reset the circuit breaker to CLOSED state.
435
- */
436
- reset(): void;
437
- /**
438
- * Manually open the circuit (for testing or manual intervention).
439
- */
440
- forceOpen(): void;
441
- /**
442
- * Record a manual success (useful for health checks).
443
- */
444
- recordSuccess(): void;
445
- /**
446
- * Record a manual failure (useful for health checks).
447
- */
448
- recordFailure(error?: unknown): void;
449
- }
450
- /**
451
- * Create a circuit breaker instance.
452
- *
453
- * @param name - Name for this circuit breaker (used in errors and logging)
454
- * @param config - Configuration options
455
- * @returns A CircuitBreaker instance
456
- *
457
- * @example
458
- * ```typescript
459
- * const apiBreaker = createCircuitBreaker('external-api', {
460
- * failureThreshold: 5,
461
- * resetTimeout: 30000,
462
- * });
463
- *
464
- * // In workflow
465
- * const data = await apiBreaker.execute(() =>
466
- * step(() => fetchFromApi(id))
467
- * );
468
- * ```
469
- */
470
- declare function createCircuitBreaker(name: string, config?: Partial<CircuitBreakerConfig>): CircuitBreaker;
471
- /**
472
- * Preset configurations for common use cases.
473
- */
474
- declare const circuitBreakerPresets: {
475
- /**
476
- * Aggressive circuit breaker for critical paths.
477
- * Opens quickly (3 failures) and recovers slowly (60s).
478
- */
479
- readonly critical: {
480
- failureThreshold: number;
481
- resetTimeout: number;
482
- windowSize: number;
483
- halfOpenMax: number;
484
- };
485
- /**
486
- * Standard circuit breaker for typical API calls.
487
- * Balanced between stability and availability.
488
- */
489
- readonly standard: {
490
- failureThreshold: number;
491
- resetTimeout: number;
492
- windowSize: number;
493
- halfOpenMax: number;
494
- };
495
- /**
496
- * Lenient circuit breaker for non-critical operations.
497
- * Opens slowly (10 failures) and recovers quickly (15s).
498
- */
499
- readonly lenient: {
500
- failureThreshold: number;
501
- resetTimeout: number;
502
- windowSize: number;
503
- halfOpenMax: number;
504
- };
505
- };
506
-
507
- /**
508
- * Rate Limiting / Concurrency Control
509
- *
510
- * Control throughput for steps that hit rate-limited APIs or shared resources.
511
- *
512
- * @example
513
- * ```typescript
514
- * import { createRateLimiter, createConcurrencyLimiter } from 'awaitly';
515
- *
516
- * // Rate limiting (requests per second)
517
- * const rateLimiter = createRateLimiter({ maxPerSecond: 10 });
518
- *
519
- * // Concurrency limiting (max concurrent)
520
- * const concurrencyLimiter = createConcurrencyLimiter({ maxConcurrent: 5 });
521
- *
522
- * const result = await workflow(async ({ step }) => {
523
- * // Wrap operations with rate limiting
524
- * const data = await rateLimiter.execute(() =>
525
- * step(() => callRateLimitedApi())
526
- * );
527
- *
528
- * // Wrap batch operations with concurrency control
529
- * const results = await concurrencyLimiter.executeAll(
530
- * ids.map(id => () => step(() => fetchItem(id)))
531
- * );
532
- *
533
- * return { data, results };
534
- * });
535
- * ```
536
- */
537
-
538
- /**
539
- * Configuration for rate limiter.
540
- */
541
- interface RateLimiterConfig {
542
- /**
543
- * Maximum operations per second.
544
- */
545
- maxPerSecond: number;
546
- /**
547
- * Burst capacity - allows brief spikes above the rate.
548
- * @default maxPerSecond * 2
549
- */
550
- burstCapacity?: number;
551
- /**
552
- * Strategy when rate limit is exceeded.
553
- * - 'wait': Wait until a slot is available (default)
554
- * - 'reject': Reject immediately with error
555
- * @default 'wait'
556
- */
557
- strategy?: "wait" | "reject";
558
- }
559
- /**
560
- * Configuration for concurrency limiter.
561
- */
562
- interface ConcurrencyLimiterConfig {
563
- /**
564
- * Maximum concurrent operations.
565
- */
566
- maxConcurrent: number;
567
- /**
568
- * Strategy when limit is reached.
569
- * - 'queue': Queue and wait (default)
570
- * - 'reject': Reject immediately
571
- * @default 'queue'
572
- */
573
- strategy?: "queue" | "reject";
574
- /**
575
- * Maximum queue size (only for 'queue' strategy).
576
- * @default Infinity
577
- */
578
- maxQueueSize?: number;
579
- }
580
- /**
581
- * Error when rate/concurrency limit is exceeded and strategy is 'reject'.
582
- */
583
- interface RateLimitExceededError {
584
- type: "RATE_LIMIT_EXCEEDED";
585
- limiterName: string;
586
- retryAfterMs?: number;
587
- }
588
- /**
589
- * Error when concurrency limit queue is full.
590
- */
591
- interface QueueFullError {
592
- type: "QUEUE_FULL";
593
- limiterName: string;
594
- queueSize: number;
595
- maxQueueSize: number;
596
- }
597
- /**
598
- * Type guard for RateLimitExceededError.
599
- */
600
- declare function isRateLimitExceededError(error: unknown): error is RateLimitExceededError;
601
- /**
602
- * Type guard for QueueFullError.
603
- */
604
- declare function isQueueFullError(error: unknown): error is QueueFullError;
605
- /**
606
- * Statistics for rate limiter.
607
- */
608
- interface RateLimiterStats {
609
- availableTokens: number;
610
- maxTokens: number;
611
- tokensPerSecond: number;
612
- waitingCount: number;
613
- }
614
- /**
615
- * Statistics for concurrency limiter.
616
- */
617
- interface ConcurrencyLimiterStats {
618
- activeCount: number;
619
- maxConcurrent: number;
620
- queueSize: number;
621
- maxQueueSize: number;
622
- }
623
- /**
624
- * Rate limiter interface.
625
- */
626
- interface RateLimiter {
627
- /**
628
- * Execute an operation with rate limiting.
629
- * @param operation - The operation to execute
630
- * @returns The operation result
631
- */
632
- execute<T>(operation: () => T | Promise<T>): Promise<T>;
633
- /**
634
- * Execute a Result-returning operation with rate limiting.
635
- */
636
- executeResult<T, E>(operation: () => Result<T, E> | AsyncResult$1<T, E>): AsyncResult$1<T, E | RateLimitExceededError>;
637
- /**
638
- * Get current statistics.
639
- */
640
- getStats(): RateLimiterStats;
641
- /**
642
- * Reset the rate limiter.
643
- */
644
- reset(): void;
645
- }
646
- /**
647
- * Create a token bucket rate limiter.
648
- *
649
- * @param name - Name for the limiter (used in errors)
650
- * @param config - Rate limiter configuration
651
- * @returns A RateLimiter instance
652
- *
653
- * @example
654
- * ```typescript
655
- * const limiter = createRateLimiter('api-calls', {
656
- * maxPerSecond: 10,
657
- * burstCapacity: 20,
658
- * });
659
- *
660
- * // In workflow
661
- * const data = await limiter.execute(() =>
662
- * step(() => callApi())
663
- * );
664
- * ```
665
- */
666
- declare function createRateLimiter(name: string, config: RateLimiterConfig): RateLimiter;
667
- /**
668
- * Concurrency limiter interface.
669
- */
670
- interface ConcurrencyLimiter {
671
- /**
672
- * Execute an operation with concurrency limiting.
673
- * @param operation - The operation to execute
674
- * @returns The operation result
675
- */
676
- execute<T>(operation: () => T | Promise<T>): Promise<T>;
677
- /**
678
- * Execute multiple operations with concurrency control.
679
- * @param operations - Array of operation factories
680
- * @returns Array of results (in order)
681
- */
682
- executeAll<T>(operations: Array<() => T | Promise<T>>): Promise<T[]>;
683
- /**
684
- * Execute a Result-returning operation with concurrency limiting.
685
- */
686
- executeResult<T, E>(operation: () => Result<T, E> | AsyncResult$1<T, E>): AsyncResult$1<T, E | QueueFullError>;
687
- /**
688
- * Get current statistics.
689
- */
690
- getStats(): ConcurrencyLimiterStats;
691
- /**
692
- * Reset the concurrency limiter.
693
- */
694
- reset(): void;
695
- }
696
- /**
697
- * Create a concurrency limiter.
698
- *
699
- * @param name - Name for the limiter (used in errors)
700
- * @param config - Concurrency limiter configuration
701
- * @returns A ConcurrencyLimiter instance
702
- *
703
- * @example
704
- * ```typescript
705
- * const limiter = createConcurrencyLimiter('db-pool', {
706
- * maxConcurrent: 10,
707
- * });
708
- *
709
- * // Execute with concurrency control
710
- * const results = await limiter.executeAll(
711
- * ids.map(id => () => fetchItem(id))
712
- * );
713
- * ```
714
- */
715
- declare function createConcurrencyLimiter(name: string, config: ConcurrencyLimiterConfig): ConcurrencyLimiter;
716
- /**
717
- * Configuration for combined rate + concurrency limiter.
718
- */
719
- interface CombinedLimiterConfig {
720
- /**
721
- * Rate limiting configuration.
722
- */
723
- rate?: RateLimiterConfig;
724
- /**
725
- * Concurrency limiting configuration.
726
- */
727
- concurrency?: ConcurrencyLimiterConfig;
728
- }
729
- /**
730
- * Create a combined rate + concurrency limiter.
731
- *
732
- * Operations are first rate-limited, then concurrency-limited.
733
- *
734
- * @param name - Name for the limiter
735
- * @param config - Combined limiter configuration
736
- * @returns An object with both limiters and a combined execute function
737
- *
738
- * @example
739
- * ```typescript
740
- * const limiter = createCombinedLimiter('api', {
741
- * rate: { maxPerSecond: 10 },
742
- * concurrency: { maxConcurrent: 5 },
743
- * });
744
- *
745
- * const result = await limiter.execute(() => callApi());
746
- * ```
747
- */
748
- declare function createCombinedLimiter(name: string, config: CombinedLimiterConfig): {
749
- rate?: RateLimiter;
750
- concurrency?: ConcurrencyLimiter;
751
- execute: <T>(operation: () => T | Promise<T>) => Promise<T>;
752
- };
753
- /**
754
- * Configuration for fixed window rate limiter.
755
- */
756
- interface FixedWindowLimiterConfig {
757
- /**
758
- * Maximum requests allowed per window.
759
- */
760
- limit: number;
761
- /**
762
- * Window duration in milliseconds.
763
- * @default 1000 (1 second)
764
- */
765
- windowMs?: number;
766
- /**
767
- * Strategy when rate limit is exceeded.
768
- * - 'wait': Wait until window resets (default)
769
- * - 'reject': Reject immediately with error
770
- * @default 'wait'
771
- */
772
- strategy?: "wait" | "reject";
773
- }
774
- /**
775
- * Statistics for fixed window rate limiter.
776
- */
777
- interface FixedWindowLimiterStats {
778
- /** Requests made in current window */
779
- requestCount: number;
780
- /** Maximum requests allowed per window */
781
- limit: number;
782
- /** Window duration in milliseconds */
783
- windowMs: number;
784
- /** Time remaining until window reset (ms) */
785
- remainingMs: number;
786
- /** Number of requests waiting for next window */
787
- waitingCount: number;
788
- }
789
- /**
790
- * Fixed window rate limiter interface.
791
- */
792
- interface FixedWindowLimiter {
793
- /**
794
- * Execute an operation with rate limiting.
795
- * @param operation - The operation to execute
796
- * @param cost - Optional cost for this operation (default: 1)
797
- * @returns The operation result
798
- */
799
- execute<T>(operation: () => T | Promise<T>, cost?: number): Promise<T>;
800
- /**
801
- * Execute a Result-returning operation with rate limiting.
802
- * @param operation - The operation to execute
803
- * @param cost - Optional cost for this operation (default: 1)
804
- */
805
- executeResult<T, E>(operation: () => Result<T, E> | AsyncResult$1<T, E>, cost?: number): AsyncResult$1<T, E | RateLimitExceededError>;
806
- /**
807
- * Get current statistics.
808
- */
809
- getStats(): FixedWindowLimiterStats;
810
- /**
811
- * Reset the rate limiter.
812
- */
813
- reset(): void;
814
- }
815
- /**
816
- * Create a fixed window rate limiter.
817
- *
818
- * Unlike token bucket, fixed window resets at fixed intervals.
819
- * Simpler to reason about but can allow bursts at window boundaries.
820
- *
821
- * @param name - Name for the limiter (used in errors)
822
- * @param config - Rate limiter configuration
823
- * @returns A FixedWindowLimiter instance
824
- *
825
- * @example
826
- * ```typescript
827
- * const limiter = createFixedWindowLimiter('api-calls', {
828
- * limit: 100, // 100 requests
829
- * windowMs: 60000, // per minute
830
- * });
831
- *
832
- * // In workflow
833
- * const data = await limiter.execute(() => callApi());
834
- *
835
- * // Cost-based limiting (e.g., batch operations cost more)
836
- * const batchData = await limiter.execute(() => callBatchApi(), 10);
837
- * ```
838
- */
839
- declare function createFixedWindowLimiter(name: string, config: FixedWindowLimiterConfig): FixedWindowLimiter;
840
- /**
841
- * Configuration for cost-based rate limiter.
842
- */
843
- interface CostBasedRateLimiterConfig {
844
- /**
845
- * Maximum tokens (credits) per second refill rate.
846
- */
847
- tokensPerSecond: number;
848
- /**
849
- * Maximum token capacity (burst capacity).
850
- * @default tokensPerSecond * 2
851
- */
852
- maxTokens?: number;
853
- /**
854
- * Strategy when rate limit is exceeded.
855
- * - 'wait': Wait until tokens are available (default)
856
- * - 'reject': Reject immediately with error
857
- * @default 'wait'
858
- */
859
- strategy?: "wait" | "reject";
860
- }
861
- /**
862
- * Statistics for cost-based rate limiter.
863
- */
864
- interface CostBasedRateLimiterStats {
865
- /** Available tokens (can be fractional) */
866
- availableTokens: number;
867
- /** Maximum token capacity */
868
- maxTokens: number;
869
- /** Token refill rate per second */
870
- tokensPerSecond: number;
871
- /** Number of operations waiting */
872
- waitingCount: number;
873
- }
874
- /**
875
- * Cost-based rate limiter interface.
876
- */
877
- interface CostBasedRateLimiter {
878
- /**
879
- * Execute an operation with cost-based rate limiting.
880
- * @param operation - The operation to execute
881
- * @param cost - Token cost for this operation (default: 1)
882
- * @returns The operation result
883
- */
884
- execute<T>(operation: () => T | Promise<T>, cost?: number): Promise<T>;
885
- /**
886
- * Execute a Result-returning operation with cost-based rate limiting.
887
- * @param operation - The operation to execute
888
- * @param cost - Token cost for this operation (default: 1)
889
- */
890
- executeResult<T, E>(operation: () => Result<T, E> | AsyncResult$1<T, E>, cost?: number): AsyncResult$1<T, E | RateLimitExceededError>;
891
- /**
892
- * Get current statistics.
893
- */
894
- getStats(): CostBasedRateLimiterStats;
895
- /**
896
- * Reset the rate limiter.
897
- */
898
- reset(): void;
899
- }
900
- /**
901
- * Create a cost-based token bucket rate limiter.
902
- *
903
- * Different operations can have different costs, allowing fine-grained
904
- * control over resource usage. For example, a batch API call might cost
905
- * 10 tokens while a simple query costs 1.
906
- *
907
- * @param name - Name for the limiter (used in errors)
908
- * @param config - Rate limiter configuration
909
- * @returns A CostBasedRateLimiter instance
910
- *
911
- * @example
912
- * ```typescript
913
- * const limiter = createCostBasedRateLimiter('api', {
914
- * tokensPerSecond: 100, // 100 tokens/second refill
915
- * maxTokens: 200, // Can burst up to 200 tokens
916
- * });
917
- *
918
- * // Simple query costs 1 token
919
- * await limiter.execute(() => simpleQuery());
920
- *
921
- * // Batch operation costs 10 tokens
922
- * await limiter.execute(() => batchOperation(), 10);
923
- *
924
- * // Heavy export costs 50 tokens
925
- * await limiter.execute(() => exportData(), 50);
926
- * ```
927
- */
928
- declare function createCostBasedRateLimiter(name: string, config: CostBasedRateLimiterConfig): CostBasedRateLimiter;
929
- /**
930
- * Preset configurations for common use cases.
931
- */
932
- declare const rateLimiterPresets: {
933
- /**
934
- * Typical API rate limit (10 req/s).
935
- */
936
- readonly api: {
937
- maxPerSecond: number;
938
- burstCapacity: number;
939
- strategy: "wait";
940
- };
941
- /**
942
- * Database pool limit (concurrent connections).
943
- */
944
- readonly database: {
945
- maxConcurrent: number;
946
- strategy: "queue";
947
- maxQueueSize: number;
948
- };
949
- /**
950
- * Aggressive rate limit for external APIs (5 req/s).
951
- */
952
- readonly external: {
953
- maxPerSecond: number;
954
- burstCapacity: number;
955
- strategy: "wait";
956
- };
957
- };
958
-
959
- /**
960
- * awaitly/cache
961
- *
962
- * Caching utilities for memoization and deduplication.
963
- * Inspired by Effect.js caching patterns.
964
- *
965
- * @example
966
- * ```typescript
967
- * import { cached, cachedWithTTL, cachedFunction, once } from 'awaitly';
968
- *
969
- * // Compute once, reuse forever
970
- * const getConfig = cached(() => loadConfig());
971
- *
972
- * // Expire after duration
973
- * const getUser = cachedWithTTL(() => fetchUser(id), { ttl: '5m' });
974
- *
975
- * // Memoize by arguments
976
- * const fetchUserMemo = cachedFunction((id: string) => fetchUser(id));
977
- *
978
- * // Execute exactly once (for initialization)
979
- * const initDb = once(() => connectToDatabase());
980
- * ```
981
- */
982
-
983
- /**
984
- * Duration input type - supports Duration objects or string shorthand.
985
- */
986
- type DurationInput = Duration | string;
987
- /**
988
- * Cache entry with metadata.
989
- */
990
- interface CacheEntry<T> {
991
- value: T;
992
- timestamp: number;
993
- expiresAt?: number;
994
- }
995
- /**
996
- * Cache options.
997
- */
998
- interface CacheOptions {
999
- /**
1000
- * Time-to-live for cached values.
1001
- * Accepts Duration or string shorthand like "5m", "1h", "30s".
1002
- */
1003
- ttl?: DurationInput;
1004
- }
1005
- /**
1006
- * Cached function options.
1007
- */
1008
- interface CachedFunctionOptions<Args extends unknown[]> {
1009
- /**
1010
- * Custom key generator for arguments.
1011
- * Default: JSON.stringify(args)
1012
- */
1013
- keyFn?: (...args: Args) => string;
1014
- /**
1015
- * Time-to-live for cached values.
1016
- */
1017
- ttl?: DurationInput;
1018
- /**
1019
- * Maximum cache size. When exceeded, oldest entries are evicted.
1020
- * @default Infinity
1021
- */
1022
- maxSize?: number;
1023
- }
1024
- /**
1025
- * Cache statistics.
1026
- */
1027
- interface CacheStats {
1028
- hits: number;
1029
- misses: number;
1030
- size: number;
1031
- }
1032
- /**
1033
- * Create a cached computation that executes once and reuses the result.
1034
- *
1035
- * The function is called at most once, even with concurrent calls.
1036
- * Subsequent calls return the cached value immediately.
1037
- *
1038
- * @param fn - Function to compute the cached value
1039
- * @returns Function that returns the cached value
1040
- *
1041
- * @example
1042
- * ```typescript
1043
- * const getConfig = cached(async () => {
1044
- * console.log('Loading config...');
1045
- * return await loadConfigFromFile();
1046
- * });
1047
- *
1048
- * // First call executes the function
1049
- * const config1 = await getConfig(); // "Loading config..."
1050
- *
1051
- * // Subsequent calls return cached value
1052
- * const config2 = await getConfig(); // No log, instant return
1053
- * const config3 = await getConfig(); // No log, instant return
1054
- * ```
1055
- */
1056
- declare function cached<T>(fn: () => T | Promise<T>): () => Promise<T>;
1057
- /**
1058
- * Create a cached computation that expires after a duration.
1059
- *
1060
- * The function is re-executed when the TTL expires.
1061
- * Concurrent calls while computing share the same promise.
1062
- *
1063
- * @param fn - Function to compute the cached value
1064
- * @param options - Cache options including TTL
1065
- * @returns Function that returns the cached value
1066
- *
1067
- * @example
1068
- * ```typescript
1069
- * const getUser = cachedWithTTL(
1070
- * async () => await fetchUser(userId),
1071
- * { ttl: '5m' } // Cache for 5 minutes
1072
- * );
1073
- *
1074
- * const user1 = await getUser(); // Fetches from API
1075
- * const user2 = await getUser(); // Returns cached (within 5 min)
1076
- *
1077
- * // After 5 minutes...
1078
- * const user3 = await getUser(); // Fetches again
1079
- * ```
1080
- */
1081
- declare function cachedWithTTL<T>(fn: () => T | Promise<T>, options: {
1082
- ttl: DurationInput;
1083
- }): () => Promise<T>;
1084
- /**
1085
- * Memoized function interface.
1086
- */
1087
- interface MemoizedFunction<Args extends unknown[], T> {
1088
- (...args: Args): Promise<T>;
1089
- /** Clear the entire cache */
1090
- clear(): void;
1091
- /** Clear a specific cache entry */
1092
- delete(...args: Args): boolean;
1093
- /** Check if an entry exists */
1094
- has(...args: Args): boolean;
1095
- /** Get cache statistics */
1096
- getStats(): CacheStats;
1097
- }
1098
- /**
1099
- * Create a memoized function that caches results by arguments.
1100
- *
1101
- * Each unique set of arguments produces a cached result.
1102
- * Supports TTL and max size limits.
1103
- *
1104
- * @param fn - Function to memoize
1105
- * @param options - Memoization options
1106
- * @returns Memoized function with cache control methods
1107
- *
1108
- * @example
1109
- * ```typescript
1110
- * const fetchUserMemo = cachedFunction(
1111
- * async (id: string) => await fetchUser(id),
1112
- * { ttl: '5m', maxSize: 100 }
1113
- * );
1114
- *
1115
- * const user1 = await fetchUserMemo('user-1'); // Fetches
1116
- * const user2 = await fetchUserMemo('user-2'); // Fetches
1117
- * const user1Again = await fetchUserMemo('user-1'); // Cached!
1118
- *
1119
- * // Cache control
1120
- * fetchUserMemo.delete('user-1'); // Remove specific entry
1121
- * fetchUserMemo.clear(); // Clear all
1122
- * console.log(fetchUserMemo.getStats()); // { hits: 1, misses: 2, size: 0 }
1123
- * ```
1124
- */
1125
- declare function cachedFunction<Args extends unknown[], T>(fn: (...args: Args) => T | Promise<T>, options?: CachedFunctionOptions<Args>): MemoizedFunction<Args, T>;
1126
- /**
1127
- * Once-executed function interface.
1128
- */
1129
- interface OnceFunction<T> {
1130
- (): Promise<T>;
1131
- /** Check if the function has been called */
1132
- called: boolean;
1133
- /** Check if execution completed successfully */
1134
- completed: boolean;
1135
- /** Check if execution failed */
1136
- failed: boolean;
1137
- /** Reset to allow re-execution */
1138
- reset(): void;
1139
- }
1140
- /**
1141
- * Create a function that executes exactly once.
1142
- *
1143
- * Useful for initialization code that should only run once.
1144
- * Subsequent calls return the same result or re-throw the same error.
1145
- *
1146
- * @param fn - Function to execute once
1147
- * @returns Function that executes once and returns the result
1148
- *
1149
- * @example
1150
- * ```typescript
1151
- * const initDb = once(async () => {
1152
- * console.log('Connecting to database...');
1153
- * const conn = await createConnection();
1154
- * return conn;
1155
- * });
1156
- *
1157
- * // First call executes
1158
- * const db1 = await initDb(); // "Connecting to database..."
1159
- *
1160
- * // Subsequent calls return cached result
1161
- * const db2 = await initDb(); // Instant, same connection
1162
- * const db3 = await initDb(); // Instant, same connection
1163
- *
1164
- * console.log(initDb.called); // true
1165
- * console.log(initDb.completed); // true
1166
- * ```
1167
- */
1168
- declare function once<T>(fn: () => T | Promise<T>): OnceFunction<T>;
1169
- /**
1170
- * General purpose cache interface.
1171
- */
1172
- interface Cache<K, V> {
1173
- /** Get a value from the cache */
1174
- get(key: K): V | undefined;
1175
- /** Set a value in the cache */
1176
- set(key: K, value: V, options?: {
1177
- ttl?: DurationInput;
1178
- }): void;
1179
- /** Check if a key exists */
1180
- has(key: K): boolean;
1181
- /** Delete a key from the cache */
1182
- delete(key: K): boolean;
1183
- /** Clear the entire cache */
1184
- clear(): void;
1185
- /** Get the cache size */
1186
- size: number;
1187
- /** Get cache statistics */
1188
- getStats(): CacheStats;
1189
- }
1190
- /**
1191
- * Cache configuration.
1192
- */
1193
- interface CacheConfig {
1194
- /**
1195
- * Default TTL for all entries.
1196
- */
1197
- defaultTTL?: DurationInput;
1198
- /**
1199
- * Maximum cache size.
1200
- * @default Infinity
1201
- */
1202
- maxSize?: number;
1203
- }
1204
- /**
1205
- * Create a general-purpose cache with TTL and size limits.
1206
- *
1207
- * @param config - Cache configuration
1208
- * @returns A Cache instance
1209
- *
1210
- * @example
1211
- * ```typescript
1212
- * const cache = createCache<string, User>({
1213
- * defaultTTL: '5m',
1214
- * maxSize: 1000,
1215
- * });
1216
- *
1217
- * cache.set('user:1', user);
1218
- * cache.set('user:2', user2, { ttl: '1h' }); // Override TTL
1219
- *
1220
- * const user = cache.get('user:1');
1221
- * ```
1222
- */
1223
- declare function createCache<K, V>(config?: CacheConfig): Cache<K, V>;
1224
-
1225
- /**
1226
- * awaitly/singleflight
1227
- *
1228
- * Request coalescing - dedupe concurrent identical requests.
1229
- * Multiple concurrent calls with the same key share one in-flight request.
1230
- *
1231
- * @example
1232
- * ```typescript
1233
- * import { singleflight } from 'awaitly';
1234
- *
1235
- * const fetchUserOnce = singleflight(
1236
- * (id: string) => fetchUser(id),
1237
- * { key: (id) => `user:${id}` }
1238
- * );
1239
- *
1240
- * // All concurrent calls share one request
1241
- * const [user1, user2] = await Promise.all([
1242
- * fetchUserOnce('1'),
1243
- * fetchUserOnce('1'), // Same key - shares request
1244
- * ]);
1245
- * ```
1246
- */
1247
-
1248
- /**
1249
- * Options for the singleflight wrapper.
1250
- */
1251
- type SingleflightOptions<Args extends unknown[]> = {
1252
- /**
1253
- * Extract cache key from arguments.
1254
- * Calls with the same key will share one in-flight request.
1255
- */
1256
- key: (...args: Args) => string;
1257
- /**
1258
- * Optional TTL in milliseconds to cache successful results.
1259
- * After TTL expires, next call will trigger a fresh request.
1260
- * @default 0 (no caching after completion - only dedupes in-flight requests)
1261
- */
1262
- ttl?: number;
1263
- };
1264
- /**
1265
- * Create a singleflight-wrapped function.
1266
- * Concurrent calls with the same key share one in-flight request.
1267
- *
1268
- * ## How It Works
1269
- *
1270
- * 1. First caller with a key starts the operation
1271
- * 2. Subsequent callers with the same key get the same Promise
1272
- * 3. When operation completes, all callers receive the same Result
1273
- * 4. Key is removed from in-flight tracking (unless TTL is set)
1274
- *
1275
- * ## Use Cases
1276
- *
1277
- * - **Prevent thundering herd**: Multiple requests for the same user
1278
- * - **API deduplication**: Avoid duplicate network calls
1279
- * - **Expensive operations**: Share computation across callers
1280
- *
1281
- * @param operation - The async operation that returns an AsyncResult
1282
- * @param options - Configuration with key extraction function
1283
- * @returns A wrapped function that deduplicates concurrent calls
1284
- *
1285
- * @example
1286
- * ```typescript
1287
- * import { singleflight } from 'awaitly';
1288
- * import { ok, err, type AsyncResult } from 'awaitly';
1289
- *
1290
- * const fetchUser = async (id: string): AsyncResult<User, 'NOT_FOUND'> =>
1291
- * id !== '0' ? ok({ id, name: `User ${id}` }) : err('NOT_FOUND');
1292
- *
1293
- * const fetchUserOnce = singleflight(fetchUser, {
1294
- * key: (id) => `user:${id}`,
1295
- * });
1296
- *
1297
- * // Concurrent calls share one request
1298
- * const [a, b, c] = await Promise.all([
1299
- * fetchUserOnce('1'), // Triggers fetch
1300
- * fetchUserOnce('1'), // Joins existing fetch
1301
- * fetchUserOnce('2'), // Different key - new fetch
1302
- * ]);
1303
- * ```
1304
- *
1305
- * @example
1306
- * ```typescript
1307
- * // With TTL for result caching
1308
- * const fetchUserCached = singleflight(fetchUser, {
1309
- * key: (id) => `user:${id}`,
1310
- * ttl: 5000, // Cache successful results for 5 seconds
1311
- * });
1312
- *
1313
- * const user1 = await fetchUserCached('1'); // Fetches
1314
- * const user2 = await fetchUserCached('1'); // Returns cached (within TTL)
1315
- * // After 5 seconds...
1316
- * const user3 = await fetchUserCached('1'); // Fetches again
1317
- * ```
1318
- */
1319
- declare function singleflight<Args extends unknown[], T, E, C = unknown>(operation: (...args: Args) => AsyncResult$1<T, E, C>, options: SingleflightOptions<Args>): (...args: Args) => AsyncResult$1<T, E, C>;
1320
- /**
1321
- * Create a singleflight group with manual key management.
1322
- * More flexible but lower-level API than the `singleflight` wrapper.
1323
- *
1324
- * @returns A group object with execute, isInflight, and clear methods
1325
- *
1326
- * @example
1327
- * ```typescript
1328
- * import { createSingleflightGroup } from 'awaitly';
1329
- *
1330
- * const group = createSingleflightGroup<User, 'NOT_FOUND'>();
1331
- *
1332
- * // Execute with manual key
1333
- * const user1 = await group.execute('user:1', () => fetchUser('1'));
1334
- * const user2 = await group.execute('user:1', () => fetchUser('1')); // Shares request
1335
- *
1336
- * // Check if request is in-flight
1337
- * if (group.isInflight('user:1')) {
1338
- * console.log('Request pending');
1339
- * }
1340
- *
1341
- * // Clear all in-flight requests
1342
- * group.clear();
1343
- * ```
1344
- */
1345
- declare function createSingleflightGroup<T, E, C = unknown>(): {
1346
- /**
1347
- * Execute or join an in-flight request for the given key.
1348
- */
1349
- execute: (key: string, operation: () => AsyncResult$1<T, E, C>) => AsyncResult$1<T, E, C>;
1350
- /**
1351
- * Check if a request is currently in-flight for the key.
1352
- */
1353
- isInflight: (key: string) => boolean;
1354
- /**
1355
- * Get the number of in-flight requests.
1356
- */
1357
- size: () => number;
1358
- /**
1359
- * Clear all in-flight tracking (does not cancel operations).
1360
- */
1361
- clear: () => void;
1362
- };
1363
-
1364
- /**
1365
- * awaitly/policies
1366
- *
1367
- * Policy-Driven Step Middleware - Reusable bundles of StepOptions
1368
- * that can be composed and applied per-workflow or per-step.
1369
- */
1370
-
1371
- /**
1372
- * A policy is a partial StepOptions that can be merged with other policies.
1373
- */
1374
- type Policy = Partial<StepOptions>;
1375
- /**
1376
- * A policy factory that creates policies based on context.
1377
- */
1378
- type PolicyFactory<T = void> = T extends void ? () => Policy : (context: T) => Policy;
1379
- /**
1380
- * Named policy with metadata.
1381
- */
1382
- interface NamedPolicy {
1383
- name: string;
1384
- policy: Policy;
1385
- description?: string;
1386
- }
1387
- /**
1388
- * Merge multiple policies into a single StepOptions object.
1389
- * Later policies override earlier ones for conflicting properties.
1390
- * Retry and timeout options are deep-merged.
1391
- *
1392
- * @param policies - Policies to merge (in order of precedence)
1393
- * @returns Merged StepOptions
1394
- *
1395
- * @example
1396
- * ```typescript
1397
- * const merged = mergePolicies(
1398
- * timeoutPolicies.api, // timeout: 5000ms
1399
- * retryPolicies.transient, // retry: 3 attempts
1400
- * { name: 'fetch-user' } // name override
1401
- * );
1402
- * ```
1403
- */
1404
- declare function mergePolicies(...policies: Policy[]): StepOptions;
1405
- /**
1406
- * Create a policy applier that merges base policies with step-specific options.
1407
- *
1408
- * @param basePolicies - Base policies to apply to all steps
1409
- * @returns A function that applies policies to step options
1410
- *
1411
- * @example
1412
- * ```typescript
1413
- * const applyPolicy = createPolicyApplier(
1414
- * timeoutPolicies.api,
1415
- * retryPolicies.transient
1416
- * );
1417
- *
1418
- * // In workflow
1419
- * const user = await step(
1420
- * 'fetch-user',
1421
- * () => fetchUser(id),
1422
- * applyPolicy({ key: 'user:' + id })
1423
- * );
1424
- * ```
1425
- */
1426
- declare function createPolicyApplier(...basePolicies: Policy[]): (stepOptions?: StepOptions) => StepOptions;
1427
- /**
1428
- * Create a named policy bundle for reuse across workflows.
1429
- *
1430
- * @param name - Policy bundle name
1431
- * @param policies - Policies to include in the bundle
1432
- * @returns Named policy object
1433
- */
1434
- declare function createPolicyBundle(name: string, ...policies: Policy[]): NamedPolicy;
1435
- /**
1436
- * Create a retry policy with the given options.
1437
- */
1438
- declare function retryPolicy(options: RetryOptions): Policy;
1439
- /**
1440
- * Pre-built retry policies for common scenarios.
1441
- */
1442
- declare const retryPolicies: {
1443
- /**
1444
- * No retry - fail immediately on error.
1445
- */
1446
- readonly none: Partial<StepOptions>;
1447
- /**
1448
- * Quick retry for transient errors (3 attempts, fast backoff).
1449
- */
1450
- readonly transient: Partial<StepOptions>;
1451
- /**
1452
- * Standard retry for API calls (3 attempts, moderate backoff).
1453
- */
1454
- readonly standard: Partial<StepOptions>;
1455
- /**
1456
- * Aggressive retry for critical operations (5 attempts, longer backoff).
1457
- */
1458
- readonly aggressive: Partial<StepOptions>;
1459
- /**
1460
- * Fixed interval retry (useful for polling).
1461
- */
1462
- readonly fixed: (attempts: number, delayMs: number) => Policy;
1463
- /**
1464
- * Linear backoff retry.
1465
- */
1466
- readonly linear: (attempts: number, initialDelay: number) => Policy;
1467
- /**
1468
- * Custom retry policy builder.
1469
- */
1470
- readonly custom: (options: Partial<RetryOptions> & {
1471
- attempts: number;
1472
- }) => Policy;
1473
- };
1474
- /**
1475
- * Create a timeout policy with the given options.
1476
- */
1477
- declare function timeoutPolicy(options: TimeoutOptions): Policy;
1478
- /**
1479
- * Pre-built timeout policies for common scenarios.
1480
- */
1481
- declare const timeoutPolicies: {
1482
- /**
1483
- * No timeout.
1484
- */
1485
- readonly none: Policy;
1486
- /**
1487
- * Fast timeout for quick operations (1 second).
1488
- */
1489
- readonly fast: Partial<StepOptions>;
1490
- /**
1491
- * Standard API timeout (5 seconds).
1492
- */
1493
- readonly api: Partial<StepOptions>;
1494
- /**
1495
- * Extended timeout for slower operations (30 seconds).
1496
- */
1497
- readonly extended: Partial<StepOptions>;
1498
- /**
1499
- * Long timeout for batch operations (2 minutes).
1500
- */
1501
- readonly long: Partial<StepOptions>;
1502
- /**
1503
- * Custom timeout in milliseconds.
1504
- */
1505
- readonly ms: (ms: number) => Policy;
1506
- /**
1507
- * Custom timeout in seconds.
1508
- */
1509
- readonly seconds: (seconds: number) => Policy;
1510
- /**
1511
- * Timeout with custom error.
1512
- */
1513
- readonly withError: <E>(ms: number, error: E) => Policy;
1514
- /**
1515
- * Timeout with AbortSignal support.
1516
- */
1517
- readonly withSignal: (ms: number) => Policy;
1518
- };
1519
- /**
1520
- * Pre-built combined policies for common service patterns.
1521
- */
1522
- declare const servicePolicies: {
1523
- /**
1524
- * Policy for external HTTP APIs.
1525
- * - 5 second timeout
1526
- * - 3 retries with exponential backoff
1527
- */
1528
- readonly httpApi: StepOptions;
1529
- /**
1530
- * Policy for database operations.
1531
- * - 30 second timeout
1532
- * - 2 retries for transient errors
1533
- */
1534
- readonly database: StepOptions;
1535
- /**
1536
- * Policy for cache operations.
1537
- * - 1 second timeout
1538
- * - No retry (cache misses are not errors)
1539
- */
1540
- readonly cache: StepOptions;
1541
- /**
1542
- * Policy for message queue operations.
1543
- * - 30 second timeout
1544
- * - 5 retries with longer backoff
1545
- */
1546
- readonly messageQueue: StepOptions;
1547
- /**
1548
- * Policy for file operations.
1549
- * - 2 minute timeout
1550
- * - 3 retries
1551
- */
1552
- readonly fileSystem: StepOptions;
1553
- /**
1554
- * Policy for third-party services with rate limits.
1555
- * - 10 second timeout
1556
- * - 5 retries with linear backoff
1557
- */
1558
- readonly rateLimited: StepOptions;
1559
- };
1560
- /**
1561
- * Options for withPolicies workflow wrapper.
1562
- */
1563
- interface WithPoliciesOptions {
1564
- /**
1565
- * Base policies applied to all steps.
1566
- */
1567
- policies: Policy[];
1568
- /**
1569
- * Step-specific policy overrides by name or key pattern.
1570
- */
1571
- overrides?: Record<string, Policy>;
1572
- }
1573
- /**
1574
- * Create step options with policies applied.
1575
- * This is a helper for applying policies inline.
1576
- *
1577
- * @param policies - Policies to apply
1578
- * @param stepOptions - Step-specific options
1579
- * @returns Merged StepOptions
1580
- *
1581
- * @example
1582
- * ```typescript
1583
- * const user = await step(
1584
- * () => fetchUser(id),
1585
- * withPolicy(servicePolicies.httpApi, { name: 'fetch-user' })
1586
- * );
1587
- * ```
1588
- */
1589
- declare function withPolicy(policy: Policy, stepOptions?: StepOptions): StepOptions;
1590
- /**
1591
- * Create step options with multiple policies applied.
1592
- *
1593
- * @param policies - Policies to apply (in order)
1594
- * @param stepOptions - Step-specific options
1595
- * @returns Merged StepOptions
1596
- *
1597
- * @example
1598
- * ```typescript
1599
- * const user = await step(
1600
- * 'fetch-user',
1601
- * () => fetchUser(id),
1602
- * withPolicies([timeoutPolicies.api, retryPolicies.standard])
1603
- * );
1604
- * ```
1605
- */
1606
- declare function withPolicies(policies: Policy[], stepOptions?: StepOptions): StepOptions;
1607
- /**
1608
- * Create a policy that applies conditionally.
1609
- *
1610
- * @param condition - Condition to check
1611
- * @param policy - Policy to apply if condition is true
1612
- * @param elsePolicy - Policy to apply if condition is false (optional)
1613
- * @returns The selected policy
1614
- *
1615
- * @example
1616
- * ```typescript
1617
- * const policy = conditionalPolicy(
1618
- * isProduction,
1619
- * servicePolicies.httpApi, // Use in production
1620
- * retryPolicies.none // Skip in development
1621
- * );
1622
- * ```
1623
- */
1624
- declare function conditionalPolicy(condition: boolean, policy: Policy, elsePolicy?: Policy): Policy;
1625
- /**
1626
- * Create a policy based on environment.
1627
- *
1628
- * @param envPolicies - Map of environment names to policies
1629
- * @param currentEnv - Current environment (defaults to NODE_ENV)
1630
- * @param defaultPolicy - Default policy if environment not found
1631
- * @returns The selected policy
1632
- *
1633
- * @example
1634
- * ```typescript
1635
- * const policy = envPolicy({
1636
- * production: servicePolicies.httpApi,
1637
- * development: retryPolicies.none,
1638
- * test: retryPolicies.none,
1639
- * });
1640
- * ```
1641
- */
1642
- declare function envPolicy(envPolicies: Record<string, Policy>, currentEnv?: string, defaultPolicy?: Policy): Policy;
1643
- /**
1644
- * A registry for managing named policies.
1645
- */
1646
- interface PolicyRegistry {
1647
- /**
1648
- * Register a named policy.
1649
- */
1650
- register(name: string, policy: Policy): void;
1651
- /**
1652
- * Get a policy by name.
1653
- */
1654
- get(name: string): Policy | undefined;
1655
- /**
1656
- * Check if a policy exists.
1657
- */
1658
- has(name: string): boolean;
1659
- /**
1660
- * Get all registered policy names.
1661
- */
1662
- names(): string[];
1663
- /**
1664
- * Create step options using a registered policy.
1665
- */
1666
- apply(policyName: string, stepOptions?: StepOptions): StepOptions;
1667
- }
1668
- /**
1669
- * Create a policy registry for managing named policies.
1670
- *
1671
- * @returns PolicyRegistry instance
1672
- *
1673
- * @example
1674
- * ```typescript
1675
- * const registry = createPolicyRegistry();
1676
- *
1677
- * // Register policies
1678
- * registry.register('api', servicePolicies.httpApi);
1679
- * registry.register('db', servicePolicies.database);
1680
- *
1681
- * // Use in workflow
1682
- * const user = await step(
1683
- * 'fetch-user',
1684
- * () => fetchUser(id),
1685
- * registry.apply('api')
1686
- * );
1687
- * ```
1688
- */
1689
- declare function createPolicyRegistry(): PolicyRegistry;
1690
- /**
1691
- * Fluent builder for constructing step options.
1692
- */
1693
- interface StepOptionsBuilder {
1694
- /**
1695
- * Set step key for caching.
1696
- */
1697
- key(key: string): StepOptionsBuilder;
1698
- /**
1699
- * Apply a policy.
1700
- */
1701
- policy(policy: Policy): StepOptionsBuilder;
1702
- /**
1703
- * Set timeout in milliseconds.
1704
- */
1705
- timeout(ms: number): StepOptionsBuilder;
1706
- /**
1707
- * Set retry options.
1708
- */
1709
- retry(options: RetryOptions): StepOptionsBuilder;
1710
- /**
1711
- * Set retry attempts (with default exponential backoff).
1712
- */
1713
- retries(attempts: number): StepOptionsBuilder;
1714
- /**
1715
- * Build the final StepOptions.
1716
- */
1717
- build(): StepOptions;
1718
- }
1719
- /**
1720
- * Create a fluent builder for step options.
1721
- *
1722
- * @returns StepOptionsBuilder instance
1723
- *
1724
- * @example
1725
- * ```typescript
1726
- * const options = stepOptions()
1727
- * .key('user:123')
1728
- * .timeout(5000)
1729
- * .retries(3)
1730
- * .build();
1731
- *
1732
- * const user = await step('fetch-user', () => fetchUser(id), options);
1733
- * ```
1734
- */
1735
- declare function stepOptions(): StepOptionsBuilder;
1736
-
1737
221
  /**
1738
222
  * awaitly/conditional
1739
223
  *
@@ -1980,4 +464,4 @@ declare function createConditionalHelpers<C = unknown>(ctx: ConditionalContext<C
1980
464
  unlessOr: <T, D>(condition: boolean, operation: Operation<T>, defaultValue: D, options?: ConditionalOptions) => MaybeAsync<T | D>;
1981
465
  };
1982
466
 
1983
- export { AsyncResult, type Cache, type CacheConfig, type CacheEntry, type CacheOptions, type CacheStats, type CachedFunctionOptions, type CircuitBreaker, type CircuitBreakerConfig, type CircuitBreakerStats, CircuitOpenError, type CircuitState, type CombinedLimiterConfig, type ConcurrencyLimiter, type ConcurrencyLimiterConfig, type ConcurrencyLimiterStats, type ConditionalContext, type ConditionalOptions, type CostBasedRateLimiter, type CostBasedRateLimiterConfig, type CostBasedRateLimiterStats, Duration, type DurationInput, Duration as DurationType, ErrorOf, type FixedWindowLimiter, type FixedWindowLimiterConfig, type FixedWindowLimiterStats, Match, type Matcher, type MemoizedFunction, type NamedPolicy, type OnceFunction, type Policy, type PolicyDelay, type PolicyFactory, type PolicyFn, type PolicyRegistry, type QueueFullError, type RateLimitExceededError, type RateLimiter, type RateLimiterConfig, type RateLimiterStats, RetryOptions, type RetryPolicyOptions, type SingleflightOptions, StepOptions, type StepOptionsBuilder, type Tagged, TimeoutError, TimeoutOptions, UnexpectedError, type WithPoliciesOptions, WorkflowEvent, cached, cachedFunction, cachedWithTTL, circuitBreakerPresets, conditionalPolicy, createCache, createCircuitBreaker, createCombinedLimiter, createConcurrencyLimiter, createConditionalHelpers, createCostBasedRateLimiter, createFixedWindowLimiter, createPolicyApplier, createPolicyBundle, createPolicyRegistry, createRateLimiter, createSingleflightGroup, envPolicy, exhaustive, fallback, isCircuitOpenError, isOneOf, isQueueFullError, isRateLimitExceededError, is as isTag, orElse as matchOrElse, tag as matchTag, tags as matchTags, matchValue, mergePolicies, once, orElseValue, rateLimiterPresets, retry, retryPolicies, retryPolicy, servicePolicies, singleflight, stepOptions, timeout, timeoutPolicies, timeoutPolicy, unless, unlessOr, when, whenOr, withPolicies, withPolicy };
467
+ export { type ConditionalContext, type ConditionalOptions, Match, type Matcher, type Tagged, WorkflowEvent, createConditionalHelpers, exhaustive, isOneOf, is as isTag, orElse as matchOrElse, tag as matchTag, tags as matchTags, matchValue, orElseValue, unless, unlessOr, when, whenOr };