@wooksjs/event-wf 0.6.6 → 0.7.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.
@@ -15,7 +15,9 @@ const app = createWfApp<{ result: number }>()
15
15
 
16
16
  // Function handler
17
17
  app.step('double', {
18
- handler: (ctx) => { ctx.result *= 2 },
18
+ handler: (ctx) => {
19
+ ctx.result *= 2
20
+ },
19
21
  })
20
22
 
21
23
  // String handler (storable, runs in restricted env)
@@ -26,6 +28,7 @@ app.step('add', {
26
28
  ```
27
29
 
28
30
  **Parameters:**
31
+
29
32
  - `id` — Step identifier (used in flow schemas to reference this step). Supports router syntax: `'add/:n'`, `'process/*'`, etc.
30
33
  - `opts.handler` — Either a function `(ctx: T, input?: I) => void | IR` or a JavaScript string.
31
34
  - `opts.input` — Optional: input type description (string). When present and no input is provided at runtime, the workflow pauses to request input.
@@ -90,14 +93,11 @@ String handlers are useful when workflow definitions are stored in a database
90
93
  Registers a flow (workflow schema) — an ordered sequence of steps:
91
94
 
92
95
  ```ts
93
- app.flow('calculate', [
94
- { id: 'add', input: 5 },
95
- { id: 'add', input: 2 },
96
- { id: 'double' },
97
- ])
96
+ app.flow('calculate', [{ id: 'add', input: 5 }, { id: 'add', input: 2 }, { id: 'double' }])
98
97
  ```
99
98
 
100
99
  **Parameters:**
100
+
101
101
  - `id` — Flow identifier. Supports router syntax (e.g., `'process/:type'`, `'batch/*'`).
102
102
  - `schema` — Array of step references, conditions, and loops (see Schema Syntax below).
103
103
  - `prefix` — Optional prefix prepended to step IDs during resolution.
@@ -135,11 +135,7 @@ app.flow('f2', [
135
135
  ])
136
136
 
137
137
  // 3. Mixed
138
- app.flow('f3', [
139
- 'step1',
140
- { id: 'add', input: 5 },
141
- 'step2',
142
- ])
138
+ app.flow('f3', ['step1', { id: 'add', input: 5 }, 'step2'])
143
139
  ```
144
140
 
145
141
  ### Conditional execution
@@ -178,13 +174,14 @@ app.flow('retry-flow', [
178
174
  while: 'attempts < 5 && !success',
179
175
  steps: [
180
176
  { id: 'attempt' },
181
- { break: 'success' }, // break when success is truthy
177
+ { break: 'success' }, // break when success is truthy
182
178
  ],
183
179
  },
184
180
  ])
185
181
  ```
186
182
 
187
183
  Loop constructs:
184
+
188
185
  - `while` — Condition string evaluated before each iteration
189
186
  - `break` — Condition string; if truthy, exits the loop
190
187
  - `continue` — Condition string; if truthy, skips to next iteration
@@ -295,12 +292,12 @@ app.step('my-step', {
295
292
  handler: () => {
296
293
  const { ctx, input, schemaId, stepId, indexes, resume } = useWfState()
297
294
 
298
- ctx<MyContext>() // the workflow context object (type T)
299
- input<MyInput>() // the current step's input (or undefined)
300
- schemaId // the flow ID being executed
301
- stepId() // the current step ID
302
- indexes() // position in schema (for resume tracking)
303
- resume // boolean: true if this is a resumed execution
295
+ ctx<MyContext>() // the workflow context object (type T)
296
+ input<MyInput>() // the current step's input (or undefined)
297
+ schemaId // the flow ID being executed
298
+ stepId() // the current step ID
299
+ indexes() // position in schema (for resume tracking)
300
+ resume // boolean: true if this is a resumed execution
304
301
  },
305
302
  })
306
303
  ```
@@ -314,7 +311,7 @@ app.step('transform', {
314
311
  handler: () => {
315
312
  const { ctx } = useWfState()
316
313
  const context = ctx<{ items: string[]; processed: boolean }>()
317
- context.items = context.items.map(s => s.toUpperCase())
314
+ context.items = context.items.map((s) => s.toUpperCase())
318
315
  context.processed = true
319
316
  },
320
317
  })
@@ -361,7 +358,7 @@ When a step declares an `input` type but no input is provided in the schema, the
361
358
 
362
359
  ```ts
363
360
  app.step('get-email', {
364
- input: 'string', // declares expected input type
361
+ input: 'string', // declares expected input type
365
362
  handler: 'ctx.email = input',
366
363
  })
367
364
 
@@ -370,7 +367,7 @@ app.step('send-welcome', {
370
367
  })
371
368
 
372
369
  app.flow('onboarding', [
373
- { id: 'get-email' }, // no input provided → workflow pauses
370
+ { id: 'get-email' }, // no input provided → workflow pauses
374
371
  { id: 'send-welcome' },
375
372
  ])
376
373
 
@@ -380,7 +377,7 @@ const output = await app.start('onboarding', {})
380
377
  // output.inputRequired.type === 'string'
381
378
 
382
379
  // Resume with user's email
383
- const final = await app.resume(output.state, 'user@example.com')
380
+ const final = await app.resume(output.state, { input: 'user@example.com' })
384
381
  // final.finished === true
385
382
  ```
386
383
 
@@ -390,7 +387,7 @@ When input is provided in the schema, the step executes immediately:
390
387
 
391
388
  ```ts
392
389
  app.flow('auto-onboarding', [
393
- { id: 'get-email', input: 'default@example.com' }, // input provided → no pause
390
+ { id: 'get-email', input: 'default@example.com' }, // input provided → no pause
394
391
  { id: 'send-welcome' },
395
392
  ])
396
393
  ```
@@ -405,7 +402,7 @@ await db.save('workflow:123', JSON.stringify(output.state))
405
402
 
406
403
  // Load and resume
407
404
  const saved = JSON.parse(await db.load('workflow:123'))
408
- const result = await app.resume(saved, userInput)
405
+ const result = await app.resume(saved, { input: userInput })
409
406
  ```
410
407
 
411
408
  ## StepRetriableError
@@ -432,7 +429,7 @@ try {
432
429
  if (error instanceof StepRetriableError) {
433
430
  // Wait and retry
434
431
  await sleep(5000)
435
- await app.resume(error.state, retryInput)
432
+ await app.resume(error.state, { input: retryInput })
436
433
  }
437
434
  }
438
435
  ```
@@ -453,11 +450,7 @@ app.step('add/:n', {
453
450
  },
454
451
  })
