tryharder 0.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.
- package/LICENSE +21 -0
- package/README.md +468 -0
- package/dist/errors.d.ts +22 -0
- package/dist/errors.js +17 -0
- package/dist/index.d.ts +269 -0
- package/dist/index.js +1223 -0
- package/dist/shared/chunk-996eswzx.js +105 -0
- package/dist/types.d.ts +17 -0
- package/dist/types.js +3 -0
- package/package.json +71 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Adel Rodriguez
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h1 align="center">🔁 tryharder</h1>
|
|
3
|
+
|
|
4
|
+
<p align="center">
|
|
5
|
+
<strong>A better try/catch for TypeScript</strong>
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
<a href="https://www.npmjs.com/package/tryharder"><img src="https://img.shields.io/npm/v/tryharder" alt="npm version" /></a>
|
|
10
|
+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT" /></a>
|
|
11
|
+
</p>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
Run sync and async work with retries, timeouts, cancellation, typed failure mapping, and orchestration. Use `tryharder` when plain `try/catch` starts to sprawl and you want a small execution API that scales from single calls to parallel task maps and early-exit pipelines.
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import * as try$ from "tryharder"
|
|
18
|
+
|
|
19
|
+
class RequestFailedError extends Error {}
|
|
20
|
+
|
|
21
|
+
const result = await try$
|
|
22
|
+
.retry(3) // Retry up to 3 times
|
|
23
|
+
.timeout(5_000) // Timeout after 5 seconds
|
|
24
|
+
.run({
|
|
25
|
+
try: async () => {
|
|
26
|
+
const response = await fetch("https://example.com")
|
|
27
|
+
|
|
28
|
+
if (!response.ok) {
|
|
29
|
+
throw new Error(`request failed: ${response.status}`)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return "ok" as const
|
|
33
|
+
},
|
|
34
|
+
catch: () => new RequestFailedError("request failed"),
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
// result is "ok" | RequestFailedError | RetryExhaustedError | TimeoutError
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary>Table of Contents</summary>
|
|
42
|
+
|
|
43
|
+
- [Features](#features)
|
|
44
|
+
- [Installation](#installation)
|
|
45
|
+
- [Migration from hardtry](#migration-from-hardtry)
|
|
46
|
+
- [Core Concepts](#core-concepts)
|
|
47
|
+
- [Quick Start](#quick-start)
|
|
48
|
+
- [Usage](#usage)
|
|
49
|
+
- [run and runSync](#run-and-runsync)
|
|
50
|
+
- [retry, timeout, signal](#retry-timeout-signal)
|
|
51
|
+
- [wrap](#wrap)
|
|
52
|
+
- [all and allSettled](#all-and-allsettled)
|
|
53
|
+
- [flow and $exit](#flow-and-exit)
|
|
54
|
+
- [gen](#gen)
|
|
55
|
+
- [dispose](#dispose)
|
|
56
|
+
- [API Reference](#api-reference)
|
|
57
|
+
- [Common Recipes](#common-recipes)
|
|
58
|
+
- [When not to use tryharder](#when-not-to-use-tryharder)
|
|
59
|
+
- [Contributing](#contributing)
|
|
60
|
+
- [Acknowledgments](#acknowledgments)
|
|
61
|
+
- [License](#license)
|
|
62
|
+
|
|
63
|
+
</details>
|
|
64
|
+
|
|
65
|
+
## Features
|
|
66
|
+
|
|
67
|
+
- **Composable execution policies** - Chain `retry`, `timeout`, and `signal` around work that may fail or be cancelled.
|
|
68
|
+
- **Typed failure mapping** - Use object-form `run({ try, catch })` to map thrown errors into domain-specific results.
|
|
69
|
+
- **Sync and async entrypoints** - Use `runSync` for synchronous work and `run` for asynchronous work.
|
|
70
|
+
- **Task orchestration** - Coordinate named task maps with `all`, `allSettled`, and `flow`.
|
|
71
|
+
- **Early exit control** - Short-circuit pipelines with `this.$exit(...)` in `flow`.
|
|
72
|
+
- **Middleware-style wrapping** - Observe execution with top-level `wrap(...).wrap(...)` chains.
|
|
73
|
+
- **Generator composition** - Build linear workflows over `run(...)` results with `gen(...)`.
|
|
74
|
+
- **Resource cleanup** - Register cleanup with `dispose()` and `AsyncDisposableStack`.
|
|
75
|
+
- **No runtime dependencies** - The published package ships without runtime dependencies.
|
|
76
|
+
|
|
77
|
+
## Installation
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# bun
|
|
81
|
+
bun add tryharder
|
|
82
|
+
|
|
83
|
+
# npm
|
|
84
|
+
npm install tryharder
|
|
85
|
+
|
|
86
|
+
# yarn
|
|
87
|
+
yarn add tryharder
|
|
88
|
+
|
|
89
|
+
# pnpm
|
|
90
|
+
pnpm add tryharder
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Migration from hardtry
|
|
94
|
+
|
|
95
|
+
Replace import specifiers only:
|
|
96
|
+
|
|
97
|
+
- `hardtry` -> `tryharder`
|
|
98
|
+
- `hardtry/errors` -> `tryharder/errors`
|
|
99
|
+
- `hardtry/types` -> `tryharder/types`
|
|
100
|
+
|
|
101
|
+
You can keep the same namespace alias in your code:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
import * as try$ from "tryharder"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
No runtime API names changed.
|
|
108
|
+
|
|
109
|
+
## Core Concepts
|
|
110
|
+
|
|
111
|
+
| Term | Meaning |
|
|
112
|
+
| --------------------- | ------------------------------------------------------------------------- |
|
|
113
|
+
| `run` | Async entrypoint that returns a value, a mapped failure, or config error |
|
|
114
|
+
| `runSync` | Sync entrypoint for synchronous work only |
|
|
115
|
+
| `retry(limit)` | Retry policy where `limit` includes the first attempt |
|
|
116
|
+
| `timeout(ms)` | Total execution timeout across attempts, delays, and catch handling |
|
|
117
|
+
| `signal(abortSignal)` | External cancellation for `run` and, from the root builder, orchestration |
|
|
118
|
+
| `wrap(fn)` | Top-level middleware hook around terminal execution APIs |
|
|
119
|
+
| `all(tasks)` | Fail-fast parallel named tasks |
|
|
120
|
+
| `allSettled(tasks)` | Settled parallel named tasks |
|
|
121
|
+
| `flow(tasks)` | Ordered task orchestration with early exit |
|
|
122
|
+
| `$exit(value)` | Stop a `flow` early and return `value` |
|
|
123
|
+
|
|
124
|
+
Not sure if `tryharder` is a good fit for your project? See [When not to use tryharder](#when-not-to-use-tryharder).
|
|
125
|
+
|
|
126
|
+
## Quick Start
|
|
127
|
+
|
|
128
|
+
Use function form when you want thrown failures normalized to `UnhandledException`:
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import * as try$ from "tryharder"
|
|
132
|
+
|
|
133
|
+
const result = await try$.run(async () => {
|
|
134
|
+
return "ok" as const
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
// "ok" | UnhandledException
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Use object form when you want to map failures into domain results:
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
import * as try$ from "tryharder"
|
|
144
|
+
|
|
145
|
+
class ValidationError extends Error {}
|
|
146
|
+
|
|
147
|
+
const result = await try$.run({
|
|
148
|
+
try: async () => {
|
|
149
|
+
throw new Error("boom")
|
|
150
|
+
},
|
|
151
|
+
catch: () => new ValidationError("invalid input"),
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
// ValidationError
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
In a real application, you usually compose policies before the terminal call:
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
class UpstreamUnavailableError extends Error {}
|
|
161
|
+
|
|
162
|
+
const result = await try$
|
|
163
|
+
.retry({ backoff: "constant", delayMs: 100, limit: 3 })
|
|
164
|
+
.timeout(1_500)
|
|
165
|
+
.run({
|
|
166
|
+
try: async () => {
|
|
167
|
+
const response = await fetch("https://example.com/data")
|
|
168
|
+
|
|
169
|
+
if (!response.ok) {
|
|
170
|
+
throw new Error("upstream failed")
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return await response.json()
|
|
174
|
+
},
|
|
175
|
+
catch: () => new UpstreamUnavailableError("data service unavailable"),
|
|
176
|
+
})
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Usage
|
|
180
|
+
|
|
181
|
+
### run and runSync
|
|
182
|
+
|
|
183
|
+
Use function form when you want thrown failures wrapped as `UnhandledException`.
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
const syncValue = try$.runSync(() => 42)
|
|
187
|
+
|
|
188
|
+
const asyncValue = await try$.run(async () => {
|
|
189
|
+
return 42
|
|
190
|
+
})
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Use object form when you want to map failures yourself.
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
class InvalidInputError extends Error {}
|
|
197
|
+
class PermissionDeniedError extends Error {}
|
|
198
|
+
|
|
199
|
+
const result = try$.runSync({
|
|
200
|
+
try: () => {
|
|
201
|
+
throw new SyntaxError("bad input")
|
|
202
|
+
},
|
|
203
|
+
catch: (error) => {
|
|
204
|
+
if (error instanceof SyntaxError) {
|
|
205
|
+
return new InvalidInputError("invalid")
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return new PermissionDeniedError("denied")
|
|
209
|
+
},
|
|
210
|
+
})
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### retry, timeout, signal
|
|
214
|
+
|
|
215
|
+
Use modifiers to add retry, total timeout, and cancellation around `run(...)`. `signal(...)` can also be applied at the root builder before `all`, `allSettled`, or `flow`.
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
const controller = new AbortController()
|
|
219
|
+
|
|
220
|
+
const result = await try$
|
|
221
|
+
.retry({ backoff: "constant", delayMs: 50, limit: 3 })
|
|
222
|
+
.timeout(1_000)
|
|
223
|
+
.signal(controller.signal)
|
|
224
|
+
.run(async (ctx) => {
|
|
225
|
+
return `attempt-${ctx.retry.attempt}`
|
|
226
|
+
})
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
`timeout(ms)` measures total execution time, not just a single attempt.
|
|
230
|
+
|
|
231
|
+
### wrap
|
|
232
|
+
|
|
233
|
+
Use `wrap(...)` for observational middleware around terminal APIs. Wraps are top-level only and can be chained as `.wrap().wrap()`.
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
const result = await try$
|
|
237
|
+
.wrap((ctx, next) => {
|
|
238
|
+
console.log("starting attempt", ctx.retry.attempt)
|
|
239
|
+
return next()
|
|
240
|
+
})
|
|
241
|
+
.wrap((_ctx, next) => next())
|
|
242
|
+
.run(async () => "ok")
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
`wrap(...)` is not available after `retry(...)`, `timeout(...)`, or `signal(...)`.
|
|
246
|
+
|
|
247
|
+
### all and allSettled
|
|
248
|
+
|
|
249
|
+
Use `all(...)` for fail-fast task maps and `allSettled(...)` when you want every task result.
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
const values = await try$.all({
|
|
253
|
+
a() {
|
|
254
|
+
return 1
|
|
255
|
+
},
|
|
256
|
+
async b() {
|
|
257
|
+
const a = await this.$result.a
|
|
258
|
+
return a + 1
|
|
259
|
+
},
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
// { a: 1, b: 2 }
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
```ts
|
|
266
|
+
const settled = await try$.allSettled({
|
|
267
|
+
fail() {
|
|
268
|
+
throw new Error("boom")
|
|
269
|
+
},
|
|
270
|
+
ok() {
|
|
271
|
+
return 1
|
|
272
|
+
},
|
|
273
|
+
})
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### flow and $exit
|
|
277
|
+
|
|
278
|
+
Use `flow(...)` for dependent pipelines that may short-circuit early. At least one path must call `this.$exit(...)`.
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
const result = await try$.flow({
|
|
282
|
+
cache() {
|
|
283
|
+
const cached: string | null = "cached-value"
|
|
284
|
+
|
|
285
|
+
if (cached !== null) {
|
|
286
|
+
return this.$exit(cached)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return null
|
|
290
|
+
},
|
|
291
|
+
async api() {
|
|
292
|
+
return "api-value"
|
|
293
|
+
},
|
|
294
|
+
async transform() {
|
|
295
|
+
const value = await this.$result.api
|
|
296
|
+
return this.$exit(`${value}-transformed`)
|
|
297
|
+
},
|
|
298
|
+
})
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### gen
|
|
302
|
+
|
|
303
|
+
Use `gen(...)` when you want a more linear style over `run(...)` results.
|
|
304
|
+
|
|
305
|
+
```ts
|
|
306
|
+
const value = await try$.gen(function* (use) {
|
|
307
|
+
const a = yield* use(try$.run(() => 1))
|
|
308
|
+
const b = yield* use(try$.run(() => a + 1))
|
|
309
|
+
return b
|
|
310
|
+
})
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### dispose
|
|
314
|
+
|
|
315
|
+
Use `dispose()` to register cleanup for work that spans async boundaries.
|
|
316
|
+
|
|
317
|
+
```ts
|
|
318
|
+
await using disposer = try$.dispose()
|
|
319
|
+
|
|
320
|
+
disposer.defer(() => {
|
|
321
|
+
console.log("cleanup")
|
|
322
|
+
})
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
## API Reference
|
|
326
|
+
|
|
327
|
+
### Runtime
|
|
328
|
+
|
|
329
|
+
| Export | Description |
|
|
330
|
+
| -------------- | ------------------------------------------- |
|
|
331
|
+
| `run` | Async execution entrypoint |
|
|
332
|
+
| `runSync` | Sync execution entrypoint |
|
|
333
|
+
| `retry` | Create a retry policy builder |
|
|
334
|
+
| `retryOptions` | Normalize retry policy input |
|
|
335
|
+
| `timeout` | Add a total execution timeout |
|
|
336
|
+
| `signal` | Add external cancellation |
|
|
337
|
+
| `wrap` | Add top-level middleware hooks |
|
|
338
|
+
| `all` | Run fail-fast parallel named tasks |
|
|
339
|
+
| `allSettled` | Run settled parallel named tasks |
|
|
340
|
+
| `flow` | Run ordered tasks with early exit |
|
|
341
|
+
| `gen` | Compose `run(...)` calls through generators |
|
|
342
|
+
| `dispose` | Create an `AsyncDisposableStack` helper |
|
|
343
|
+
|
|
344
|
+
### Errors
|
|
345
|
+
|
|
346
|
+
Exports from `tryharder/errors`:
|
|
347
|
+
|
|
348
|
+
| Export | Description |
|
|
349
|
+
| --------------------- | --------------------------------------------------------- |
|
|
350
|
+
| `CancellationError` | Returned or thrown when execution is externally cancelled |
|
|
351
|
+
| `TimeoutError` | Returned when timed execution expires |
|
|
352
|
+
| `RetryExhaustedError` | Returned when retry attempts are exhausted |
|
|
353
|
+
| `UnhandledException` | Returned when function-form execution throws |
|
|
354
|
+
| `Panic` | Thrown for programmer errors and invalid API usage |
|
|
355
|
+
|
|
356
|
+
### Types
|
|
357
|
+
|
|
358
|
+
Exports from `tryharder/types`:
|
|
359
|
+
|
|
360
|
+
| Export | Description |
|
|
361
|
+
| ------------------ | ---------------------------------------------------- |
|
|
362
|
+
| `AllSettledResult` | Settled result map returned by `allSettled(...)` |
|
|
363
|
+
| `SettledFulfilled` | Fulfilled branch of a settled task result |
|
|
364
|
+
| `SettledRejected` | Rejected branch of a settled task result |
|
|
365
|
+
| `SettledResult` | Union of fulfilled and rejected settled task results |
|
|
366
|
+
| `FlowExit` | Exit marker type used by `flow(...)` |
|
|
367
|
+
|
|
368
|
+
```ts
|
|
369
|
+
import * as try$ from "tryharder"
|
|
370
|
+
import { Panic, TimeoutError, UnhandledException } from "tryharder/errors"
|
|
371
|
+
import type { FlowExit, SettledResult } from "tryharder/types"
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## Common Recipes
|
|
375
|
+
|
|
376
|
+
### Retry a flaky request with timeout
|
|
377
|
+
|
|
378
|
+
```ts
|
|
379
|
+
const result = await try$
|
|
380
|
+
.retry({ backoff: "constant", delayMs: 200, limit: 3 })
|
|
381
|
+
.timeout(2_000)
|
|
382
|
+
.run(async () => {
|
|
383
|
+
const response = await fetch("https://example.com")
|
|
384
|
+
return response.text()
|
|
385
|
+
})
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Map thrown exceptions into domain results
|
|
389
|
+
|
|
390
|
+
```ts
|
|
391
|
+
class RemoteServiceError extends Error {}
|
|
392
|
+
|
|
393
|
+
const result = await try$.run({
|
|
394
|
+
try: async () => {
|
|
395
|
+
throw new Error("boom")
|
|
396
|
+
},
|
|
397
|
+
catch: () => new RemoteServiceError("service failed"),
|
|
398
|
+
})
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Run dependent parallel tasks with all
|
|
402
|
+
|
|
403
|
+
```ts
|
|
404
|
+
const result = await try$.all({
|
|
405
|
+
async user() {
|
|
406
|
+
return { id: "1", name: "Ada" }
|
|
407
|
+
},
|
|
408
|
+
async profile() {
|
|
409
|
+
const user = await this.$result.user
|
|
410
|
+
return { userId: user.id, plan: "pro" as const }
|
|
411
|
+
},
|
|
412
|
+
})
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
### Short-circuit a pipeline with flow
|
|
416
|
+
|
|
417
|
+
```ts
|
|
418
|
+
const result = await try$.flow({
|
|
419
|
+
cache() {
|
|
420
|
+
return this.$exit("cached" as const)
|
|
421
|
+
},
|
|
422
|
+
async api() {
|
|
423
|
+
return "remote"
|
|
424
|
+
},
|
|
425
|
+
})
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
### Add per-task retry inside orchestration
|
|
429
|
+
|
|
430
|
+
`retry(...)` and `timeout(...)` apply to `run(...)` and `runSync(...)`, not directly to `all(...)` or `flow(...)`. When you need per-task policies, wrap leaf work in nested `run(...)` calls.
|
|
431
|
+
|
|
432
|
+
```ts
|
|
433
|
+
const result = await try$.flow({
|
|
434
|
+
async fetchUser() {
|
|
435
|
+
const user = await try$.retry(2).run(async () => {
|
|
436
|
+
const response = await fetch("https://example.com/user")
|
|
437
|
+
return await response.json()
|
|
438
|
+
})
|
|
439
|
+
|
|
440
|
+
return this.$exit(user)
|
|
441
|
+
},
|
|
442
|
+
})
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
## When not to use tryharder
|
|
446
|
+
|
|
447
|
+
- **Small scripts or one-off tasks** - Plain `try/catch` is often simpler when you do not need retries, cancellation, or orchestration.
|
|
448
|
+
- **You already use an effect system or result abstraction** - If your codebase already has a consistent execution model, adding `tryharder` may be redundant.
|
|
449
|
+
- **Your workflows are mostly straightforward Promise chains** - `all(...)` and `flow(...)` help when coordination matters; otherwise native composition may be clearer.
|
|
450
|
+
- **Your team prefers explicit `Result` values everywhere** - `tryharder` centers execution wrappers, not a dedicated result data type.
|
|
451
|
+
- **You do not want policy-driven execution behavior** - If retry and timeout semantics are unnecessary overhead, the abstraction may not pay for itself.
|
|
452
|
+
|
|
453
|
+
## Contributing
|
|
454
|
+
|
|
455
|
+
Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for development workflow, code quality requirements, testing expectations, and changeset guidance.
|
|
456
|
+
|
|
457
|
+
## Acknowledgments
|
|
458
|
+
|
|
459
|
+
- [`better-result`](https://github.com/dmmulroy/better-result) for typed result-oriented error handling in TypeScript.
|
|
460
|
+
- [`effect`](https://github.com/Effect-TS/effect) for structured, composable models of execution, failure, and concurrency.
|
|
461
|
+
- [`better-all`](https://github.com/shuding/better-all) for task orchestration patterns over object-shaped work graphs.
|
|
462
|
+
- [`errore`](https://errore.org/) for modeling errors as unions instead of tuples.
|
|
463
|
+
|
|
464
|
+
Made with [🥐 `pastry`](https://github.com/adelrodriguez/pastry)
|
|
465
|
+
|
|
466
|
+
## License
|
|
467
|
+
|
|
468
|
+
[MIT](LICENSE)
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
type PanicCode = "ALL_CATCH_HANDLER_REJECT" | "ALL_CATCH_HANDLER_THROW" | "FLOW_NO_EXIT" | "ORCHESTRATION_UNSUPPORTED_POLICY" | "RETRY_INVALID_LIMIT" | "RUN_CATCH_HANDLER_REJECT" | "RUN_CATCH_HANDLER_THROW" | "RUN_SYNC_ASYNC_RETRY_POLICY" | "RUN_SYNC_CATCH_HANDLER_THROW" | "RUN_SYNC_CATCH_PROMISE" | "RUN_SYNC_TRY_PROMISE" | "RUN_SYNC_WRAPPED_RESULT_PROMISE" | "TASK_INVALID_HANDLER" | "TASK_SELF_REFERENCE" | "TIMEOUT_INVALID_MS" | "TASK_UNKNOWN_REFERENCE" | "UNREACHABLE_RETRY_POLICY_BACKOFF";
|
|
2
|
+
/** @internal */
|
|
3
|
+
declare class ControlError extends Error {}
|
|
4
|
+
declare class CancellationError extends ControlError {
|
|
5
|
+
constructor(message?: string, options?: ErrorOptions);
|
|
6
|
+
}
|
|
7
|
+
declare class TimeoutError extends ControlError {
|
|
8
|
+
constructor(message?: string, options?: ErrorOptions);
|
|
9
|
+
}
|
|
10
|
+
declare class RetryExhaustedError extends Error {
|
|
11
|
+
constructor(message?: string, options?: ErrorOptions);
|
|
12
|
+
}
|
|
13
|
+
declare class UnhandledException extends Error {
|
|
14
|
+
constructor(message?: string, options?: ErrorOptions);
|
|
15
|
+
}
|
|
16
|
+
declare class Panic extends Error {
|
|
17
|
+
readonly code: PanicCode;
|
|
18
|
+
constructor(code: PanicCode, options?: ErrorOptions & {
|
|
19
|
+
message?: string;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export { UnhandledException, TimeoutError, RetryExhaustedError, PanicCode, Panic, CancellationError };
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CancellationError,
|
|
3
|
+
Panic,
|
|
4
|
+
RetryExhaustedError,
|
|
5
|
+
TimeoutError,
|
|
6
|
+
UnhandledException
|
|
7
|
+
} from "./shared/chunk-996eswzx.js";
|
|
8
|
+
export {
|
|
9
|
+
UnhandledException,
|
|
10
|
+
TimeoutError,
|
|
11
|
+
RetryExhaustedError,
|
|
12
|
+
Panic,
|
|
13
|
+
CancellationError
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
//# debugId=7909B944ED0605C464756E2164756E21
|
|
17
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFtdLAogICJzb3VyY2VzQ29udGVudCI6IFsKICBdLAogICJtYXBwaW5ncyI6ICIiLAogICJkZWJ1Z0lkIjogIjc5MDlCOTQ0RUQwNjA1QzQ2NDc1NkUyMTY0NzU2RTIxIiwKICAibmFtZXMiOiBbXQp9
|