tryharder 0.1.2 → 0.2.1
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 +63 -55
- package/dist/errors.d.ts +6 -1
- package/dist/errors.js +14 -4
- package/dist/index.d.ts +82 -10
- package/dist/index.js +144 -206
- package/dist/shared/chunk-nw88v1ee.js +123 -0
- package/dist/types.d.ts +12 -3
- package/package.json +12 -12
- package/dist/shared/chunk-f024nrjy.js +0 -108
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ const result = await try$
|
|
|
38
38
|
catch: () => new RequestFailedError("request failed"),
|
|
39
39
|
})
|
|
40
40
|
|
|
41
|
-
// result is OrderStatus | RequestFailedError |
|
|
41
|
+
// result is OrderStatus | RequestFailedError | TimeoutError
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
<details>
|
|
@@ -47,7 +47,6 @@ const result = await try$
|
|
|
47
47
|
- [Why not plain try/catch?](#why-not-plain-trycatch)
|
|
48
48
|
- [Features](#features)
|
|
49
49
|
- [Installation](#installation)
|
|
50
|
-
- [Migration from hardtry](#migration-from-hardtry)
|
|
51
50
|
- [Execution Model](#execution-model)
|
|
52
51
|
- [Type Semantics](#type-semantics)
|
|
53
52
|
- [Quick Start](#quick-start)
|
|
@@ -59,7 +58,7 @@ const result = await try$
|
|
|
59
58
|
- [all and allSettled](#all-and-allsettled)
|
|
60
59
|
- [flow and $exit](#flow-and-exit)
|
|
61
60
|
- [gen](#gen)
|
|
62
|
-
- [
|
|
61
|
+
- [disposer](#disposer)
|
|
63
62
|
- [API Reference](#api-reference)
|
|
64
63
|
- [Common Recipes](#common-recipes)
|
|
65
64
|
- [When not to use tryharder](#when-not-to-use-tryharder)
|
|
@@ -133,7 +132,7 @@ const result = await try$
|
|
|
133
132
|
})
|
|
134
133
|
|
|
135
134
|
// result is
|
|
136
|
-
// User | UserUnavailableError |
|
|
135
|
+
// User | UserUnavailableError | TimeoutError | CancellationError
|
|
137
136
|
```
|
|
138
137
|
|
|
139
138
|
That is the core shift:
|
|
@@ -142,7 +141,8 @@ That is the core shift:
|
|
|
142
141
|
- `tryharder` exposes execution policy in the builder chain and failure shape in the return type.
|
|
143
142
|
- `run(fn)` returns `T | UnhandledException`.
|
|
144
143
|
- `run({ try, catch })` returns `T | C`.
|
|
145
|
-
- Adding `
|
|
144
|
+
- Adding `timeout(...)` and `signal(...)` widens the union with `TimeoutError` and `CancellationError`.
|
|
145
|
+
- Adding `retry(...)` changes how persistent failure is reported: with `catch`, the last attempt's error is mapped by `catch`; without `catch`, it surfaces as `RetryExhaustedError` (last error as `cause`) instead of `UnhandledException`.
|
|
146
146
|
|
|
147
147
|
## Features
|
|
148
148
|
|
|
@@ -151,7 +151,7 @@ That is the core shift:
|
|
|
151
151
|
- **Sync and async parity** - Use the same mental model for `runSync(...)` and `run(...)`.
|
|
152
152
|
- **Named task orchestration** - Express concurrent and ordered workflows with object-shaped task graphs instead of positional arrays.
|
|
153
153
|
- **Observable execution hooks** - Add top-level instrumentation with `wrap(...)` without changing task behavior.
|
|
154
|
-
- **Resource cleanup** - Register teardown that survives async boundaries with `
|
|
154
|
+
- **Resource cleanup** - Register teardown that survives async boundaries with `disposer()` and task disposers.
|
|
155
155
|
- **No runtime dependencies** - The published package ships without runtime dependencies.
|
|
156
156
|
|
|
157
157
|
## Installation
|
|
@@ -170,39 +170,23 @@ yarn add tryharder
|
|
|
170
170
|
pnpm add tryharder
|
|
171
171
|
```
|
|
172
172
|
|
|
173
|
-
## Migration from hardtry
|
|
174
|
-
|
|
175
|
-
Replace import specifiers only:
|
|
176
|
-
|
|
177
|
-
- `hardtry` -> `tryharder`
|
|
178
|
-
- `hardtry/errors` -> `tryharder/errors`
|
|
179
|
-
- `hardtry/types` -> `tryharder/types`
|
|
180
|
-
|
|
181
|
-
You can keep the same namespace alias in your code:
|
|
182
|
-
|
|
183
|
-
```ts
|
|
184
|
-
import * as try$ from "tryharder"
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
No runtime API names changed.
|
|
188
|
-
|
|
189
173
|
## Execution Model
|
|
190
174
|
|
|
191
175
|
`tryharder` has three layers: terminal execution APIs, policy builders, and orchestration APIs.
|
|
192
176
|
|
|
193
|
-
Terminal execution APIs are `run(...)` and `runSync(...)`. They are the points where work is actually executed and a result union is produced. Function form is the minimal shape and returns `T | UnhandledException
|
|
177
|
+
Terminal execution APIs are `run(...)` and `runSync(...)`. They are the points where work is actually executed and a result union is produced. Function form is the minimal shape and returns `T | UnhandledException` by default, or `T | RetryExhaustedError` when retry is configured. Object form adds a `catch` mapper and returns `T | C`.
|
|
194
178
|
|
|
195
179
|
Policy builders decorate terminal execution. `retry(...)`, `timeout(...)`, and `signal(...)` do not run work by themselves; they configure the next terminal call and widen the resulting union with the policy-level failures they can introduce. `retry(limit)` counts the first attempt. `timeout(ms)` applies one total deadline across attempts, delays, and catch handling. `signal(abortSignal)` forwards external cancellation into execution.
|
|
196
180
|
|
|
197
181
|
Orchestration APIs scale the same model from one operation to a task graph. `all(...)` runs a fail-fast named task map. `allSettled(...)` preserves every settled task outcome. `flow(...)` runs an ordered workflow that must explicitly terminate through `this.$exit(...)`.
|
|
198
182
|
|
|
199
|
-
`wrap(...)` sits above those execution APIs as observational middleware. It can inspect readonly execution context and surround terminal calls, but it is not available after `retry(...)`, `timeout(...)`, or execution-scoped `signal(...)` chains. `gen(...)` offers a more linear way to compose returned unions. `
|
|
183
|
+
`wrap(...)` sits above those execution APIs as observational middleware. It can inspect readonly execution context and surround terminal calls, but it is not available after `retry(...)`, `timeout(...)`, or execution-scoped `signal(...)` chains. `gen(...)` offers a more linear way to compose returned unions. `disposer()` provides cleanup registration for work that spans async boundaries.
|
|
200
184
|
|
|
201
185
|
| Term | Meaning |
|
|
202
186
|
| --------------------- | ------------------------------------------------------------------------------ |
|
|
203
187
|
| `run` | Async terminal execution that returns a value, mapped failure, or policy error |
|
|
204
188
|
| `runSync` | Sync terminal execution for synchronous work only |
|
|
205
|
-
| `retry(limit)` | Retry policy
|
|
189
|
+
| `retry(limit)` | Retry policy; `limit` is a positive integer counting the first attempt |
|
|
206
190
|
| `timeout(ms)` | Total execution timeout across attempts, delays, and catch handling |
|
|
207
191
|
| `signal(abortSignal)` | External cancellation for `run(...)` and root-level orchestration |
|
|
208
192
|
| `wrap(fn)` | Top-level observational middleware around terminal APIs |
|
|
@@ -237,10 +221,20 @@ const result = await try$
|
|
|
237
221
|
})
|
|
238
222
|
|
|
239
223
|
// result is
|
|
240
|
-
// ValidationError |
|
|
224
|
+
// ValidationError | TimeoutError
|
|
241
225
|
```
|
|
242
226
|
|
|
243
|
-
That inferred union is the contract. A caller can see whether a function returns a domain error
|
|
227
|
+
That inferred union is the contract. A caller can see whether a function returns a domain error and whether a deadline may fire, without reading the implementation body.
|
|
228
|
+
|
|
229
|
+
The `catch` contract is strict: `catch` maps errors that originated inside `try` — thrown directly, or carried out of the retry loop as the last attempt's error once the retry policy gives up. Policy outcomes (`TimeoutError`, `CancellationError`) never pass through `catch`; they surface typed in the union so you can handle them at the call site:
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
if (result instanceof TimeoutError) {
|
|
233
|
+
// deadline expired; map or handle it here
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Without `catch`, unmapped failures are wrapped: `RetryExhaustedError` when a retry policy gave up (for any reason — limit exhausted or `shouldRetry` declining), `UnhandledException` otherwise. The original error is always available as `cause`.
|
|
244
238
|
|
|
245
239
|
`Panic` is intentionally separate from that model. It signals programmer errors such as invalid builder usage or invalid task graphs, not expected business-domain failures.
|
|
246
240
|
|
|
@@ -407,6 +401,8 @@ const result = await try$
|
|
|
407
401
|
|
|
408
402
|
`timeout(ms)` measures total execution time, not just a single attempt.
|
|
409
403
|
|
|
404
|
+
`runSync(...)` stays available after the numeric retry shorthand (`retry(3)`), but not after the object form (`retry({ ... })`) or `timeout(...)` — those policies may need to wait or interrupt, which synchronous execution cannot do. This restriction is intentionally conservative: it is enforced at the type level even for object policies that would be sync-safe at runtime (constant backoff, no delay, no jitter). If you need retries with `runSync(...)`, use the numeric shorthand.
|
|
405
|
+
|
|
410
406
|
Apply `signal(...)` on the root builder when you want cancellation to cover `all(...)`, `allSettled(...)`, or `flow(...)`.
|
|
411
407
|
|
|
412
408
|
### wrap
|
|
@@ -495,21 +491,21 @@ const value = await try$.gen(function* (use) {
|
|
|
495
491
|
})
|
|
496
492
|
```
|
|
497
493
|
|
|
498
|
-
###
|
|
494
|
+
### disposer
|
|
499
495
|
|
|
500
|
-
Use `
|
|
496
|
+
Use `disposer()` when cleanup should stay colocated with the workflow that allocates the resource, even across async boundaries. The returned `AsyncDisposer` gives you three operations:
|
|
501
497
|
|
|
502
|
-
- `
|
|
498
|
+
- `defer(fn)` registers a cleanup callback.
|
|
503
499
|
- `use(resource)` tracks a disposable resource.
|
|
504
|
-
- `
|
|
500
|
+
- `dispose()` runs the registered teardown in reverse order (also triggered by leaving an `await using` scope).
|
|
505
501
|
|
|
506
502
|
```ts
|
|
507
|
-
await using disposer = try$.
|
|
503
|
+
await using disposer = try$.disposer()
|
|
508
504
|
|
|
509
505
|
{
|
|
510
506
|
const connection = await db.connect()
|
|
511
507
|
|
|
512
|
-
disposer.
|
|
508
|
+
disposer.defer(async () => {
|
|
513
509
|
await connection.close()
|
|
514
510
|
})
|
|
515
511
|
|
|
@@ -523,32 +519,44 @@ await using disposer = try$.dispose()
|
|
|
523
519
|
|
|
524
520
|
### Runtime
|
|
525
521
|
|
|
526
|
-
| Export | Description
|
|
527
|
-
| -------------- |
|
|
528
|
-
| `run` | Async terminal execution API
|
|
529
|
-
| `runSync` | Sync terminal execution API
|
|
530
|
-
| `retry` | Create an execution-scoped retry builder
|
|
531
|
-
| `retryOptions` | Normalize retry policy input
|
|
532
|
-
| `timeout` | Add a total execution timeout
|
|
533
|
-
| `signal` | Add external cancellation to execution or root-level orchestration
|
|
534
|
-
| `wrap` | Add top-level observational middleware
|
|
535
|
-
| `all` | Run a fail-fast parallel named task graph
|
|
536
|
-
| `allSettled` | Run a settled parallel named task graph
|
|
537
|
-
| `flow` | Run an ordered workflow with explicit early exit
|
|
538
|
-
| `gen` | Compose `run(...)` results through generators
|
|
539
|
-
| `
|
|
522
|
+
| Export | Description |
|
|
523
|
+
| -------------- | ------------------------------------------------------------------------- |
|
|
524
|
+
| `run` | Async terminal execution API |
|
|
525
|
+
| `runSync` | Sync terminal execution API |
|
|
526
|
+
| `retry` | Create an execution-scoped retry builder |
|
|
527
|
+
| `retryOptions` | Normalize retry policy input |
|
|
528
|
+
| `timeout` | Add a total execution timeout |
|
|
529
|
+
| `signal` | Add external cancellation to execution or root-level orchestration |
|
|
530
|
+
| `wrap` | Add top-level observational middleware |
|
|
531
|
+
| `all` | Run a fail-fast parallel named task graph |
|
|
532
|
+
| `allSettled` | Run a settled parallel named task graph |
|
|
533
|
+
| `flow` | Run an ordered workflow with explicit early exit |
|
|
534
|
+
| `gen` | Compose `run(...)` results through generators |
|
|
535
|
+
| `disposer` | Create an `AsyncDisposer` helper with `defer()`, `use()`, and `dispose()` |
|
|
540
536
|
|
|
541
537
|
### Errors
|
|
542
538
|
|
|
543
539
|
Exports from `tryharder/errors`:
|
|
544
540
|
|
|
545
|
-
| Export | Description
|
|
546
|
-
| --------------------- |
|
|
547
|
-
| `CancellationError` | Returned or thrown when execution is externally cancelled
|
|
548
|
-
| `TimeoutError` | Returned when timed execution expires
|
|
549
|
-
| `RetryExhaustedError` | Returned when retry
|
|
550
|
-
| `UnhandledException` | Returned when function-form execution throws
|
|
551
|
-
| `Panic` | Thrown for programmer errors and invalid API usage
|
|
541
|
+
| Export | Description |
|
|
542
|
+
| --------------------- | --------------------------------------------------------------------------------------------------------- |
|
|
543
|
+
| `CancellationError` | Returned or thrown when execution is externally cancelled |
|
|
544
|
+
| `TimeoutError` | Returned when timed execution expires |
|
|
545
|
+
| `RetryExhaustedError` | Returned when a retry policy gives up and no `catch` is provided; the last attempt's error is the `cause` |
|
|
546
|
+
| `UnhandledException` | Returned when function-form execution throws |
|
|
547
|
+
| `Panic` | Thrown for programmer errors and invalid API usage |
|
|
548
|
+
|
|
549
|
+
Each error class has a matching type guard: `isCancellationError`, `isTimeoutError`, `isRetryExhaustedError`, `isUnhandledException`, and `isPanic`. Prefer the guards over `instanceof` — they also match by `error.name`, so they keep working when two copies of `tryharder` end up in one dependency graph or when errors cross realm boundaries, where `instanceof` silently fails.
|
|
550
|
+
|
|
551
|
+
```ts
|
|
552
|
+
import { isTimeoutError } from "tryharder/errors"
|
|
553
|
+
|
|
554
|
+
const result = await try$.timeout(1_000).run(fetchUser)
|
|
555
|
+
|
|
556
|
+
if (isTimeoutError(result)) {
|
|
557
|
+
// handle the deadline here
|
|
558
|
+
}
|
|
559
|
+
```
|
|
552
560
|
|
|
553
561
|
### Types
|
|
554
562
|
|
|
@@ -557,7 +565,7 @@ Exports from `tryharder/types`:
|
|
|
557
565
|
| Export | Description |
|
|
558
566
|
| ------------------ | ---------------------------------------------------- |
|
|
559
567
|
| `AllSettledResult` | Settled result map returned by `allSettled(...)` |
|
|
560
|
-
| `AsyncDisposer` | Async cleanup helper returned by `
|
|
568
|
+
| `AsyncDisposer` | Async cleanup helper returned by `disposer()` |
|
|
561
569
|
| `SettledFulfilled` | Fulfilled branch of a settled task result |
|
|
562
570
|
| `SettledRejected` | Rejected branch of a settled task result |
|
|
563
571
|
| `SettledResult` | Union of fulfilled and rejected settled task results |
|
package/dist/errors.d.ts
CHANGED
|
@@ -23,4 +23,9 @@ declare class Panic extends Error {
|
|
|
23
23
|
message?: string;
|
|
24
24
|
});
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
declare function isCancellationError(error: unknown): error is CancellationError;
|
|
27
|
+
declare function isTimeoutError(error: unknown): error is TimeoutError;
|
|
28
|
+
declare function isRetryExhaustedError(error: unknown): error is RetryExhaustedError;
|
|
29
|
+
declare function isUnhandledException(error: unknown): error is UnhandledException;
|
|
30
|
+
declare function isPanic(error: unknown): error is Panic;
|
|
31
|
+
export { isUnhandledException, isTimeoutError, isRetryExhaustedError, isPanic, isCancellationError, UnhandledException, TimeoutError, RetryExhaustedError, PanicCode, Panic, CancellationError };
|
package/dist/errors.js
CHANGED
|
@@ -3,9 +3,19 @@ import {
|
|
|
3
3
|
Panic,
|
|
4
4
|
RetryExhaustedError,
|
|
5
5
|
TimeoutError,
|
|
6
|
-
UnhandledException
|
|
7
|
-
|
|
6
|
+
UnhandledException,
|
|
7
|
+
isCancellationError,
|
|
8
|
+
isPanic,
|
|
9
|
+
isRetryExhaustedError,
|
|
10
|
+
isTimeoutError,
|
|
11
|
+
isUnhandledException
|
|
12
|
+
} from "./shared/chunk-nw88v1ee.js";
|
|
8
13
|
export {
|
|
14
|
+
isUnhandledException,
|
|
15
|
+
isTimeoutError,
|
|
16
|
+
isRetryExhaustedError,
|
|
17
|
+
isPanic,
|
|
18
|
+
isCancellationError,
|
|
9
19
|
UnhandledException,
|
|
10
20
|
TimeoutError,
|
|
11
21
|
RetryExhaustedError,
|
|
@@ -13,5 +23,5 @@ export {
|
|
|
13
23
|
CancellationError
|
|
14
24
|
};
|
|
15
25
|
|
|
16
|
-
//# debugId=
|
|
17
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
26
|
+
//# debugId=796F554FE5FDACF264756E2164756E21
|
|
27
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFtdLAogICJzb3VyY2VzQ29udGVudCI6IFsKICBdLAogICJtYXBwaW5ncyI6ICIiLAogICJkZWJ1Z0lkIjogIjc5NkY1NTRGRTVGREFDRjI2NDc1NkUyMTY0NzU2RTIxIiwKICAibmFtZXMiOiBbXQp9
|
package/dist/index.d.ts
CHANGED
|
@@ -17,11 +17,20 @@ declare class UnhandledException extends Error {
|
|
|
17
17
|
constructor(message?: string, options?: ErrorOptions);
|
|
18
18
|
}
|
|
19
19
|
interface AsyncDisposer extends AsyncDisposable {
|
|
20
|
-
|
|
21
|
-
cleanup()
|
|
20
|
+
/**
|
|
21
|
+
* Registers a cleanup callback. Callbacks run in reverse registration order (LIFO) when the
|
|
22
|
+
* disposer is disposed.
|
|
23
|
+
*/
|
|
22
24
|
defer(fn: () => void | PromiseLike<void>): void;
|
|
25
|
+
/**
|
|
26
|
+
* Tracks a disposable resource and returns it.
|
|
27
|
+
*/
|
|
23
28
|
use<T extends AsyncDisposable | Disposable | null | undefined>(value: T): T;
|
|
24
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Runs all registered teardown in reverse registration order. Equivalent to leaving an `await
|
|
31
|
+
* using` scope.
|
|
32
|
+
*/
|
|
33
|
+
dispose(): Promise<void>;
|
|
25
34
|
}
|
|
26
35
|
type TaskRecord = Record<string, any>;
|
|
27
36
|
type TaskValidation<T extends TaskRecord> = { [K in keyof T] : T[K] extends (...args: any[]) => any ? T[K] : never };
|
|
@@ -131,6 +140,27 @@ type RetryPolicy = LinearBackoffRetryPolicy | ExponentialBackoffRetryPolicy | Co
|
|
|
131
140
|
* - `RetryPolicy`: detailed retry settings
|
|
132
141
|
*/
|
|
133
142
|
type RetryOptions = number | RetryPolicy;
|
|
143
|
+
declare const INVALID_RETRY_LIMIT: unique symbol;
|
|
144
|
+
type InvalidRetryLimit = {
|
|
145
|
+
readonly [INVALID_RETRY_LIMIT]: "retry() requires a positive integer limit";
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* Compile-time validation for literal retry limits. Rejects `0`, negative, and fractional literals;
|
|
149
|
+
* non-literal `number` values pass and are validated at runtime by {@link retryOptions} instead.
|
|
150
|
+
* (`Infinity`/`NaN` have no literal types, so they are runtime-only.)
|
|
151
|
+
*/
|
|
152
|
+
type ValidateRetryLimit<N extends number> = number extends N ? number : `${N}` extends `-${string}` | `${string}.${string}` ? InvalidRetryLimit : N extends 0 ? InvalidRetryLimit : number;
|
|
153
|
+
/**
|
|
154
|
+
* Compile-time validation for full {@link RetryOptions} values, including unions of number and
|
|
155
|
+
* policy forms. Distributes over union members so that mixed inputs like `flag ? 3 : { backoff:
|
|
156
|
+
* "constant", limit: 5 }` are accepted while any member carrying an invalid literal limit still
|
|
157
|
+
* fails to compile.
|
|
158
|
+
*/
|
|
159
|
+
type ValidateRetryOptions<P extends RetryOptions> = P extends number ? ValidateRetryLimit<P> : P extends {
|
|
160
|
+
limit: infer N extends number;
|
|
161
|
+
} ? {
|
|
162
|
+
limit: ValidateRetryLimit<N>;
|
|
163
|
+
} : never;
|
|
134
164
|
declare function retryOptions(policy: RetryOptions): RetryPolicy;
|
|
135
165
|
declare const FLOW_EXIT_BRAND: unique symbol;
|
|
136
166
|
type FlowExit<T> = {
|
|
@@ -153,6 +183,12 @@ interface RunAsyncOptions<
|
|
|
153
183
|
Ctx extends BaseTryCtx = BaseTryCtx
|
|
154
184
|
> {
|
|
155
185
|
try: RunTryFn<T, Ctx>;
|
|
186
|
+
/**
|
|
187
|
+
* Maps errors that originated inside `try` — thrown directly, or carried out of the retry loop as
|
|
188
|
+
* the last attempt's error once the retry policy gives up. Policy outcomes (timeout,
|
|
189
|
+
* cancellation) and defects (`Panic`) never pass through `catch`: they are reported directly,
|
|
190
|
+
* even when they fire while the handler is running.
|
|
191
|
+
*/
|
|
156
192
|
catch: RunCatchFn<E>;
|
|
157
193
|
}
|
|
158
194
|
type AsyncRunInput<
|
|
@@ -171,6 +207,12 @@ interface SyncRunOptions<
|
|
|
171
207
|
Ctx extends BaseTryCtx = BaseTryCtx
|
|
172
208
|
> {
|
|
173
209
|
try: SyncRunTryFn<T, Ctx>;
|
|
210
|
+
/**
|
|
211
|
+
* Maps errors that originated inside `try` — thrown directly, or carried out of the retry loop as
|
|
212
|
+
* the last attempt's error once the retry policy gives up. Policy outcomes (timeout,
|
|
213
|
+
* cancellation) and defects (`Panic`) never pass through `catch`: they are reported directly,
|
|
214
|
+
* even when they fire while the handler is running.
|
|
215
|
+
*/
|
|
174
216
|
catch: SyncRunCatchFn<E>;
|
|
175
217
|
}
|
|
176
218
|
type SyncRunInput<
|
|
@@ -204,7 +246,13 @@ interface BuilderConfig {
|
|
|
204
246
|
*/
|
|
205
247
|
wraps?: WrapFn[];
|
|
206
248
|
}
|
|
207
|
-
type ConfigRunErrors =
|
|
249
|
+
type ConfigRunErrors = TimeoutError | CancellationError;
|
|
250
|
+
/**
|
|
251
|
+
* The failure type for try functions without a catch handler. With retry configured, any give-up
|
|
252
|
+
* (limit exhausted or `shouldRetry` declining) is reported as {@link RetryExhaustedError} carrying
|
|
253
|
+
* the last attempt's error as `cause`; otherwise failures are wrapped in {@link UnhandledException}.
|
|
254
|
+
*/
|
|
255
|
+
type UnmappedError<HasRetry extends boolean> = HasRetry extends true ? RetryExhaustedError : UnhandledException;
|
|
208
256
|
type OrchestrationMethods = "all" | "allSettled" | "flow";
|
|
209
257
|
type SignalBuilderHiddenMethods<SupportsOrchestration extends boolean> = "runSync" | "wrap" | (SupportsOrchestration extends true ? never : OrchestrationMethods);
|
|
210
258
|
type ExecutionBuilderSurface<
|
|
@@ -229,17 +277,37 @@ declare class RunBuilder<
|
|
|
229
277
|
constructor(config?: BuilderConfig);
|
|
230
278
|
protected buildTimeoutConfig(ms: number): BuilderConfig;
|
|
231
279
|
protected buildSignalConfig(signal: AbortSignal): BuilderConfig;
|
|
232
|
-
retry(policy:
|
|
233
|
-
retry(policy:
|
|
280
|
+
retry<N extends number>(policy: N & ValidateRetryLimit<N>): ExecutionBuilderSurface<E, true>;
|
|
281
|
+
retry<N extends number>(policy: RetryPolicy & {
|
|
282
|
+
limit: N & ValidateRetryLimit<N>;
|
|
283
|
+
}): AsyncExecutionBuilderSurface<E, true>;
|
|
284
|
+
retry<const P extends RetryOptions>(policy: P & ValidateRetryOptions<P>): AsyncExecutionBuilderSurface<E, true>;
|
|
234
285
|
timeout(ms: number): AsyncExecutionBuilderSurface<E | TimeoutError, HasRetry>;
|
|
235
286
|
signal(signal: AbortSignal): SignalBuilderSurface<E | CancellationError, HasRetry, SupportsOrchestration>;
|
|
236
287
|
wrap(fn: WrapFn): RunBuilder<E, HasRetry, SupportsOrchestration>;
|
|
237
|
-
|
|
288
|
+
/**
|
|
289
|
+
* Executes an async unit of work.
|
|
290
|
+
*
|
|
291
|
+
* `catch` maps errors that originated inside `try` — thrown directly, or carried out of the retry
|
|
292
|
+
* loop as the last attempt's error once the retry policy gives up. Policy outcomes ({@link
|
|
293
|
+
* TimeoutError}, {@link CancellationError}) and defects (`Panic`) never pass through `catch`; they
|
|
294
|
+
* surface typed in the return union (or are thrown, for `Panic`).
|
|
295
|
+
*
|
|
296
|
+
* Without `catch`, unmapped failures are wrapped: {@link RetryExhaustedError} when a retry policy
|
|
297
|
+
* gave up, {@link UnhandledException} otherwise. The original error is available as `cause`.
|
|
298
|
+
*/
|
|
299
|
+
run<T>(tryFn: RunTryFn<T, TryCtxFor<HasRetry>>): Promise<T | UnmappedError<HasRetry> | E>;
|
|
238
300
|
run<
|
|
239
301
|
T,
|
|
240
302
|
C
|
|
241
303
|
>(options: AsyncRunInput<T, C, TryCtxFor<HasRetry>>): Promise<T | C | E>;
|
|
242
|
-
|
|
304
|
+
/**
|
|
305
|
+
* Executes a sync unit of work.
|
|
306
|
+
*
|
|
307
|
+
* Follows the same `catch` contract as {@link RunBuilder.run}: `catch` maps try-originated errors
|
|
308
|
+
* (including retry give-up); policy outcomes and defects never pass through it.
|
|
309
|
+
*/
|
|
310
|
+
runSync<T>(tryFn: SyncRunTryFn<T, TryCtxFor<HasRetry>>): T | UnmappedError<HasRetry> | E;
|
|
243
311
|
runSync<
|
|
244
312
|
T,
|
|
245
313
|
C
|
|
@@ -251,7 +319,11 @@ declare class RunBuilder<
|
|
|
251
319
|
allSettled<T extends TaskRecord>(tasks: T & TaskValidation<NoInfer<T>> & ThisType<InferredTaskContext<T>>): Promise<AllSettledResult<T>>;
|
|
252
320
|
flow<T extends TaskRecord>(tasks: T & ThisType<InferredFlowTaskContext<T>>): Promise<FlowResult<T>>;
|
|
253
321
|
}
|
|
254
|
-
|
|
322
|
+
/**
|
|
323
|
+
* Creates an {@link AsyncDisposer}: register cleanup with `defer(fn)` or `use(resource)`, then run
|
|
324
|
+
* teardown with `await d.dispose()` or by declaring the disposer with `await using`.
|
|
325
|
+
*/
|
|
326
|
+
declare function disposer(): AsyncDisposer;
|
|
255
327
|
type GenUnwrap<T> = Exclude<Awaited<T>, Error>;
|
|
256
328
|
type GenUse = <T>(value: T) => Generator<T, GenUnwrap<T>, GenUnwrap<T>>;
|
|
257
329
|
type GenErrors<TYield> = Extract<Awaited<TYield>, Error>;
|
|
@@ -276,4 +348,4 @@ declare const runSync2: RunBuilder["runSync"];
|
|
|
276
348
|
declare const signal: RunBuilder["signal"];
|
|
277
349
|
declare const timeout: RunBuilder["timeout"];
|
|
278
350
|
declare const wrap: RunBuilder["wrap"];
|
|
279
|
-
export { wrap, timeout, signal, runSync2 as runSync, run, retryOptions, retry, driveGen as gen, flow,
|
|
351
|
+
export { wrap, timeout, signal, runSync2 as runSync, run, retryOptions, retry, driveGen as gen, flow, disposer, allSettled2 as allSettled, all };
|