455
452
 
456
- app.flow('calculate', [
457
- { id: 'add', input: 10 },
458
- { id: 'multiply', input: 2 },
459
- 'add/5',
460
- ])
453
+ app.flow('calculate', [{ id: 'add', input: 10 }, { id: 'multiply', input: 2 }, 'add/5'])
461
454
 
462
455
  const output = await app.start('calculate', { result: 0 })
463
456
  // result: (0 + 10) * 2 + 5 = 25
@@ -474,20 +467,26 @@ const app = createWfApp<{
474
467
  }>()
475
468
 
476
469
  app.step('validate', {
477
- handler: (ctx) => { ctx.validated = isValid(ctx.data) },
470
+ handler: (ctx) => {
471
+ ctx.validated = isValid(ctx.data)
472
+ },
478
473
  })
479
474
 
480
475
  app.step('to-json', {
481
- handler: (ctx) => { ctx.output = JSON.stringify(ctx.data) },
476
+ handler: (ctx) => {
477
+ ctx.output = JSON.stringify(ctx.data)
478
+ },
482
479
  })
483
480
 
484
481
  app.step('to-csv', {
485
- handler: (ctx) => { ctx.output = toCsv(ctx.data) },
482
+ handler: (ctx) => {
483
+ ctx.output = toCsv(ctx.data)
484
+ },
486
485
  })
487
486
 
488
487
  app.flow('export', [
489
488
  { id: 'validate' },
490
- { condition: '!validated', steps: [] }, // early exit if invalid
489
+ { condition: '!validated', steps: [] }, // early exit if invalid
491
490
  { condition: 'format === "json"', steps: ['to-json'] },
492
491
  { condition: 'format === "csv"', steps: ['to-csv'] },
493
492
  ])
@@ -511,18 +510,13 @@ app.step('confirm', {
511
510
  },
512
511
  })
513
512
 
514
- app.flow('signup', [
515
- { id: 'get-name' },
516
- { id: 'get-email' },
517
- { id: 'get-plan' },
518
- { id: 'confirm' },
519
- ])
513
+ app.flow('signup', [{ id: 'get-name' }, { id: 'get-email' }, { id: 'get-plan' }, { id: 'confirm' }])
520
514
 
521
515
  // Each step pauses for user input
522
516
  let output = await app.start('signup', {})
523
- output = await app.resume(output.state, 'Alice') // name
524
- output = await app.resume(output.state, 'a@b.com') // email
525
- output = await app.resume(output.state, 'pro') // plan
517
+ output = await app.resume(output.state, { input: 'Alice' }) // name
518
+ output = await app.resume(output.state, { input: 'a@b.com' }) // email
519
+ output = await app.resume(output.state, { input: 'pro' }) // plan
526
520
  // output.finished === true
527
521
  ```
528
522
 
@@ -546,10 +540,7 @@ app.step('attempt', {
546
540
  app.flow('resilient-fetch', [
547
541
  {
548
542
  while: 'attempts < 5 && !success',
549
- steps: [
550
- { id: 'attempt' },
551
- { break: 'success' },
552
- ],
543
+ steps: [{ id: 'attempt' }, { break: 'success' }],
553
544
  },
554
545
  ])
555
546
 
@@ -572,7 +563,7 @@ const output = await app.start('resilient-fetch', {
572
563
  ## Gotchas
573
564
 
574
565
  - **Conditions access context properties directly** — The condition `'result > 10'` checks `context.result`, not a local variable. The entire context is the evaluation scope.
575
- - **Input is only for the first step on start** — When calling `app.start(id, ctx, input)`, the `input` is consumed by the first step. After that, `input` is cleared. Subsequent steps only get input if the workflow pauses and resumes.
566
+ - **Input is only for the first step on start** — When calling `app.start(id, ctx, { input })`, the `input` is consumed by the first step. After that, `input` is cleared. Subsequent steps only get input if the workflow pauses and resumes.
576
567
  - **String handlers are sandboxed** — No access to Node.js APIs, `require`, `import`, `console`, etc. Only `ctx` and `input` are available.
577
568
  - **Step IDs are router paths** — A step ID `'process/items'` is treated as two path segments. Use `'process-items'` if you want a flat ID.
578
569
  - **Flow `init` runs in context** — The init function has access to composables (`useWfState()`, `useRouteParams()`, etc.) because it runs inside the async event context.