@jagreehal/workflow 1.6.0 → 1.8.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/README.md +499 -19
- package/dist/core.cjs +1 -1
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +158 -19
- package/dist/core.d.ts +158 -19
- package/dist/core.js +1 -1
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +5 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +282 -17
- package/dist/index.d.ts +282 -17
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/visualize.cjs +1188 -6
- package/dist/visualize.cjs.map +1 -1
- package/dist/visualize.d.cts +467 -1
- package/dist/visualize.d.ts +467 -1
- package/dist/visualize.js +1188 -6
- package/dist/visualize.js.map +1 -1
- package/dist/workflow.cjs +1 -1
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +97 -15
- package/dist/workflow.d.ts +97 -15
- package/dist/workflow.js +1 -1
- package/dist/workflow.js.map +1 -1
- package/docs/advanced.md +425 -7
- package/docs/api.md +37 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -154,6 +154,102 @@ const result = await processPayment(async (step) => {
|
|
|
154
154
|
});
|
|
155
155
|
```
|
|
156
156
|
|
|
157
|
+
### 💾 Save & Resume (Persist Workflows Across Restarts)
|
|
158
|
+
|
|
159
|
+
Save workflow state to a database and resume later from exactly where you left off. Perfect for long-running workflows, crash recovery, or pausing for approvals.
|
|
160
|
+
|
|
161
|
+
**Step 1: Collect state during execution**
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
import { createWorkflow, createStepCollector } from '@jagreehal/workflow';
|
|
165
|
+
|
|
166
|
+
// Create a collector to automatically capture step results
|
|
167
|
+
const collector = createStepCollector();
|
|
168
|
+
|
|
169
|
+
const workflow = createWorkflow({ fetchUser, fetchPosts }, {
|
|
170
|
+
onEvent: collector.handleEvent, // Automatically collects step_complete events
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
await workflow(async (step) => {
|
|
174
|
+
// Only steps with keys are saved
|
|
175
|
+
const user = await step(() => fetchUser("1"), { key: "user:1" });
|
|
176
|
+
const posts = await step(() => fetchPosts(user.id), { key: `posts:${user.id}` });
|
|
177
|
+
return { user, posts };
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Get the collected state
|
|
181
|
+
const state = collector.getState(); // Returns ResumeState
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**Step 2: Save to database**
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
import { stringifyState, parseState } from '@jagreehal/workflow';
|
|
188
|
+
|
|
189
|
+
// Serialize to JSON
|
|
190
|
+
const json = stringifyState(state, { workflowId: "123", timestamp: Date.now() });
|
|
191
|
+
|
|
192
|
+
// Save to your database
|
|
193
|
+
await db.workflowStates.create({
|
|
194
|
+
id: workflowId,
|
|
195
|
+
state: json,
|
|
196
|
+
createdAt: new Date(),
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Step 3: Resume from saved state**
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
// Load from database
|
|
204
|
+
const saved = await db.workflowStates.findUnique({ where: { id: workflowId } });
|
|
205
|
+
const savedState = parseState(saved.state);
|
|
206
|
+
|
|
207
|
+
// Resume workflow - cached steps skip execution
|
|
208
|
+
const workflow = createWorkflow({ fetchUser, fetchPosts }, {
|
|
209
|
+
resumeState: savedState, // Pre-populates cache from saved state
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
await workflow(async (step) => {
|
|
213
|
+
const user = await step(() => fetchUser("1"), { key: "user:1" }); // ✅ Cache hit - no fetchUser call
|
|
214
|
+
const posts = await step(() => fetchPosts(user.id), { key: `posts:${user.id}` }); // ✅ Cache hit
|
|
215
|
+
return { user, posts };
|
|
216
|
+
});
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**With database adapter (Redis, DynamoDB, etc.)**
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
import { createStatePersistence } from '@jagreehal/workflow';
|
|
223
|
+
import { createClient } from 'redis';
|
|
224
|
+
|
|
225
|
+
const redis = createClient();
|
|
226
|
+
await redis.connect();
|
|
227
|
+
|
|
228
|
+
// Create persistence adapter
|
|
229
|
+
const persistence = createStatePersistence({
|
|
230
|
+
get: (key) => redis.get(key),
|
|
231
|
+
set: (key, value) => redis.set(key, value),
|
|
232
|
+
delete: (key) => redis.del(key).then(n => n > 0),
|
|
233
|
+
exists: (key) => redis.exists(key).then(n => n > 0),
|
|
234
|
+
keys: (pattern) => redis.keys(pattern),
|
|
235
|
+
}, 'workflow:state:');
|
|
236
|
+
|
|
237
|
+
// Save
|
|
238
|
+
await persistence.save(runId, state, { metadata: { userId: 'user-1' } });
|
|
239
|
+
|
|
240
|
+
// Load
|
|
241
|
+
const savedState = await persistence.load(runId);
|
|
242
|
+
|
|
243
|
+
// Resume
|
|
244
|
+
const workflow = createWorkflow(deps, { resumeState: savedState });
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**Key points:**
|
|
248
|
+
- Only steps with `key` options are saved (unkeyed steps execute fresh on resume)
|
|
249
|
+
- Error results are preserved with metadata for proper replay
|
|
250
|
+
- You can also pass an async function: `resumeState: async () => await loadFromDB()`
|
|
251
|
+
- Works seamlessly with HITL approvals and crash recovery
|
|
252
|
+
|
|
157
253
|
### 🧑💻 Human-in-the-Loop
|
|
158
254
|
|
|
159
255
|
Pause for manual approvals (large transfers, deployments, refunds) and resume exactly where you left off.
|
|
@@ -281,6 +377,82 @@ That's the foundation. Now let's build on it.
|
|
|
281
377
|
|
|
282
378
|
---
|
|
283
379
|
|
|
380
|
+
## Persistence Quickstart
|
|
381
|
+
|
|
382
|
+
Save workflow state to a database and resume later. Perfect for crash recovery, long-running workflows, or pausing for approvals.
|
|
383
|
+
|
|
384
|
+
### Basic Save & Resume
|
|
385
|
+
|
|
386
|
+
```typescript
|
|
387
|
+
import { createWorkflow, createStepCollector, stringifyState, parseState } from '@jagreehal/workflow';
|
|
388
|
+
|
|
389
|
+
// 1. Collect state during execution
|
|
390
|
+
const collector = createStepCollector();
|
|
391
|
+
const workflow = createWorkflow({ fetchUser, fetchPosts }, {
|
|
392
|
+
onEvent: collector.handleEvent,
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
await workflow(async (step) => {
|
|
396
|
+
const user = await step(() => fetchUser("1"), { key: "user:1" });
|
|
397
|
+
const posts = await step(() => fetchPosts(user.id), { key: `posts:${user.id}` });
|
|
398
|
+
return { user, posts };
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
// 2. Save to database
|
|
402
|
+
const state = collector.getState();
|
|
403
|
+
const json = stringifyState(state, { workflowId: "123" });
|
|
404
|
+
await db.workflowStates.create({ id: "123", state: json });
|
|
405
|
+
|
|
406
|
+
// 3. Resume later
|
|
407
|
+
const saved = await db.workflowStates.findUnique({ where: { id: "123" } });
|
|
408
|
+
const savedState = parseState(saved.state);
|
|
409
|
+
|
|
410
|
+
const resumed = createWorkflow({ fetchUser, fetchPosts }, {
|
|
411
|
+
resumeState: savedState,
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
// Cached steps skip execution automatically
|
|
415
|
+
await resumed(async (step) => {
|
|
416
|
+
const user = await step(() => fetchUser("1"), { key: "user:1" }); // ✅ Cache hit
|
|
417
|
+
const posts = await step(() => fetchPosts(user.id), { key: `posts:${user.id}` }); // ✅ Cache hit
|
|
418
|
+
return { user, posts };
|
|
419
|
+
});
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### With Database Adapter (Redis, DynamoDB, etc.)
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
import { createStatePersistence } from '@jagreehal/workflow';
|
|
426
|
+
import { createClient } from 'redis';
|
|
427
|
+
|
|
428
|
+
const redis = createClient();
|
|
429
|
+
await redis.connect();
|
|
430
|
+
|
|
431
|
+
// Create persistence adapter
|
|
432
|
+
const persistence = createStatePersistence({
|
|
433
|
+
get: (key) => redis.get(key),
|
|
434
|
+
set: (key, value) => redis.set(key, value),
|
|
435
|
+
delete: (key) => redis.del(key).then(n => n > 0),
|
|
436
|
+
exists: (key) => redis.exists(key).then(n => n > 0),
|
|
437
|
+
keys: (pattern) => redis.keys(pattern),
|
|
438
|
+
}, 'workflow:state:');
|
|
439
|
+
|
|
440
|
+
// Save
|
|
441
|
+
const collector = createStepCollector();
|
|
442
|
+
const workflow = createWorkflow(deps, { onEvent: collector.handleEvent });
|
|
443
|
+
await workflow(async (step) => { /* ... */ });
|
|
444
|
+
|
|
445
|
+
await persistence.save('run-123', collector.getState(), { userId: 'user-1' });
|
|
446
|
+
|
|
447
|
+
// Load and resume
|
|
448
|
+
const savedState = await persistence.load('run-123');
|
|
449
|
+
const resumed = createWorkflow(deps, { resumeState: savedState });
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
**See the [Save & Resume](#-save--resume-persist-workflows-across-restarts) section for more details.**
|
|
453
|
+
|
|
454
|
+
---
|
|
455
|
+
|
|
284
456
|
## Guided Tutorial
|
|
285
457
|
|
|
286
458
|
We'll take a single workflow through four stages - from basic to production-ready. Each stage builds on the last, so you'll see how features compose naturally.
|
|
@@ -356,29 +528,37 @@ Pause long-running workflows until an operator approves, then resume using persi
|
|
|
356
528
|
import {
|
|
357
529
|
createApprovalStep,
|
|
358
530
|
createWorkflow,
|
|
531
|
+
createStepCollector,
|
|
359
532
|
injectApproval,
|
|
360
533
|
isPendingApproval,
|
|
361
|
-
isStepComplete,
|
|
362
|
-
type ResumeStateEntry,
|
|
363
534
|
} from '@jagreehal/workflow';
|
|
364
535
|
|
|
365
|
-
|
|
536
|
+
// Use collector to automatically capture state
|
|
537
|
+
const collector = createStepCollector();
|
|
366
538
|
const requireApproval = createApprovalStep({
|
|
367
539
|
key: 'approval:deploy',
|
|
368
540
|
checkApproval: async () => ({ status: 'pending' }),
|
|
369
541
|
});
|
|
370
542
|
|
|
371
543
|
const gatedWorkflow = createWorkflow({ requireApproval }, {
|
|
372
|
-
onEvent:
|
|
373
|
-
if (isStepComplete(event)) savedSteps.set(event.stepKey, { result: event.result, meta: event.meta });
|
|
374
|
-
},
|
|
544
|
+
onEvent: collector.handleEvent, // Automatically collects step results
|
|
375
545
|
});
|
|
376
546
|
|
|
377
547
|
const result = await gatedWorkflow(async (step) => step(requireApproval, { key: 'approval:deploy' }));
|
|
378
548
|
|
|
379
549
|
if (!result.ok && isPendingApproval(result.error)) {
|
|
380
|
-
//
|
|
381
|
-
|
|
550
|
+
// Get collected state
|
|
551
|
+
const state = collector.getState();
|
|
552
|
+
|
|
553
|
+
// Later, when approval is granted, inject it and resume
|
|
554
|
+
const updatedState = injectApproval(state, {
|
|
555
|
+
stepKey: 'approval:deploy',
|
|
556
|
+
value: { approvedBy: 'ops' },
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
// Resume with approval injected
|
|
560
|
+
const resumed = createWorkflow({ requireApproval }, { resumeState: updatedState });
|
|
561
|
+
await resumed(async (step) => step(requireApproval, { key: 'approval:deploy' })); // Uses injected approval
|
|
382
562
|
}
|
|
383
563
|
```
|
|
384
564
|
|
|
@@ -400,6 +580,250 @@ if (!result.ok && isPendingApproval(result.error)) {
|
|
|
400
580
|
| **Events** | `onEvent` streams everything - timing, retries, failures - for visualization or logging |
|
|
401
581
|
| **Resume** | Save completed steps, pick up later (great for approvals or crashes) |
|
|
402
582
|
| **UnexpectedError** | Safety net for throws outside your declared union; use `strict` mode to force explicit handling |
|
|
583
|
+
| **TaggedError** | Factory for rich error types with exhaustive pattern matching |
|
|
584
|
+
|
|
585
|
+
## Tagged Errors: When String Literals Aren't Enough
|
|
586
|
+
|
|
587
|
+
String literal errors like `'NOT_FOUND'` are perfect for simple cases. But sometimes you need **rich error objects** with contextual data. That's where `TaggedError` shines.
|
|
588
|
+
|
|
589
|
+
### When to Use What
|
|
590
|
+
|
|
591
|
+
| Use Case | Recommendation |
|
|
592
|
+
|----------|----------------|
|
|
593
|
+
| Simple, distinct error states | String literals: `'NOT_FOUND' \| 'UNAUTHORIZED'` |
|
|
594
|
+
| Errors with contextual data | TaggedError: `NotFoundError { id, resource }` |
|
|
595
|
+
| Multiple error variants to handle | TaggedError with `match()` for exhaustive handling |
|
|
596
|
+
| API responses or user messages | TaggedError for structured error details |
|
|
597
|
+
|
|
598
|
+
### String Literals (Simple Cases)
|
|
599
|
+
|
|
600
|
+
For most workflows, string literals are cleaner and simpler:
|
|
601
|
+
|
|
602
|
+
```typescript
|
|
603
|
+
const fetchUser = async (id: string): AsyncResult<User, 'NOT_FOUND' | 'DB_ERROR'> =>
|
|
604
|
+
id ? ok({ id, name: 'Alice' }) : err('NOT_FOUND');
|
|
605
|
+
|
|
606
|
+
const result = await workflow(async (step) => {
|
|
607
|
+
const user = await step(fetchUser('123'));
|
|
608
|
+
return user;
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
if (!result.ok) {
|
|
612
|
+
switch (result.error) {
|
|
613
|
+
case 'NOT_FOUND': return res.status(404).send('User not found');
|
|
614
|
+
case 'DB_ERROR': return res.status(500).send('Database error');
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
### TaggedError (Rich Error Objects)
|
|
620
|
+
|
|
621
|
+
Use `TaggedError` when you need to carry additional context:
|
|
622
|
+
|
|
623
|
+
```typescript
|
|
624
|
+
import { TaggedError, ok, err, type AsyncResult } from '@jagreehal/workflow';
|
|
625
|
+
|
|
626
|
+
// Pattern 1: Props via generic (default message = tag name)
|
|
627
|
+
class NotFoundError extends TaggedError('NotFoundError')<{
|
|
628
|
+
resource: string;
|
|
629
|
+
id: string;
|
|
630
|
+
}> {}
|
|
631
|
+
|
|
632
|
+
// Pattern 2: Type-safe message (Props inferred from callback annotation)
|
|
633
|
+
class ValidationError extends TaggedError('ValidationError', {
|
|
634
|
+
message: (p: { field: string; reason: string }) => `Validation failed for ${p.field}: ${p.reason}`,
|
|
635
|
+
}) {}
|
|
636
|
+
|
|
637
|
+
class RateLimitError extends TaggedError('RateLimitError', {
|
|
638
|
+
message: (p: { retryAfter: number }) => `Rate limited. Retry after ${p.retryAfter}s`,
|
|
639
|
+
}) {}
|
|
640
|
+
|
|
641
|
+
// Runtime type checks work!
|
|
642
|
+
const error = new NotFoundError({ resource: 'User', id: '123' });
|
|
643
|
+
console.log(error instanceof TaggedError); // true
|
|
644
|
+
|
|
645
|
+
// Use in your functions
|
|
646
|
+
type UserError = NotFoundError | ValidationError | RateLimitError;
|
|
647
|
+
|
|
648
|
+
const fetchUser = async (id: string): AsyncResult<User, UserError> => {
|
|
649
|
+
if (!id) return err(new ValidationError({ field: 'id', reason: 'required' }));
|
|
650
|
+
if (id === 'limited') return err(new RateLimitError({ retryAfter: 60 }));
|
|
651
|
+
if (id === 'missing') return err(new NotFoundError({ resource: 'User', id }));
|
|
652
|
+
return ok({ id, name: 'Alice' });
|
|
653
|
+
};
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
### Exhaustive Matching with `TaggedError.match()`
|
|
657
|
+
|
|
658
|
+
TypeScript enforces you handle **every** error variant:
|
|
659
|
+
|
|
660
|
+
```typescript
|
|
661
|
+
const result = await workflow(async (step) => {
|
|
662
|
+
const user = await step(fetchUser('123'));
|
|
663
|
+
return user;
|
|
664
|
+
});
|
|
665
|
+
|
|
666
|
+
if (!result.ok) {
|
|
667
|
+
// TypeScript enforces all variants are handled
|
|
668
|
+
const response = TaggedError.match(result.error, {
|
|
669
|
+
NotFoundError: (e) => ({
|
|
670
|
+
status: 404,
|
|
671
|
+
body: { error: 'not_found', resource: e.resource, id: e.id },
|
|
672
|
+
}),
|
|
673
|
+
ValidationError: (e) => ({
|
|
674
|
+
status: 400,
|
|
675
|
+
body: { error: 'validation', field: e.field, reason: e.reason },
|
|
676
|
+
}),
|
|
677
|
+
RateLimitError: (e) => ({
|
|
678
|
+
status: 429,
|
|
679
|
+
body: { error: 'rate_limited', retryAfter: e.retryAfter },
|
|
680
|
+
}),
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
return res.status(response.status).json(response.body);
|
|
684
|
+
}
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
**Add a new error type? TypeScript will error until you handle it.** This catches bugs at compile time, not production.
|
|
688
|
+
|
|
689
|
+
### Partial Matching with Fallback
|
|
690
|
+
|
|
691
|
+
Handle specific errors and catch-all for the rest:
|
|
692
|
+
|
|
693
|
+
```typescript
|
|
694
|
+
const message = TaggedError.matchPartial(
|
|
695
|
+
result.error,
|
|
696
|
+
{
|
|
697
|
+
RateLimitError: (e) => `Please wait ${e.retryAfter} seconds`,
|
|
698
|
+
},
|
|
699
|
+
(e) => `Something went wrong: ${e.message}` // Fallback for other errors
|
|
700
|
+
);
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
### Real-World Example: Payment Errors
|
|
704
|
+
|
|
705
|
+
```typescript
|
|
706
|
+
// Type-safe message with Props inferred from callback annotation
|
|
707
|
+
class PaymentDeclinedError extends TaggedError('PaymentDeclinedError', {
|
|
708
|
+
message: (p: {
|
|
709
|
+
code: string;
|
|
710
|
+
declineReason: 'insufficient_funds' | 'card_expired' | 'fraud_suspected';
|
|
711
|
+
}) => `Payment declined: ${p.declineReason}`,
|
|
712
|
+
}) {}
|
|
713
|
+
|
|
714
|
+
class PaymentProviderError extends TaggedError('PaymentProviderError', {
|
|
715
|
+
message: (p: { provider: string; statusCode: number }) => `${p.provider} returned ${p.statusCode}`,
|
|
716
|
+
}) {}
|
|
717
|
+
|
|
718
|
+
type PaymentError = PaymentDeclinedError | PaymentProviderError;
|
|
719
|
+
|
|
720
|
+
// In your workflow
|
|
721
|
+
if (!result.ok) {
|
|
722
|
+
TaggedError.match(result.error, {
|
|
723
|
+
PaymentDeclinedError: (e) => {
|
|
724
|
+
switch (e.declineReason) {
|
|
725
|
+
case 'insufficient_funds': notifyUser('Please use a different card');
|
|
726
|
+
case 'card_expired': notifyUser('Your card has expired');
|
|
727
|
+
case 'fraud_suspected': alertFraudTeam(e);
|
|
728
|
+
}
|
|
729
|
+
},
|
|
730
|
+
PaymentProviderError: (e) => {
|
|
731
|
+
logToDatadog({ provider: e.provider, status: e.statusCode });
|
|
732
|
+
retryWithBackup(e.provider);
|
|
733
|
+
},
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
### Type Helpers
|
|
739
|
+
|
|
740
|
+
```typescript
|
|
741
|
+
import { type TagOf, type ErrorByTag } from '@jagreehal/workflow';
|
|
742
|
+
|
|
743
|
+
type PaymentError = PaymentDeclinedError | PaymentProviderError;
|
|
744
|
+
|
|
745
|
+
// Extract the tag literal type
|
|
746
|
+
type Tags = TagOf<PaymentError>; // 'PaymentDeclinedError' | 'PaymentProviderError'
|
|
747
|
+
|
|
748
|
+
// Extract a specific variant from the union
|
|
749
|
+
type Declined = ErrorByTag<PaymentError, 'PaymentDeclinedError'>; // PaymentDeclinedError
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
### Reserved Keys & Cause Handling
|
|
753
|
+
|
|
754
|
+
**Reserved property names** are stripped from props to preserve Error semantics:
|
|
755
|
+
|
|
756
|
+
| Key | Reason |
|
|
757
|
+
|-----|--------|
|
|
758
|
+
| `_tag` | Discriminant for pattern matching (cannot be forged) |
|
|
759
|
+
| `name` | Error.name (shown in stack traces/logs) |
|
|
760
|
+
| `message` | Error.message (shown in logs/telemetry) |
|
|
761
|
+
| `stack` | Error.stack (the stack trace) |
|
|
762
|
+
|
|
763
|
+
```typescript
|
|
764
|
+
// These reserved keys are silently stripped - use different names!
|
|
765
|
+
class BadExample extends TaggedError('BadExample')<{
|
|
766
|
+
message: string; // ❌ Won't work - use 'details' or 'description' instead
|
|
767
|
+
id: string;
|
|
768
|
+
}> {}
|
|
769
|
+
|
|
770
|
+
// Better approach:
|
|
771
|
+
class GoodExample extends TaggedError('GoodExample')<{
|
|
772
|
+
details: string; // ✅ Custom prop name
|
|
773
|
+
id: string;
|
|
774
|
+
}> {}
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
**The `cause` property** is special - it can be used as a user prop for domain data:
|
|
778
|
+
|
|
779
|
+
```typescript
|
|
780
|
+
// cause as domain data (e.g., structured validation errors)
|
|
781
|
+
class ValidationError extends TaggedError('ValidationError')<{
|
|
782
|
+
cause: { field: string; reason: string }; // ✅ Allowed as user prop
|
|
783
|
+
}> {}
|
|
784
|
+
|
|
785
|
+
const error = new ValidationError({
|
|
786
|
+
cause: { field: 'email', reason: 'invalid format' },
|
|
787
|
+
});
|
|
788
|
+
console.log(error.cause); // { field: 'email', reason: 'invalid format' }
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
**Conflict detection**: You cannot provide `cause` in both props AND ErrorOptions:
|
|
792
|
+
|
|
793
|
+
```typescript
|
|
794
|
+
// This throws TypeError at runtime!
|
|
795
|
+
const error = new ValidationError(
|
|
796
|
+
{ cause: { field: 'email', reason: 'invalid' } }, // cause in props
|
|
797
|
+
{ cause: new Error('original') } // cause in options
|
|
798
|
+
);
|
|
799
|
+
// TypeError: cannot provide 'cause' in props when also setting ErrorOptions.cause
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
Use ErrorOptions.cause for error chaining (linking to the original error):
|
|
803
|
+
|
|
804
|
+
```typescript
|
|
805
|
+
class NetworkError extends TaggedError('NetworkError')<{
|
|
806
|
+
url: string;
|
|
807
|
+
statusCode: number;
|
|
808
|
+
}> {}
|
|
809
|
+
|
|
810
|
+
try {
|
|
811
|
+
await fetch('/api');
|
|
812
|
+
} catch (original) {
|
|
813
|
+
// Chain to original error via ErrorOptions (not props)
|
|
814
|
+
throw new NetworkError(
|
|
815
|
+
{ url: '/api', statusCode: 500 },
|
|
816
|
+
{ cause: original } // ✅ Error chaining
|
|
817
|
+
);
|
|
818
|
+
}
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
### Summary
|
|
822
|
+
|
|
823
|
+
- **String literals**: Simple, great for distinct states without extra data
|
|
824
|
+
- **TaggedError**: Rich errors with context, exhaustive matching, proper stack traces
|
|
825
|
+
- **`match()`**: Forces you to handle every variant (compile-time safety)
|
|
826
|
+
- **`matchPartial()`**: Handle some variants with a catch-all fallback
|
|
403
827
|
|
|
404
828
|
## Recipes & Patterns
|
|
405
829
|
|
|
@@ -547,15 +971,24 @@ const result = await validateAndCheckout(async (step) => {
|
|
|
547
971
|
- **State save & resume** – Persist step completions and resume later.
|
|
548
972
|
|
|
549
973
|
```typescript
|
|
550
|
-
import { createWorkflow,
|
|
974
|
+
import { createWorkflow, createStepCollector } from '@jagreehal/workflow';
|
|
551
975
|
|
|
552
|
-
|
|
976
|
+
// Collect state during execution
|
|
977
|
+
const collector = createStepCollector();
|
|
553
978
|
const workflow = createWorkflow(deps, {
|
|
554
|
-
onEvent:
|
|
555
|
-
if (isStepComplete(event)) savedSteps.set(event.stepKey, { result: event.result, meta: event.meta });
|
|
556
|
-
},
|
|
979
|
+
onEvent: collector.handleEvent, // Automatically collects step_complete events
|
|
557
980
|
});
|
|
558
|
-
|
|
981
|
+
|
|
982
|
+
await workflow(async (step) => {
|
|
983
|
+
const user = await step(() => fetchUser("1"), { key: "user:1" });
|
|
984
|
+
return user;
|
|
985
|
+
});
|
|
986
|
+
|
|
987
|
+
// Get collected state
|
|
988
|
+
const state = collector.getState();
|
|
989
|
+
|
|
990
|
+
// Resume later
|
|
991
|
+
const resumed = createWorkflow(deps, { resumeState: state });
|
|
559
992
|
```
|
|
560
993
|
|
|
561
994
|
- **Human-in-the-loop approvals** – Pause a workflow until someone approves.
|
|
@@ -605,16 +1038,25 @@ const result = await validateAndCheckout(async (step) => {
|
|
|
605
1038
|
const data = map(result, ([user, posts]) => ({ user, posts }));
|
|
606
1039
|
```
|
|
607
1040
|
|
|
608
|
-
## Real-World Example: Safe Payment Retries
|
|
1041
|
+
## Real-World Example: Safe Payment Retries with Persistence
|
|
609
1042
|
|
|
610
1043
|
The scariest failure mode in payments: **charge succeeded, but persistence failed**. If you retry naively, you charge the customer twice.
|
|
611
1044
|
|
|
612
|
-
Step keys solve this.
|
|
1045
|
+
Step keys + persistence solve this. Save state to a database, and if the workflow crashes, resume from the last successful step:
|
|
613
1046
|
|
|
614
1047
|
```typescript
|
|
1048
|
+
import { createWorkflow, createStepCollector, stringifyState, parseState } from '@jagreehal/workflow';
|
|
1049
|
+
|
|
615
1050
|
const processPayment = createWorkflow({ validateCard, chargeProvider, persistResult });
|
|
616
1051
|
|
|
617
|
-
|
|
1052
|
+
// Collect state for persistence
|
|
1053
|
+
const collector = createStepCollector();
|
|
1054
|
+
const workflow = createWorkflow(
|
|
1055
|
+
{ validateCard, chargeProvider, persistResult },
|
|
1056
|
+
{ onEvent: collector.handleEvent }
|
|
1057
|
+
);
|
|
1058
|
+
|
|
1059
|
+
const result = await workflow(async (step) => {
|
|
618
1060
|
const card = await step(() => validateCard(input), { key: 'validate' });
|
|
619
1061
|
|
|
620
1062
|
// This is the dangerous step. Once it succeeds, never repeat it:
|
|
@@ -622,15 +1064,53 @@ const result = await processPayment(async (step) => {
|
|
|
622
1064
|
key: `charge:${input.idempotencyKey}`,
|
|
623
1065
|
});
|
|
624
1066
|
|
|
625
|
-
// If THIS fails (DB down),
|
|
1067
|
+
// If THIS fails (DB down), save state and rerun later.
|
|
626
1068
|
// The charge step is cached - it won't execute again.
|
|
627
1069
|
await step(() => persistResult(charge), { key: `persist:${charge.id}` });
|
|
628
1070
|
|
|
629
1071
|
return { paymentId: charge.id };
|
|
630
1072
|
});
|
|
1073
|
+
|
|
1074
|
+
// Save state after each run (or on crash)
|
|
1075
|
+
if (result.ok) {
|
|
1076
|
+
const state = collector.getState();
|
|
1077
|
+
const json = stringifyState(state, { orderId: input.orderId });
|
|
1078
|
+
await db.workflowStates.upsert({
|
|
1079
|
+
where: { idempotencyKey: input.idempotencyKey },
|
|
1080
|
+
update: { state: json, updatedAt: new Date() },
|
|
1081
|
+
create: { idempotencyKey: input.idempotencyKey, state: json },
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
```
|
|
1085
|
+
|
|
1086
|
+
**Crash recovery:** If the workflow crashes after charging but before persisting:
|
|
1087
|
+
|
|
1088
|
+
```typescript
|
|
1089
|
+
// On restart, load saved state
|
|
1090
|
+
const saved = await db.workflowStates.findUnique({
|
|
1091
|
+
where: { idempotencyKey: input.idempotencyKey },
|
|
1092
|
+
});
|
|
1093
|
+
|
|
1094
|
+
if (saved) {
|
|
1095
|
+
const savedState = parseState(saved.state);
|
|
1096
|
+
const workflow = createWorkflow(
|
|
1097
|
+
{ validateCard, chargeProvider, persistResult },
|
|
1098
|
+
{ resumeState: savedState }
|
|
1099
|
+
);
|
|
1100
|
+
|
|
1101
|
+
// Resume - charge step uses cached result, no double-billing!
|
|
1102
|
+
const result = await workflow(async (step) => {
|
|
1103
|
+
const card = await step(() => validateCard(input), { key: 'validate' }); // Cache hit
|
|
1104
|
+
const charge = await step(() => chargeProvider(card), {
|
|
1105
|
+
key: `charge:${input.idempotencyKey}`,
|
|
1106
|
+
}); // Cache hit - returns previous charge result
|
|
1107
|
+
await step(() => persistResult(charge), { key: `persist:${charge.id}` }); // Executes fresh
|
|
1108
|
+
return { paymentId: charge.id };
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
631
1111
|
```
|
|
632
1112
|
|
|
633
|
-
Crash after charging but before persisting?
|
|
1113
|
+
Crash after charging but before persisting? Resume the workflow. The charge step returns its cached result. No double-billing.
|
|
634
1114
|
|
|
635
1115
|
## Is This Library Right for You?
|
|
636
1116
|
|
package/dist/core.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var Y=Object.defineProperty;var pe=Object.getOwnPropertyDescriptor;var le=Object.getOwnPropertyNames;var ce=Object.prototype.hasOwnProperty;var Ee=(e,t)=>{for(var n in t)Y(e,n,{get:t[n],enumerable:!0})},ye=(e,t,n,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let l of le(t))!ce.call(e,l)&&l!==n&&Y(e,l,{get:()=>t[l],enumerable:!(s=pe(t,l))||s.enumerable});return e};var me=e=>ye(Y({},"__esModule",{value:!0}),e);var $e={};Ee($e,{EARLY_EXIT_SYMBOL:()=>G,STEP_TIMEOUT_MARKER:()=>O,UnwrapError:()=>N,all:()=>Le,allAsync:()=>We,allSettled:()=>Xe,allSettledAsync:()=>Je,andThen:()=>Me,any:()=>Be,anyAsync:()=>qe,bimap:()=>Ke,createEarlyExit:()=>ne,err:()=>T,from:()=>ge,fromNullable:()=>ve,fromPromise:()=>Ae,getStepTimeoutMeta:()=>te,isEarlyExit:()=>re,isErr:()=>Te,isOk:()=>we,isStepTimeoutError:()=>J,isUnexpectedError:()=>ee,map:()=>be,mapError:()=>he,mapErrorTry:()=>De,mapTry:()=>Ue,match:()=>_e,ok:()=>S,orElse:()=>Fe,orElseAsync:()=>je,partition:()=>Ye,recover:()=>Ne,recoverAsync:()=>Ve,run:()=>$,tap:()=>Ie,tapError:()=>Oe,tryAsync:()=>Pe,unwrap:()=>Ce,unwrapOr:()=>xe,unwrapOrElse:()=>Se});module.exports=me($e);var S=e=>({ok:!0,value:e}),T=(e,t)=>({ok:!1,error:e,...t?.cause!==void 0?{cause:t.cause}:{}}),we=e=>e.ok,Te=e=>!e.ok,ee=e=>typeof e=="object"&&e!==null&&e.type==="UNEXPECTED_ERROR",O=Symbol.for("step_timeout_marker");function J(e){return typeof e!="object"||e===null?!1:e.type==="STEP_TIMEOUT"?!0:O in e}function te(e){if(!(typeof e!="object"||e===null)){if(e.type==="STEP_TIMEOUT"){let t=e;return{timeoutMs:t.timeoutMs,stepName:t.stepName,stepKey:t.stepKey,attempt:t.attempt}}if(O in e)return e[O]}}var G=Symbol("early-exit");function ne(e,t){return{[G]:!0,error:e,meta:t}}function re(e){return typeof e=="object"&&e!==null&&e[G]===!0}var oe=Symbol("mapper-exception");function ke(e){return{[oe]:!0,thrown:e}}function de(e){return typeof e=="object"&&e!==null&&e[oe]===!0}function fe(e){return typeof e=="string"?{name:e}:e??{}}function B(e,t){let{backoff:n,initialDelay:s,maxDelay:l,jitter:A}=t,k;switch(n){case"fixed":k=s;break;case"linear":k=s*e;break;case"exponential":k=s*Math.pow(2,e-1);break}if(k=Math.min(k,l),A){let o=k*.25*Math.random();k=k+o}return Math.floor(k)}function q(e){return new Promise(t=>setTimeout(t,e))}var Z=Symbol("timeout");async function Re(e,t,n){let s=new AbortController,l=t.error??{type:"STEP_TIMEOUT",stepName:n.name,stepKey:n.key,timeoutMs:t.ms,attempt:n.attempt},A,k=new Promise((h,x)=>{A=setTimeout(()=>{s.abort(),x({[Z]:!0,error:l})},t.ms)}),o;t.signal?o=Promise.resolve(e(s.signal)):o=Promise.resolve(e());try{return await Promise.race([o,k])}catch(h){if(typeof h=="object"&&h!==null&&h[Z]===!0){let x=h.error;if(typeof x=="object"&&x!==null&&x.type!=="STEP_TIMEOUT"){let K={timeoutMs:t.ms,stepName:n.name,stepKey:n.key,attempt:n.attempt};O in x?x[O]=K:Object.defineProperty(x,O,{value:K,enumerable:!1,writable:!0,configurable:!1})}throw x}throw h}finally{clearTimeout(A)}}var D={backoff:"exponential",initialDelay:100,maxDelay:3e4,jitter:!0,retryOn:()=>!0,onRetry:()=>{}};async function $(e,t){let{onError:n,onEvent:s,catchUnexpected:l,workflowId:A,context:k}=t&&typeof t=="object"?t:{},o=A??crypto.randomUUID(),h=!n&&!l,x=[],K=0,V=r=>r??`step_${++K}`,c=r=>{if(r.type==="step_success"){let b=r.stepId;for(let v=x.length-1;v>=0;v--){let w=x[v];if(w.type==="race"&&!w.winnerId){w.winnerId=b;break}}}s?.(r,k)},M=ne,H=r=>re(r),L=(r,b)=>h?b?.origin==="result"?{type:"UNEXPECTED_ERROR",cause:{type:"STEP_FAILURE",origin:"result",error:r,...b.resultCause!==void 0?{cause:b.resultCause}:{}}}:b?.origin==="throw"?{type:"UNEXPECTED_ERROR",cause:{type:"STEP_FAILURE",origin:"throw",error:r,thrown:b.thrown}}:{type:"UNEXPECTED_ERROR",cause:{type:"STEP_FAILURE",origin:"result",error:r}}:r,se=r=>r.origin==="result"?r.resultCause:r.thrown,ue=r=>({type:"UNEXPECTED_ERROR",cause:r.meta.origin==="result"?{type:"STEP_FAILURE",origin:"result",error:r.error,...r.meta.resultCause!==void 0?{cause:r.meta.resultCause}:{}}:{type:"STEP_FAILURE",origin:"throw",error:r.error,thrown:r.meta.thrown}});try{let r=(w,i)=>(async()=>{let m=fe(i),{name:u,key:a,retry:d,timeout:E}=m,p=V(a),f=s,R=f?performance.now():0;if(!(typeof w=="function")){if(d&&d.attempts>1)throw new Error("step: retry options require a function operation. Direct Promise/Result values cannot be re-executed on retry. Wrap your operation in a function: step(() => yourOperation, { retry: {...} })");if(E)throw new Error("step: timeout options require a function operation. Direct Promise/Result values cannot be wrapped with timeout after they've started. Wrap your operation in a function: step(() => yourOperation, { timeout: {...} })")}let g={attempts:Math.max(1,d?.attempts??1),backoff:d?.backoff??D.backoff,initialDelay:d?.initialDelay??D.initialDelay,maxDelay:d?.maxDelay??D.maxDelay,jitter:d?.jitter??D.jitter,retryOn:d?.retryOn??D.retryOn,onRetry:d?.onRetry??D.onRetry};s&&c({type:"step_start",workflowId:o,stepId:p,stepKey:a,name:u,ts:Date.now()});let z;for(let C=1;C<=g.attempts;C++){let ie=f?performance.now():0;try{let y;if(typeof w=="function"?E?y=await Re(w,E,{name:u,key:a,attempt:C}):y=await w():y=await w,y.ok){let _=performance.now()-R;return c({type:"step_success",workflowId:o,stepId:p,stepKey:a,name:u,ts:Date.now(),durationMs:_}),a&&c({type:"step_complete",workflowId:o,stepKey:a,name:u,ts:Date.now(),durationMs:_,result:y}),y.value}if(z=y,C<g.attempts&&g.retryOn(y.error,C)){let _=B(C,g);c({type:"step_retry",workflowId:o,stepId:p,stepKey:a,name:u,ts:Date.now(),attempt:C+1,maxAttempts:g.attempts,delayMs:_,error:y.error}),g.onRetry(y.error,C,_),await q(_);continue}g.attempts>1&&c({type:"step_retries_exhausted",workflowId:o,stepId:p,stepKey:a,name:u,ts:Date.now(),durationMs:performance.now()-R,attempts:C,lastError:y.error});break}catch(y){let _=performance.now()-ie;if(H(y))throw c({type:"step_aborted",workflowId:o,stepId:p,stepKey:a,name:u,ts:Date.now(),durationMs:_}),y;if(J(y)){let P=te(y),W=E?.ms??P?.timeoutMs??0;if(c({type:"step_timeout",workflowId:o,stepId:p,stepKey:a,name:u,ts:Date.now(),timeoutMs:W,attempt:C}),C<g.attempts&&g.retryOn(y,C)){let X=B(C,g);c({type:"step_retry",workflowId:o,stepId:p,stepKey:a,name:u,ts:Date.now(),attempt:C+1,maxAttempts:g.attempts,delayMs:X,error:y}),g.onRetry(y,C,X),await q(X);continue}g.attempts>1&&c({type:"step_retries_exhausted",workflowId:o,stepId:p,stepKey:a,name:u,ts:Date.now(),durationMs:performance.now()-R,attempts:C,lastError:y})}if(C<g.attempts&&g.retryOn(y,C)){let P=B(C,g);c({type:"step_retry",workflowId:o,stepId:p,stepKey:a,name:u,ts:Date.now(),attempt:C+1,maxAttempts:g.attempts,delayMs:P,error:y}),g.onRetry(y,C,P),await q(P);continue}g.attempts>1&&!J(y)&&c({type:"step_retries_exhausted",workflowId:o,stepId:p,stepKey:a,name:u,ts:Date.now(),durationMs:performance.now()-R,attempts:C,lastError:y});let j=performance.now()-R;if(l){let P;try{P=l(y)}catch(W){throw ke(W)}throw c({type:"step_error",workflowId:o,stepId:p,stepKey:a,name:u,ts:Date.now(),durationMs:j,error:P}),a&&c({type:"step_complete",workflowId:o,stepKey:a,name:u,ts:Date.now(),durationMs:j,result:T(P,{cause:y}),meta:{origin:"throw",thrown:y}}),n?.(P,u),M(P,{origin:"throw",thrown:y})}else{let P={type:"UNEXPECTED_ERROR",cause:{type:"UNCAUGHT_EXCEPTION",thrown:y}};throw c({type:"step_error",workflowId:o,stepId:p,stepKey:a,name:u,ts:Date.now(),durationMs:j,error:P}),a&&c({type:"step_complete",workflowId:o,stepKey:a,name:u,ts:Date.now(),durationMs:j,result:T(P,{cause:y}),meta:{origin:"throw",thrown:y}}),y}}}let I=z,Q=performance.now()-R,ae=L(I.error,{origin:"result",resultCause:I.cause});throw c({type:"step_error",workflowId:o,stepId:p,stepKey:a,name:u,ts:Date.now(),durationMs:Q,error:ae}),a&&c({type:"step_complete",workflowId:o,stepKey:a,name:u,ts:Date.now(),durationMs:Q,result:I,meta:{origin:"result",resultCause:I.cause}}),n?.(I.error,u),M(I.error,{origin:"result",resultCause:I.cause})})();r.try=(w,i)=>{let m=i.name,u=i.key,a=V(u),d="error"in i?()=>i.error:i.onError,E=s;return(async()=>{let p=E?performance.now():0;s&&c({type:"step_start",workflowId:o,stepId:a,stepKey:u,name:m,ts:Date.now()});try{let f=await w(),R=performance.now()-p;return c({type:"step_success",workflowId:o,stepId:a,stepKey:u,name:m,ts:Date.now(),durationMs:R}),u&&c({type:"step_complete",workflowId:o,stepKey:u,name:m,ts:Date.now(),durationMs:R,result:S(f)}),f}catch(f){let R=d(f),U=performance.now()-p,F=L(R,{origin:"throw",thrown:f});throw c({type:"step_error",workflowId:o,stepId:a,stepKey:u,name:m,ts:Date.now(),durationMs:U,error:F}),u&&c({type:"step_complete",workflowId:o,stepKey:u,name:m,ts:Date.now(),durationMs:U,result:T(R,{cause:f}),meta:{origin:"throw",thrown:f}}),n?.(R,m),M(R,{origin:"throw",thrown:f})}})()},r.fromResult=(w,i)=>{let m=i.name,u=i.key,a=V(u),d="error"in i?()=>i.error:i.onError,E=s;return(async()=>{let p=E?performance.now():0;s&&c({type:"step_start",workflowId:o,stepId:a,stepKey:u,name:m,ts:Date.now()});let f=await w();if(f.ok){let R=performance.now()-p;return c({type:"step_success",workflowId:o,stepId:a,stepKey:u,name:m,ts:Date.now(),durationMs:R}),u&&c({type:"step_complete",workflowId:o,stepKey:u,name:m,ts:Date.now(),durationMs:R,result:S(f.value)}),f.value}else{let R=d(f.error),U=performance.now()-p,F=L(R,{origin:"result",resultCause:f.error});throw c({type:"step_error",workflowId:o,stepId:a,stepKey:u,name:m,ts:Date.now(),durationMs:U,error:F}),u&&c({type:"step_complete",workflowId:o,stepKey:u,name:m,ts:Date.now(),durationMs:U,result:T(R,{cause:f.error}),meta:{origin:"result",resultCause:f.error}}),n?.(R,m),M(R,{origin:"result",resultCause:f.error})}})()},r.retry=(w,i)=>r(w,{name:i.name,key:i.key,retry:{attempts:i.attempts,backoff:i.backoff,initialDelay:i.initialDelay,maxDelay:i.maxDelay,jitter:i.jitter,retryOn:i.retryOn,onRetry:i.onRetry},timeout:i.timeout}),r.withTimeout=(w,i)=>r(w,{name:i.name,key:i.key,timeout:i}),r.parallel=(w,i)=>{let m=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let u=performance.now(),a=!1;x.push({scopeId:m,type:"parallel"});let d=()=>{if(a)return;a=!0;let E=x.findIndex(p=>p.scopeId===m);E!==-1&&x.splice(E,1),c({type:"scope_end",workflowId:o,scopeId:m,ts:Date.now(),durationMs:performance.now()-u})};c({type:"scope_start",workflowId:o,scopeId:m,scopeType:"parallel",name:w,ts:Date.now()});try{let E=await i();if(d(),!E.ok)throw n?.(E.error,w),M(E.error,{origin:"result",resultCause:E.cause});return E.value}catch(E){throw d(),E}})()},r.race=(w,i)=>{let m=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let u=performance.now(),a=!1,d={scopeId:m,type:"race",winnerId:void 0};x.push(d);let E=()=>{if(a)return;a=!0;let p=x.findIndex(f=>f.scopeId===m);p!==-1&&x.splice(p,1),c({type:"scope_end",workflowId:o,scopeId:m,ts:Date.now(),durationMs:performance.now()-u,winnerId:d.winnerId})};c({type:"scope_start",workflowId:o,scopeId:m,scopeType:"race",name:w,ts:Date.now()});try{let p=await i();if(E(),!p.ok)throw n?.(p.error,w),M(p.error,{origin:"result",resultCause:p.cause});return p.value}catch(p){throw E(),p}})()},r.allSettled=(w,i)=>{let m=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let u=performance.now(),a=!1;x.push({scopeId:m,type:"allSettled"});let d=()=>{if(a)return;a=!0;let E=x.findIndex(p=>p.scopeId===m);E!==-1&&x.splice(E,1),c({type:"scope_end",workflowId:o,scopeId:m,ts:Date.now(),durationMs:performance.now()-u})};c({type:"scope_start",workflowId:o,scopeId:m,scopeType:"allSettled",name:w,ts:Date.now()});try{let E=await i();if(d(),!E.ok)throw n?.(E.error,w),M(E.error,{origin:"result",resultCause:E.cause});return E.value}catch(E){throw d(),E}})()};let v=await e(r);return S(v)}catch(r){if(de(r))throw r.thrown;if(H(r)){let v=se(r.meta);if(l||n)return T(r.error,{cause:v});if(ee(r.error))return T(r.error,{cause:v});let w=ue(r);return T(w,{cause:v})}if(l){let v=l(r);return n?.(v,"unexpected"),T(v,{cause:r})}let b={type:"UNEXPECTED_ERROR",cause:{type:"UNCAUGHT_EXCEPTION",thrown:r}};return n?.(b,"unexpected"),T(b,{cause:r})}}$.strict=(e,t)=>$(e,t);var N=class extends Error{constructor(n,s){super(`Unwrap called on an error result: ${String(n)}`);this.error=n;this.cause=s;this.name="UnwrapError"}},Ce=e=>{if(e.ok)return e.value;throw new N(e.error,e.cause)},xe=(e,t)=>e.ok?e.value:t,Se=(e,t)=>e.ok?e.value:t(e.error,e.cause);function ge(e,t){try{return S(e())}catch(n){return t?T(t(n),{cause:n}):T(n)}}async function Ae(e,t){try{return S(await e)}catch(n){return t?T(t(n),{cause:n}):T(n)}}async function Pe(e,t){try{return S(await e())}catch(n){return t?T(t(n),{cause:n}):T(n)}}function ve(e,t){return e!=null?S(e):T(t())}function be(e,t){return e.ok?S(t(e.value)):e}function he(e,t){return e.ok?e:T(t(e.error),{cause:e.cause})}function _e(e,t){return e.ok?t.ok(e.value):t.err(e.error,e.cause)}function Me(e,t){return e.ok?t(e.value):e}function Ie(e,t){return e.ok&&t(e.value),e}function Oe(e,t){return e.ok||t(e.error,e.cause),e}function Ue(e,t,n){if(!e.ok)return e;try{return S(t(e.value))}catch(s){return T(n(s),{cause:s})}}function De(e,t,n){if(e.ok)return e;try{return T(t(e.error),{cause:e.cause})}catch(s){return T(n(s),{cause:s})}}function Ke(e,t,n){return e.ok?S(t(e.value)):T(n(e.error),{cause:e.cause})}function Fe(e,t){return e.ok?e:t(e.error,e.cause)}async function je(e,t){let n=await e;return n.ok?n:t(n.error,n.cause)}function Ne(e,t){return e.ok?S(e.value):S(t(e.error,e.cause))}async function Ve(e,t){let n=await e;return n.ok?S(n.value):S(await t(n.error,n.cause))}function Le(e){let t=[];for(let n of e){if(!n.ok)return n;t.push(n.value)}return S(t)}async function We(e){return e.length===0?S([]):new Promise(t=>{let n=!1,s=e.length,l=new Array(e.length);for(let A=0;A<e.length;A++){let k=A;Promise.resolve(e[k]).catch(o=>T({type:"PROMISE_REJECTED",cause:o},{cause:{type:"PROMISE_REJECTION",reason:o}})).then(o=>{if(!n){if(!o.ok){n=!0,t(o);return}l[k]=o.value,s--,s===0&&t(S(l))}})}})}function Xe(e){let t=[],n=[];for(let s of e)s.ok?t.push(s.value):n.push({error:s.error,cause:s.cause});return n.length>0?T(n):S(t)}function Ye(e){let t=[],n=[];for(let s of e)s.ok?t.push(s.value):n.push(s.error);return{values:t,errors:n}}function Be(e){if(e.length===0)return T({type:"EMPTY_INPUT",message:"any() requires at least one Result"});let t=null;for(let n of e){if(n.ok)return n;t||(t=n)}return t}async function qe(e){return e.length===0?T({type:"EMPTY_INPUT",message:"anyAsync() requires at least one Result"}):new Promise(t=>{let n=!1,s=e.length,l=null;for(let A of e)Promise.resolve(A).catch(k=>T({type:"PROMISE_REJECTED",cause:k},{cause:{type:"PROMISE_REJECTION",reason:k}})).then(k=>{if(!n){if(k.ok){n=!0,t(k);return}l||(l=k),s--,s===0&&t(l)}})})}async function Je(e){let t=await Promise.all(e.map(l=>Promise.resolve(l).then(A=>({status:"result",result:A})).catch(A=>({status:"rejected",error:{type:"PROMISE_REJECTED",cause:A},cause:{type:"PROMISE_REJECTION",reason:A}})))),n=[],s=[];for(let l of t)l.status==="rejected"?s.push({error:l.error,cause:l.cause}):l.result.ok?n.push(l.result.value):s.push({error:l.result.error,cause:l.result.cause});return s.length>0?T(s):S(n)}0&&(module.exports={EARLY_EXIT_SYMBOL,STEP_TIMEOUT_MARKER,UnwrapError,all,allAsync,allSettled,allSettledAsync,andThen,any,anyAsync,bimap,createEarlyExit,err,from,fromNullable,fromPromise,getStepTimeoutMeta,isEarlyExit,isErr,isOk,isStepTimeoutError,isUnexpectedError,map,mapError,mapErrorTry,mapTry,match,ok,orElse,orElseAsync,partition,recover,recoverAsync,run,tap,tapError,tryAsync,unwrap,unwrapOr,unwrapOrElse});
|
|
1
|
+
"use strict";var G=Object.defineProperty;var Ee=Object.getOwnPropertyDescriptor;var ye=Object.getOwnPropertyNames;var we=Object.prototype.hasOwnProperty;var me=(e,t)=>{for(var n in t)G(e,n,{get:t[n],enumerable:!0})},Te=(e,t,n,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let w of ye(t))!we.call(e,w)&&w!==n&&G(e,w,{get:()=>t[w],enumerable:!(a=Ee(t,w))||a.enumerable});return e};var ke=e=>Te(G({},"__esModule",{value:!0}),e);var Qe={};me(Qe,{EARLY_EXIT_SYMBOL:()=>ee,STEP_TIMEOUT_MARKER:()=>D,UnwrapError:()=>X,all:()=>$e,allAsync:()=>Je,allSettled:()=>Be,allSettledAsync:()=>ze,andThen:()=>Ue,any:()=>Ge,anyAsync:()=>He,bimap:()=>Ne,createEarlyExit:()=>se,err:()=>f,from:()=>Pe,fromNullable:()=>ve,fromPromise:()=>he,getStepTimeoutMeta:()=>oe,hydrate:()=>ie,isEarlyExit:()=>ue,isErr:()=>fe,isOk:()=>de,isSerializedResult:()=>Ye,isStepTimeoutError:()=>Q,isUnexpectedError:()=>re,map:()=>Me,mapError:()=>Ie,mapErrorTry:()=>Fe,mapTry:()=>je,match:()=>Oe,ok:()=>g,orElse:()=>Ve,orElseAsync:()=>Le,partition:()=>qe,recover:()=>We,recoverAsync:()=>Xe,run:()=>Z,tap:()=>De,tapError:()=>Ke,tryAsync:()=>_e,unwrap:()=>ge,unwrapOr:()=>Ae,unwrapOrElse:()=>be});module.exports=ke(Qe);var g=e=>({ok:!0,value:e}),f=(e,t)=>({ok:!1,error:e,...t?.cause!==void 0?{cause:t.cause}:{}}),de=e=>e.ok,fe=e=>!e.ok,re=e=>typeof e=="object"&&e!==null&&e.type==="UNEXPECTED_ERROR",D=Symbol.for("step_timeout_marker");function Q(e){return typeof e!="object"||e===null?!1:e.type==="STEP_TIMEOUT"?!0:D in e}function oe(e){if(!(typeof e!="object"||e===null)){if(e.type==="STEP_TIMEOUT"){let t=e;return{timeoutMs:t.timeoutMs,stepName:t.stepName,stepKey:t.stepKey,attempt:t.attempt}}if(D in e)return e[D]}}var ee=Symbol("early-exit");function se(e,t){return{[ee]:!0,error:e,meta:t}}function ue(e){return typeof e=="object"&&e!==null&&e[ee]===!0}var ae=Symbol("mapper-exception");function Re(e){return{[ae]:!0,thrown:e}}function Ce(e){return typeof e=="object"&&e!==null&&e[ae]===!0}function xe(e){return typeof e=="string"?{name:e}:e??{}}function H(e,t){let{backoff:n,initialDelay:a,maxDelay:w,jitter:A}=t,E;switch(n){case"fixed":E=a;break;case"linear":E=a*e;break;case"exponential":E=a*Math.pow(2,e-1);break}if(E=Math.min(E,w),A){let r=E*.25*Math.random();E=E+r}return Math.floor(E)}function z(e){return new Promise(t=>setTimeout(t,e))}var ne=Symbol("timeout");async function Se(e,t,n){let a=new AbortController,w=t.error??{type:"STEP_TIMEOUT",stepName:n.name,stepKey:n.key,timeoutMs:t.ms,attempt:n.attempt},A,E=new Promise((I,C)=>{A=setTimeout(()=>{a.abort(),C({[ne]:!0,error:w})},t.ms)}),r;t.signal?r=Promise.resolve(e(a.signal)):r=Promise.resolve(e());try{return await Promise.race([r,E])}catch(I){if(typeof I=="object"&&I!==null&&I[ne]===!0){let C=I.error;if(typeof C=="object"&&C!==null&&C.type!=="STEP_TIMEOUT"){let L={timeoutMs:t.ms,stepName:n.name,stepKey:n.key,attempt:n.attempt};D in C?C[D]=L:Object.defineProperty(C,D,{value:L,enumerable:!1,writable:!0,configurable:!1})}throw C}throw I}finally{clearTimeout(A)}}var F={backoff:"exponential",initialDelay:100,maxDelay:3e4,jitter:!0,retryOn:()=>!0,onRetry:()=>{}};async function Z(e,t){let{onError:n,onEvent:a,catchUnexpected:w,workflowId:A,context:E}=t&&typeof t=="object"?t:{},r=A??crypto.randomUUID(),I=!n&&!w,C=[],L=0,Y=o=>o??`step_${++L}`,y=o=>{let b=o.context!==void 0||E===void 0?o:{...o,context:E};if(b.type==="step_success"){let M=b.stepId;for(let K=C.length-1;K>=0;K--){let N=C[K];if(N.type==="race"&&!N.winnerId){N.winnerId=M;break}}}a?.(b,E)},O=se,te=o=>ue(o),$=(o,b)=>I?b?.origin==="result"?{type:"UNEXPECTED_ERROR",cause:{type:"STEP_FAILURE",origin:"result",error:o,...b.resultCause!==void 0?{cause:b.resultCause}:{}}}:b?.origin==="throw"?{type:"UNEXPECTED_ERROR",cause:{type:"STEP_FAILURE",origin:"throw",error:o,thrown:b.thrown}}:{type:"UNEXPECTED_ERROR",cause:{type:"STEP_FAILURE",origin:"result",error:o}}:o,pe=o=>o.origin==="result"?o.resultCause:o.thrown,le=o=>({type:"UNEXPECTED_ERROR",cause:o.meta.origin==="result"?{type:"STEP_FAILURE",origin:"result",error:o.error,...o.meta.resultCause!==void 0?{cause:o.meta.resultCause}:{}}:{type:"STEP_FAILURE",origin:"throw",error:o.error,thrown:o.meta.thrown}});try{let b=function(T,p){let i=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let s=performance.now(),u=!1;C.push({scopeId:i,type:"parallel"});let x=()=>{if(u)return;u=!0;let c=C.findIndex(l=>l.scopeId===i);c!==-1&&C.splice(c,1),y({type:"scope_end",workflowId:r,scopeId:i,ts:Date.now(),durationMs:performance.now()-s})};y({type:"scope_start",workflowId:r,scopeId:i,scopeType:"parallel",name:T,ts:Date.now()});try{let c=await p();if(x(),!c.ok)throw n?.(c.error,T,E),O(c.error,{origin:"result",resultCause:c.cause});return c.value}catch(c){throw x(),c}})()},M=function(T,p){let i=Object.keys(T),s=p.name??`Parallel(${i.join(", ")})`,u=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let x=performance.now(),c=!1;C.push({scopeId:u,type:"parallel"});let l=()=>{if(c)return;c=!0;let k=C.findIndex(R=>R.scopeId===u);k!==-1&&C.splice(k,1),y({type:"scope_end",workflowId:r,scopeId:u,ts:Date.now(),durationMs:performance.now()-x})};y({type:"scope_start",workflowId:r,scopeId:u,scopeType:"parallel",name:s,ts:Date.now()});try{let k=await new Promise(h=>{if(i.length===0){h([]);return}let _=!1,S=i.length,V=new Array(i.length);for(let v=0;v<i.length;v++){let j=i[v],J=v;Promise.resolve(T[j]()).catch(d=>f({type:"PROMISE_REJECTED",cause:d},{cause:{type:"PROMISE_REJECTION",reason:d}})).then(d=>{if(!_){if(!d.ok){_=!0,h([{key:j,result:d}]);return}V[J]={key:j,result:d},S--,S===0&&h(V)}})}});l();let R={};for(let{key:h,result:_}of k){if(!_.ok)throw n?.(_.error,h,E),O(_.error,{origin:"result",resultCause:_.cause});R[h]=_.value}return R}catch(k){throw l(),k}})()};var Ze=b,et=M;let o=(T,p)=>(async()=>{let i=xe(p),{name:s,key:u,retry:x,timeout:c}=i,l=Y(u),k=a,R=k?performance.now():0;if(!(typeof T=="function")){if(x&&x.attempts>1)throw new Error("step: retry options require a function operation. Direct Promise/Result values cannot be re-executed on retry. Wrap your operation in a function: step(() => yourOperation, { retry: {...} })");if(c)throw new Error("step: timeout options require a function operation. Direct Promise/Result values cannot be wrapped with timeout after they've started. Wrap your operation in a function: step(() => yourOperation, { timeout: {...} })")}let S={attempts:Math.max(1,x?.attempts??1),backoff:x?.backoff??F.backoff,initialDelay:x?.initialDelay??F.initialDelay,maxDelay:x?.maxDelay??F.maxDelay,jitter:x?.jitter??F.jitter,retryOn:x?.retryOn??F.retryOn,onRetry:x?.onRetry??F.onRetry};a&&y({type:"step_start",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now()});let V;for(let d=1;d<=S.attempts;d++){let ce=k?performance.now():0;try{let m;if(typeof T=="function"?c?m=await Se(T,c,{name:s,key:u,attempt:d}):m=await T():m=await T,m.ok){let U=performance.now()-R;return y({type:"step_success",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),durationMs:U}),u&&y({type:"step_complete",workflowId:r,stepKey:u,name:s,ts:Date.now(),durationMs:U,result:m}),m.value}if(V=m,d<S.attempts&&S.retryOn(m.error,d)){let U=H(d,S);y({type:"step_retry",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),attempt:d+1,maxAttempts:S.attempts,delayMs:U,error:m.error}),S.onRetry(m.error,d,U),await z(U);continue}S.attempts>1&&y({type:"step_retries_exhausted",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),durationMs:performance.now()-R,attempts:d,lastError:m.error});break}catch(m){let U=performance.now()-ce;if(te(m))throw y({type:"step_aborted",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),durationMs:U}),m;if(Q(m)){let P=oe(m),B=c?.ms??P?.timeoutMs??0;if(y({type:"step_timeout",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),timeoutMs:B,attempt:d}),d<S.attempts&&S.retryOn(m,d)){let q=H(d,S);y({type:"step_retry",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),attempt:d+1,maxAttempts:S.attempts,delayMs:q,error:m}),S.onRetry(m,d,q),await z(q);continue}S.attempts>1&&y({type:"step_retries_exhausted",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),durationMs:performance.now()-R,attempts:d,lastError:m})}if(d<S.attempts&&S.retryOn(m,d)){let P=H(d,S);y({type:"step_retry",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),attempt:d+1,maxAttempts:S.attempts,delayMs:P,error:m}),S.onRetry(m,d,P),await z(P);continue}S.attempts>1&&!Q(m)&&y({type:"step_retries_exhausted",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),durationMs:performance.now()-R,attempts:d,lastError:m});let W=performance.now()-R;if(w){let P;try{P=w(m)}catch(B){throw Re(B)}throw y({type:"step_error",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),durationMs:W,error:P}),u&&y({type:"step_complete",workflowId:r,stepKey:u,name:s,ts:Date.now(),durationMs:W,result:f(P,{cause:m}),meta:{origin:"throw",thrown:m}}),n?.(P,s,E),O(P,{origin:"throw",thrown:m})}else{let P={type:"UNEXPECTED_ERROR",cause:{type:"UNCAUGHT_EXCEPTION",thrown:m}};throw y({type:"step_error",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),durationMs:W,error:P}),u&&y({type:"step_complete",workflowId:r,stepKey:u,name:s,ts:Date.now(),durationMs:W,result:f(P,{cause:m}),meta:{origin:"throw",thrown:m}}),m}}}let v=V,j=performance.now()-R,J=$(v.error,{origin:"result",resultCause:v.cause});throw y({type:"step_error",workflowId:r,stepId:l,stepKey:u,name:s,ts:Date.now(),durationMs:j,error:J}),u&&y({type:"step_complete",workflowId:r,stepKey:u,name:s,ts:Date.now(),durationMs:j,result:v,meta:{origin:"result",resultCause:v.cause}}),n?.(v.error,s,E),O(v.error,{origin:"result",resultCause:v.cause})})();o.try=(T,p)=>{let i=p.name,s=p.key,u=Y(s),x="error"in p?()=>p.error:p.onError,c=a;return(async()=>{let l=c?performance.now():0;a&&y({type:"step_start",workflowId:r,stepId:u,stepKey:s,name:i,ts:Date.now()});try{let k=await T(),R=performance.now()-l;return y({type:"step_success",workflowId:r,stepId:u,stepKey:s,name:i,ts:Date.now(),durationMs:R}),s&&y({type:"step_complete",workflowId:r,stepKey:s,name:i,ts:Date.now(),durationMs:R,result:g(k)}),k}catch(k){let R=x(k),h=performance.now()-l,_=$(R,{origin:"throw",thrown:k});throw y({type:"step_error",workflowId:r,stepId:u,stepKey:s,name:i,ts:Date.now(),durationMs:h,error:_}),s&&y({type:"step_complete",workflowId:r,stepKey:s,name:i,ts:Date.now(),durationMs:h,result:f(R,{cause:k}),meta:{origin:"throw",thrown:k}}),n?.(R,i,E),O(R,{origin:"throw",thrown:k})}})()},o.fromResult=(T,p)=>{let i=p.name,s=p.key,u=Y(s),x="error"in p?()=>p.error:p.onError,c=a;return(async()=>{let l=c?performance.now():0;a&&y({type:"step_start",workflowId:r,stepId:u,stepKey:s,name:i,ts:Date.now()});let k=await T();if(k.ok){let R=performance.now()-l;return y({type:"step_success",workflowId:r,stepId:u,stepKey:s,name:i,ts:Date.now(),durationMs:R}),s&&y({type:"step_complete",workflowId:r,stepKey:s,name:i,ts:Date.now(),durationMs:R,result:g(k.value)}),k.value}else{let R=x(k.error),h=performance.now()-l,_=$(R,{origin:"result",resultCause:k.error});throw y({type:"step_error",workflowId:r,stepId:u,stepKey:s,name:i,ts:Date.now(),durationMs:h,error:_}),s&&y({type:"step_complete",workflowId:r,stepKey:s,name:i,ts:Date.now(),durationMs:h,result:f(R,{cause:k.error}),meta:{origin:"result",resultCause:k.error}}),n?.(R,i,E),O(R,{origin:"result",resultCause:k.error})}})()},o.retry=(T,p)=>o(T,{name:p.name,key:p.key,retry:{attempts:p.attempts,backoff:p.backoff,initialDelay:p.initialDelay,maxDelay:p.maxDelay,jitter:p.jitter,retryOn:p.retryOn,onRetry:p.onRetry},timeout:p.timeout}),o.withTimeout=(T,p)=>o(T,{name:p.name,key:p.key,timeout:p}),o.parallel=((...T)=>{if(typeof T[0]=="string"){let p=T[0],i=T[1];return b(p,i)}else{let p=T[0],i=T[1]??{};return M(p,i)}}),o.race=(T,p)=>{let i=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let s=performance.now(),u=!1,x={scopeId:i,type:"race",winnerId:void 0};C.push(x);let c=()=>{if(u)return;u=!0;let l=C.findIndex(k=>k.scopeId===i);l!==-1&&C.splice(l,1),y({type:"scope_end",workflowId:r,scopeId:i,ts:Date.now(),durationMs:performance.now()-s,winnerId:x.winnerId})};y({type:"scope_start",workflowId:r,scopeId:i,scopeType:"race",name:T,ts:Date.now()});try{let l=await p();if(c(),!l.ok)throw n?.(l.error,T,E),O(l.error,{origin:"result",resultCause:l.cause});return l.value}catch(l){throw c(),l}})()},o.allSettled=(T,p)=>{let i=`scope_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;return(async()=>{let s=performance.now(),u=!1;C.push({scopeId:i,type:"allSettled"});let x=()=>{if(u)return;u=!0;let c=C.findIndex(l=>l.scopeId===i);c!==-1&&C.splice(c,1),y({type:"scope_end",workflowId:r,scopeId:i,ts:Date.now(),durationMs:performance.now()-s})};y({type:"scope_start",workflowId:r,scopeId:i,scopeType:"allSettled",name:T,ts:Date.now()});try{let c=await p();if(x(),!c.ok)throw n?.(c.error,T,E),O(c.error,{origin:"result",resultCause:c.cause});return c.value}catch(c){throw x(),c}})()};let N=await e(o);return g(N)}catch(o){if(Ce(o))throw o.thrown;if(te(o)){let M=pe(o.meta);if(w||n)return f(o.error,{cause:M});if(re(o.error))return f(o.error,{cause:M});let K=le(o);return f(K,{cause:M})}if(w){let M=w(o);return n?.(M,"unexpected",E),f(M,{cause:o})}let b={type:"UNEXPECTED_ERROR",cause:{type:"UNCAUGHT_EXCEPTION",thrown:o}};return n?.(b,"unexpected",E),f(b,{cause:o})}}Z.strict=(e,t)=>Z(e,t);var X=class extends Error{constructor(n,a){super(`Unwrap called on an error result: ${String(n)}`);this.error=n;this.cause=a;this.name="UnwrapError"}},ge=e=>{if(e.ok)return e.value;throw new X(e.error,e.cause)},Ae=(e,t)=>e.ok?e.value:t,be=(e,t)=>e.ok?e.value:t(e.error,e.cause);function Pe(e,t){try{return g(e())}catch(n){return t?f(t(n),{cause:n}):f(n)}}async function he(e,t){try{return g(await e)}catch(n){return t?f(t(n),{cause:n}):f(n)}}async function _e(e,t){try{return g(await e())}catch(n){return t?f(t(n),{cause:n}):f(n)}}function ve(e,t){return e!=null?g(e):f(t())}function Me(e,t){return e.ok?g(t(e.value)):e}function Ie(e,t){return e.ok?e:f(t(e.error),{cause:e.cause})}function Oe(e,t){return e.ok?t.ok(e.value):t.err(e.error,e.cause)}function Ue(e,t){return e.ok?t(e.value):e}function De(e,t){return e.ok&&t(e.value),e}function Ke(e,t){return e.ok||t(e.error,e.cause),e}function je(e,t,n){if(!e.ok)return e;try{return g(t(e.value))}catch(a){return f(n(a),{cause:a})}}function Fe(e,t,n){if(e.ok)return e;try{return f(t(e.error),{cause:e.cause})}catch(a){return f(n(a),{cause:a})}}function Ne(e,t,n){return e.ok?g(t(e.value)):f(n(e.error),{cause:e.cause})}function Ve(e,t){return e.ok?e:t(e.error,e.cause)}async function Le(e,t){let n=await e;return n.ok?n:t(n.error,n.cause)}function We(e,t){return e.ok?g(e.value):g(t(e.error,e.cause))}async function Xe(e,t){let n=await e;return n.ok?g(n.value):g(await t(n.error,n.cause))}function ie(e){return e!==null&&typeof e=="object"&&"ok"in e&&typeof e.ok=="boolean"&&(e.ok===!0&&"value"in e||e.ok===!1&&"error"in e)?e:null}function Ye(e){return ie(e)!==null}function $e(e){let t=[];for(let n of e){if(!n.ok)return n;t.push(n.value)}return g(t)}async function Je(e){return e.length===0?g([]):new Promise(t=>{let n=!1,a=e.length,w=new Array(e.length);for(let A=0;A<e.length;A++){let E=A;Promise.resolve(e[E]).catch(r=>f({type:"PROMISE_REJECTED",cause:r},{cause:{type:"PROMISE_REJECTION",reason:r}})).then(r=>{if(!n){if(!r.ok){n=!0,t(r);return}w[E]=r.value,a--,a===0&&t(g(w))}})}})}function Be(e){let t=[],n=[];for(let a of e)a.ok?t.push(a.value):n.push({error:a.error,cause:a.cause});return n.length>0?f(n):g(t)}function qe(e){let t=[],n=[];for(let a of e)a.ok?t.push(a.value):n.push(a.error);return{values:t,errors:n}}function Ge(e){if(e.length===0)return f({type:"EMPTY_INPUT",message:"any() requires at least one Result"});let t=null;for(let n of e){if(n.ok)return n;t||(t=n)}return t}async function He(e){return e.length===0?f({type:"EMPTY_INPUT",message:"anyAsync() requires at least one Result"}):new Promise(t=>{let n=!1,a=e.length,w=null;for(let A of e)Promise.resolve(A).catch(E=>f({type:"PROMISE_REJECTED",cause:E},{cause:{type:"PROMISE_REJECTION",reason:E}})).then(E=>{if(!n){if(E.ok){n=!0,t(E);return}w||(w=E),a--,a===0&&t(w)}})})}async function ze(e){let t=await Promise.all(e.map(w=>Promise.resolve(w).then(A=>({status:"result",result:A})).catch(A=>({status:"rejected",error:{type:"PROMISE_REJECTED",cause:A},cause:{type:"PROMISE_REJECTION",reason:A}})))),n=[],a=[];for(let w of t)w.status==="rejected"?a.push({error:w.error,cause:w.cause}):w.result.ok?n.push(w.result.value):a.push({error:w.result.error,cause:w.result.cause});return a.length>0?f(a):g(n)}0&&(module.exports={EARLY_EXIT_SYMBOL,STEP_TIMEOUT_MARKER,UnwrapError,all,allAsync,allSettled,allSettledAsync,andThen,any,anyAsync,bimap,createEarlyExit,err,from,fromNullable,fromPromise,getStepTimeoutMeta,hydrate,isEarlyExit,isErr,isOk,isSerializedResult,isStepTimeoutError,isUnexpectedError,map,mapError,mapErrorTry,mapTry,match,ok,orElse,orElseAsync,partition,recover,recoverAsync,run,tap,tapError,tryAsync,unwrap,unwrapOr,unwrapOrElse});
|
|
2
2
|
//# sourceMappingURL=core.cjs.map
|