runsheet 0.5.0 → 0.6.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 +53 -57
- package/dist/index.cjs +357 -349
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +331 -290
- package/dist/index.d.ts +331 -290
- package/dist/index.js +356 -347
- package/dist/index.js.map +1 -1
- package/llms.txt +66 -45
- package/package.json +2 -5
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
Type-safe, composable business logic pipelines for TypeScript.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Pipelines are steps — compose them freely, nest them arbitrarily.
|
|
9
9
|
|
|
10
10
|
## Why runsheet
|
|
11
11
|
|
|
@@ -44,7 +44,7 @@ A pipeline orchestration library with:
|
|
|
44
44
|
on hover. Both sync and async `run` functions are supported.
|
|
45
45
|
- **Type-safe accumulated context** — each step declares what it requires and
|
|
46
46
|
provides. TypeScript enforces at compile time that requirements are satisfied,
|
|
47
|
-
and `
|
|
47
|
+
and `pipeline` infers the full output type from the steps you pass.
|
|
48
48
|
- **Immutable step boundaries** — context is frozen between steps. Each step
|
|
49
49
|
receives a snapshot and returns only what it adds.
|
|
50
50
|
- **Rollback with snapshots** — on failure, rollback handlers execute in reverse
|
|
@@ -127,9 +127,9 @@ integrity from one step to the next.
|
|
|
127
127
|
### Build and run a pipeline
|
|
128
128
|
|
|
129
129
|
```typescript
|
|
130
|
-
import {
|
|
130
|
+
import { pipeline } from 'runsheet';
|
|
131
131
|
|
|
132
|
-
const placeOrder =
|
|
132
|
+
const placeOrder = pipeline({
|
|
133
133
|
name: 'placeOrder',
|
|
134
134
|
steps: [validateOrder, chargePayment, sendConfirmation],
|
|
135
135
|
});
|
|
@@ -140,7 +140,7 @@ if (result.success) {
|
|
|
140
140
|
console.log(result.data.chargeId); // string — fully typed
|
|
141
141
|
console.log(result.data.sentAt); // Date
|
|
142
142
|
} else {
|
|
143
|
-
console.error(result.
|
|
143
|
+
console.error(result.error); // what went wrong
|
|
144
144
|
console.log(result.rollback); // { completed: [...], failed: [...] }
|
|
145
145
|
}
|
|
146
146
|
```
|
|
@@ -148,19 +148,35 @@ if (result.success) {
|
|
|
148
148
|
The pipeline's result type is inferred from the steps — `result.data` carries
|
|
149
149
|
the intersection of all step outputs, not an erased `Record<string, unknown>`.
|
|
150
150
|
|
|
151
|
+
### Pipeline composition
|
|
152
|
+
|
|
153
|
+
Pipelines are steps — use one pipeline as a step in another:
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
const checkout = pipeline({
|
|
157
|
+
name: 'checkout',
|
|
158
|
+
steps: [validateOrder, chargePayment, sendConfirmation],
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const fullFlow = pipeline({
|
|
162
|
+
name: 'fullFlow',
|
|
163
|
+
steps: [checkout, shipOrder, notifyWarehouse],
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
151
167
|
### Builder API
|
|
152
168
|
|
|
153
169
|
For complex pipelines, the builder gives progressive type narrowing — each
|
|
154
170
|
`.step()` call extends the known context type:
|
|
155
171
|
|
|
156
172
|
```typescript
|
|
157
|
-
import {
|
|
173
|
+
import { pipeline } from 'runsheet';
|
|
158
174
|
import { z } from 'zod';
|
|
159
175
|
|
|
160
|
-
const placeOrder =
|
|
161
|
-
'placeOrder',
|
|
162
|
-
z.object({ orderId: z.string() }),
|
|
163
|
-
)
|
|
176
|
+
const placeOrder = pipeline({
|
|
177
|
+
name: 'placeOrder',
|
|
178
|
+
argsSchema: z.object({ orderId: z.string() }),
|
|
179
|
+
})
|
|
164
180
|
.step(validateOrder) // context now includes order
|
|
165
181
|
.step(chargePayment) // context now includes chargeId
|
|
166
182
|
.step(sendConfirmation) // context now includes sentAt
|
|
@@ -170,7 +186,7 @@ const placeOrder = createPipeline(
|
|
|
170
186
|
Type-only args (no runtime validation of pipeline input):
|
|
171
187
|
|
|
172
188
|
```typescript
|
|
173
|
-
const placeOrder =
|
|
189
|
+
const placeOrder = pipeline<{ orderId: string }>({ name: 'placeOrder' })
|
|
174
190
|
.step(validateOrder)
|
|
175
191
|
.step(chargePayment)
|
|
176
192
|
.step(sendConfirmation)
|
|
@@ -197,7 +213,7 @@ const logOrder = defineStep<{ order: { id: string } }, { loggedAt: Date }>({
|
|
|
197
213
|
```typescript
|
|
198
214
|
import { when } from 'runsheet';
|
|
199
215
|
|
|
200
|
-
const placeOrder =
|
|
216
|
+
const placeOrder = pipeline({
|
|
201
217
|
name: 'placeOrder',
|
|
202
218
|
steps: [
|
|
203
219
|
validateOrder,
|
|
@@ -208,15 +224,15 @@ const placeOrder = buildPipeline({
|
|
|
208
224
|
});
|
|
209
225
|
```
|
|
210
226
|
|
|
211
|
-
Skipped steps produce no snapshot, no rollback entry
|
|
212
|
-
|
|
227
|
+
Skipped steps produce no snapshot, no rollback entry, and do not appear in
|
|
228
|
+
`result.meta.stepsExecuted`.
|
|
213
229
|
|
|
214
230
|
### Middleware
|
|
215
231
|
|
|
216
232
|
Middleware wraps the entire step lifecycle including schema validation:
|
|
217
233
|
|
|
218
234
|
```typescript
|
|
219
|
-
import {
|
|
235
|
+
import { pipeline } from 'runsheet';
|
|
220
236
|
import type { StepMiddleware } from 'runsheet';
|
|
221
237
|
|
|
222
238
|
const timing: StepMiddleware = (step, next) => async (ctx) => {
|
|
@@ -233,7 +249,7 @@ const logging: StepMiddleware = (step, next) => async (ctx) => {
|
|
|
233
249
|
return result;
|
|
234
250
|
};
|
|
235
251
|
|
|
236
|
-
const placeOrder =
|
|
252
|
+
const placeOrder = pipeline({
|
|
237
253
|
name: 'placeOrder',
|
|
238
254
|
steps: [validateOrder, chargePayment, sendConfirmation],
|
|
239
255
|
middleware: [logging, timing],
|
|
@@ -243,7 +259,7 @@ const placeOrder = buildPipeline({
|
|
|
243
259
|
Middleware with the builder:
|
|
244
260
|
|
|
245
261
|
```typescript
|
|
246
|
-
const placeOrder =
|
|
262
|
+
const placeOrder = pipeline<{ orderId: string }>({ name: 'placeOrder' })
|
|
247
263
|
.use(logging, timing)
|
|
248
264
|
.step(validateOrder)
|
|
249
265
|
.step(chargePayment)
|
|
@@ -289,7 +305,7 @@ Run steps concurrently with `parallel()`. Outputs merge in array order:
|
|
|
289
305
|
```typescript
|
|
290
306
|
import { parallel } from 'runsheet';
|
|
291
307
|
|
|
292
|
-
const placeOrder =
|
|
308
|
+
const placeOrder = pipeline({
|
|
293
309
|
name: 'placeOrder',
|
|
294
310
|
steps: [
|
|
295
311
|
validateOrder,
|
|
@@ -323,16 +339,16 @@ const chargePayment = defineStep({
|
|
|
323
339
|
},
|
|
324
340
|
});
|
|
325
341
|
|
|
326
|
-
const
|
|
342
|
+
const placeOrder = pipeline<{
|
|
327
343
|
orderId: string;
|
|
328
344
|
stripe: Stripe;
|
|
329
345
|
db: Database;
|
|
330
|
-
}>('placeOrder')
|
|
346
|
+
}>({ name: 'placeOrder' })
|
|
331
347
|
.step(validateOrder)
|
|
332
348
|
.step(chargePayment)
|
|
333
349
|
.build();
|
|
334
350
|
|
|
335
|
-
await
|
|
351
|
+
await placeOrder.run({
|
|
336
352
|
orderId: '123',
|
|
337
353
|
stripe: stripeClient,
|
|
338
354
|
db: dbClient,
|
|
@@ -352,7 +368,7 @@ Functions Choice state:
|
|
|
352
368
|
```typescript
|
|
353
369
|
import { choice } from 'runsheet';
|
|
354
370
|
|
|
355
|
-
const placeOrder =
|
|
371
|
+
const placeOrder = pipeline({
|
|
356
372
|
name: 'placeOrder',
|
|
357
373
|
steps: [
|
|
358
374
|
validateOrder,
|
|
@@ -380,7 +396,7 @@ like an AWS Step Functions Map state:
|
|
|
380
396
|
import { map } from 'runsheet';
|
|
381
397
|
|
|
382
398
|
// Function form — items can be any type
|
|
383
|
-
const
|
|
399
|
+
const p = pipeline({
|
|
384
400
|
name: 'notify',
|
|
385
401
|
steps: [
|
|
386
402
|
map(
|
|
@@ -395,7 +411,7 @@ const pipeline = buildPipeline({
|
|
|
395
411
|
});
|
|
396
412
|
|
|
397
413
|
// Step form — reuse existing steps
|
|
398
|
-
const
|
|
414
|
+
const p = pipeline({
|
|
399
415
|
name: 'process',
|
|
400
416
|
steps: [map('results', (ctx) => ctx.items, processItem)],
|
|
401
417
|
});
|
|
@@ -412,7 +428,7 @@ only).
|
|
|
412
428
|
```typescript
|
|
413
429
|
import { filter, map } from 'runsheet';
|
|
414
430
|
|
|
415
|
-
const
|
|
431
|
+
const p = pipeline({
|
|
416
432
|
name: 'notify',
|
|
417
433
|
steps: [
|
|
418
434
|
filter(
|
|
@@ -444,7 +460,7 @@ pure operation).
|
|
|
444
460
|
```typescript
|
|
445
461
|
import { flatMap } from 'runsheet';
|
|
446
462
|
|
|
447
|
-
const
|
|
463
|
+
const p = pipeline({
|
|
448
464
|
name: 'process',
|
|
449
465
|
steps: [
|
|
450
466
|
flatMap(
|
|
@@ -501,29 +517,27 @@ if (!result.success) {
|
|
|
501
517
|
}
|
|
502
518
|
```
|
|
503
519
|
|
|
504
|
-
##
|
|
520
|
+
## Step result
|
|
505
521
|
|
|
506
|
-
Every
|
|
522
|
+
Every `run()` returns a `StepResult` with execution metadata:
|
|
507
523
|
|
|
508
524
|
```typescript
|
|
509
525
|
// Success
|
|
510
526
|
{
|
|
511
527
|
success: true,
|
|
512
528
|
data: { /* accumulated context — fully typed */ },
|
|
513
|
-
errors: [],
|
|
514
529
|
meta: {
|
|
515
|
-
|
|
530
|
+
name: 'placeOrder',
|
|
516
531
|
args: { orderId: '123' },
|
|
517
532
|
stepsExecuted: ['validateOrder', 'chargePayment', 'sendConfirmation'],
|
|
518
|
-
stepsSkipped: [],
|
|
519
533
|
}
|
|
520
534
|
}
|
|
521
535
|
|
|
522
536
|
// Failure
|
|
523
537
|
{
|
|
524
538
|
success: false,
|
|
525
|
-
|
|
526
|
-
meta: {
|
|
539
|
+
error: Error,
|
|
540
|
+
meta: { name, args, stepsExecuted },
|
|
527
541
|
failedStep: 'chargePayment',
|
|
528
542
|
rollback: { completed: [...], failed: [...] },
|
|
529
543
|
}
|
|
@@ -547,42 +561,25 @@ schemas or generics you provide.
|
|
|
547
561
|
| `retry` | `RetryPolicy` | Optional retry policy for transient failures |
|
|
548
562
|
| `timeout` | `number` | Optional max duration in ms for the `run` function |
|
|
549
563
|
|
|
550
|
-
### `
|
|
564
|
+
### `pipeline(config)`
|
|
551
565
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
566
|
+
Create a pipeline. When `steps` is provided, returns an `AggregateStep`
|
|
567
|
+
immediately. When `steps` is omitted, returns a `PipelineBuilder` with
|
|
568
|
+
`.step()`, `.use()`, and `.build()` for progressive type narrowing.
|
|
555
569
|
|
|
556
570
|
| Option | Type | Description |
|
|
557
571
|
| ------------ | ------------------ | ----------------------------------------------------------------- |
|
|
558
572
|
| `name` | `string` | Pipeline name |
|
|
559
|
-
| `steps` | `Step[]` | Steps to execute in order
|
|
573
|
+
| `steps` | `Step[]` | Steps to execute in order (omit for builder mode) |
|
|
560
574
|
| `middleware` | `StepMiddleware[]` | Optional middleware |
|
|
561
575
|
| `argsSchema` | `ZodSchema` | Optional schema for pipeline input validation |
|
|
562
576
|
| `strict` | `boolean` | Optional — throws at build time if two steps provide the same key |
|
|
563
577
|
|
|
564
|
-
### `createPipeline(name, argsSchema?, options?)`
|
|
565
|
-
|
|
566
|
-
Start a fluent pipeline builder. Returns a `PipelineBuilder` with:
|
|
567
|
-
|
|
568
|
-
- `.step(step)` — add a step
|
|
569
|
-
- `.use(...middleware)` — add middleware
|
|
570
|
-
- `.build()` — produce the pipeline
|
|
571
|
-
|
|
572
|
-
The second argument accepts a schema (for runtime args validation) or an options
|
|
573
|
-
object:
|
|
574
|
-
|
|
575
|
-
```typescript
|
|
576
|
-
createPipeline('order', z.object({ id: z.string() }));
|
|
577
|
-
createPipeline('order', { strict: true });
|
|
578
|
-
createPipeline('order', z.object({ id: z.string() }), { strict: true });
|
|
579
|
-
```
|
|
580
|
-
|
|
581
578
|
### `parallel(...steps)`
|
|
582
579
|
|
|
583
580
|
Run steps concurrently and merge their outputs. Returns a single step usable
|
|
584
581
|
anywhere a regular step is accepted. On partial failure, succeeded inner steps
|
|
585
|
-
are rolled back before the error propagates.
|
|
582
|
+
are rolled back before the error propagates.
|
|
586
583
|
|
|
587
584
|
### `choice(...branches)`
|
|
588
585
|
|
|
@@ -629,7 +626,6 @@ MIT
|
|
|
629
626
|
[ci-badge]:
|
|
630
627
|
https://github.com/shaug/runsheet-js/actions/workflows/ci.yml/badge.svg
|
|
631
628
|
[ci-url]: https://github.com/shaug/runsheet-js/actions/workflows/ci.yml
|
|
632
|
-
[composable-functions]: https://github.com/seasonedcc/composable-functions
|
|
633
629
|
[license-badge]: https://img.shields.io/npm/l/runsheet
|
|
634
630
|
[license-url]: https://github.com/shaug/runsheet-js/blob/main/LICENSE
|
|
635
631
|
[npm-badge]: https://img.shields.io/npm/v/runsheet
|