@gesslar/actioneer 3.0.1 → 3.1.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Actioneer
2
2
 
3
- Actioneer is a small, focused action orchestration library for Node.js and browser environments. It provides a fluent builder for composing activities and a concurrent runner with lifecycle hooks and control flow semantics (while/until/if/break/continue). The project is written as ES modules and targets Node 20+ and modern browsers.
3
+ Actioneer is a small, focused action orchestration library for Node.js and browser environments. It provides a fluent builder for composing activities and a concurrent runner with lifecycle hooks and control flow semantics (while/until/if/break/continue). The project is written as ES modules and targets Node 24+ and modern browsers.
4
4
 
5
5
  This repository extracts the action orchestration pieces from a larger codebase and exposes a compact API for building pipelines of work that can run concurrently with hook support and nested pipelines.
6
6
 
@@ -131,623 +131,17 @@ import { ActionBuilder, ActionRunner } from "@gesslar/actioneer"
131
131
 
132
132
  If you'd like more complete typings or additional JSDoc, open an issue or send a PR — contributions welcome.
133
133
 
134
- ## Activity Modes
134
+ ## Documentation
135
135
 
136
- Actioneer supports six distinct execution modes for activities, allowing you to control how operations are executed:
136
+ Full guides and API reference live at **[actioneer.gesslar.io](https://actioneer.gesslar.io)**. Highlights:
137
137
 
138
- ### Execute Once (Default)
139
-
140
- The simplest mode executes an activity exactly once per context:
141
-
142
- ```js
143
- class MyAction {
144
- setup(builder) {
145
- builder.do("processItem", ctx => {
146
- ctx.result = ctx.input * 2
147
- })
148
- }
149
- }
150
- ```
151
-
152
- ### WHILE Mode
153
-
154
- Loops while a predicate returns `true`. The predicate is evaluated **before** each iteration:
155
-
156
- ```js
157
- import { ActionBuilder, ACTIVITY } from "@gesslar/actioneer"
158
-
159
- class CounterAction {
160
- #shouldContinue = (ctx) => ctx.count < 10
161
-
162
- #increment = (ctx) => {
163
- ctx.count += 1
164
- }
165
-
166
- setup(builder) {
167
- builder
168
- .do("initialize", ctx => { ctx.count = 0 })
169
- .do("countUp", ACTIVITY.WHILE, this.#shouldContinue, this.#increment)
170
- .do("finish", ctx => { return ctx.count })
171
- }
172
- }
173
- ```
174
-
175
- The activity will continue executing as long as the predicate returns `true`. Once it returns `false`, execution moves to the next activity.
176
-
177
- ### UNTIL Mode
178
-
179
- Loops until a predicate returns `true`. The predicate is evaluated **after** each iteration:
180
-
181
- ```js
182
- import { ActionBuilder, ACTIVITY } from "@gesslar/actioneer"
183
-
184
- class ProcessorAction {
185
- #queueIsEmpty = (ctx) => ctx.queue.length === 0
186
-
187
- #processItem = (ctx) => {
188
- const item = ctx.queue.shift()
189
- ctx.processed.push(item)
190
- }
191
-
192
- setup(builder) {
193
- builder
194
- .do("initialize", ctx => {
195
- ctx.queue = [1, 2, 3, 4, 5]
196
- ctx.processed = []
197
- })
198
- .do("process", ACTIVITY.UNTIL, this.#queueIsEmpty, this.#processItem)
199
- .do("finish", ctx => { return ctx.processed })
200
- }
201
- }
202
- ```
203
-
204
- The activity executes at least once, then continues while the predicate returns `false`. Once it returns `true`, execution moves to the next activity.
205
-
206
- ### IF Mode
207
-
208
- Conditionally executes an activity based on a predicate. Unlike WHILE/UNTIL, IF executes at most once:
209
-
210
- ```js
211
- import { ActionBuilder, ACTIVITY } from "@gesslar/actioneer"
212
-
213
- class ConditionalAction {
214
- #shouldProcess = (ctx) => ctx.value > 10
215
-
216
- #processLargeValue = (ctx) => {
217
- ctx.processed = ctx.value * 2
218
- }
219
-
220
- setup(builder) {
221
- builder
222
- .do("initialize", ctx => { ctx.value = 15 })
223
- .do("maybeProcess", ACTIVITY.IF, this.#shouldProcess, this.#processLargeValue)
224
- .do("finish", ctx => { return ctx })
225
- }
226
- }
227
- ```
228
-
229
- If the predicate returns `true`, the activity executes once. If `false`, the activity is skipped entirely and execution moves to the next activity.
230
-
231
- ### BREAK Mode
232
-
233
- Breaks out of a WHILE or UNTIL loop when a predicate returns `true`. BREAK must be used inside a nested ActionBuilder within a loop:
234
-
235
- ```js
236
- import { ActionBuilder, ACTIVITY } from "@gesslar/actioneer"
237
-
238
- class BreakExample {
239
- setup(builder) {
240
- builder
241
- .do("initialize", ctx => {
242
- ctx.count = 0
243
- ctx.items = []
244
- })
245
- .do("loop", ACTIVITY.WHILE, ctx => ctx.count < 100,
246
- new ActionBuilder()
247
- .do("increment", ctx => {
248
- ctx.count++
249
- ctx.items.push(ctx.count)
250
- return ctx
251
- })
252
- .do("earlyExit", ACTIVITY.BREAK, ctx => ctx.count >= 5)
253
- )
254
- .do("finish", ctx => { return ctx.items }) // Returns [1, 2, 3, 4, 5]
255
- }
256
- }
257
- ```
258
-
259
- When the BREAK predicate returns `true`, the loop terminates immediately and execution continues with the next activity after the loop.
260
-
261
- **Important:** BREAK only works inside a nested ActionBuilder that is the operation of a WHILE or UNTIL activity. Using BREAK outside of a loop context will throw an error.
262
-
263
- ### CONTINUE Mode
264
-
265
- Skips the remaining activities in the current loop iteration and continues to the next iteration. Like BREAK, CONTINUE must be used inside a nested ActionBuilder within a loop:
266
-
267
- ```js
268
- import { ActionBuilder, ACTIVITY } from "@gesslar/actioneer"
269
-
270
- class ContinueExample {
271
- setup(builder) {
272
- builder
273
- .do("initialize", ctx => {
274
- ctx.count = 0
275
- ctx.processed = []
276
- })
277
- .do("loop", ACTIVITY.WHILE, ctx => ctx.count < 5,
278
- new ActionBuilder()
279
- .do("increment", ctx => {
280
- ctx.count++
281
- return ctx
282
- })
283
- .do("skipEvens", ACTIVITY.CONTINUE, ctx => ctx.count % 2 === 0)
284
- .do("process", ctx => {
285
- ctx.processed.push(ctx.count)
286
- return ctx
287
- })
288
- )
289
- .do("finish", ctx => { return ctx.processed }) // Returns [1, 3, 5]
290
- }
291
- }
292
- ```
293
-
294
- When the CONTINUE predicate returns `true`, the remaining activities in that iteration are skipped, and the loop continues with its next iteration (re-evaluating the loop predicate for WHILE, or executing the operation then evaluating for UNTIL).
295
-
296
- **Important:** Like BREAK, CONTINUE only works inside a nested ActionBuilder within a WHILE or UNTIL loop.
297
-
298
- ### Combining Control Flow
299
-
300
- You can combine IF, BREAK, and CONTINUE within the same loop for complex control flow:
301
-
302
- ```js
303
- class CombinedExample {
304
- setup(builder) {
305
- builder
306
- .do("initialize", ctx => {
307
- ctx.count = 0
308
- ctx.results = []
309
- })
310
- .do("loop", ACTIVITY.WHILE, ctx => ctx.count < 100,
311
- new ActionBuilder()
312
- .do("increment", ctx => { ctx.count++; return ctx })
313
- .do("exitAt10", ACTIVITY.BREAK, ctx => ctx.count > 10)
314
- .do("skipEvens", ACTIVITY.CONTINUE, ctx => ctx.count % 2 === 0)
315
- .do("processLarge", ACTIVITY.IF, ctx => ctx.count > 5, ctx => {
316
- ctx.results.push(ctx.count * 10)
317
- return ctx
318
- })
319
- .do("processAll", ctx => {
320
- ctx.results.push(ctx.count)
321
- return ctx
322
- })
323
- )
324
- }
325
- }
326
- // Results: [1, 3, 5, 70, 7, 90, 9]
327
- // - 1, 3, 5: odd numbers <= 5, just pushed
328
- // - 7, 9: odd numbers > 5, pushed with *10 first, then pushed
329
- // - evens skipped by CONTINUE
330
- // - loop exits when count > 10
331
- ```
332
-
333
- ### SPLIT Mode
334
-
335
- Executes with a split/rejoin pattern for parallel execution. This mode requires a splitter function to divide the context and a rejoiner function to recombine results:
336
-
337
- ```js
338
- import { ActionBuilder, ACTIVITY } from "@gesslar/actioneer"
339
-
340
- class ParallelProcessor {
341
- #split = (ctx) => {
342
- // Split context into multiple items for parallel processing
343
- return ctx.items.map(item => ({ item, processedBy: "worker" }))
344
- }
345
-
346
- #rejoin = (originalCtx, splitResults) => {
347
- // Recombine parallel results back into original context
348
- originalCtx.results = splitResults.map(r => r.item)
349
- return originalCtx
350
- }
351
-
352
- #processItem = (ctx) => {
353
- ctx.item = ctx.item.toUpperCase()
354
- }
355
-
356
- setup(builder) {
357
- builder
358
- .do("initialize", ctx => {
359
- ctx.items = ["apple", "banana", "cherry"]
360
- })
361
- .do("parallel", ACTIVITY.SPLIT, this.#split, this.#rejoin, this.#processItem)
362
- .do("finish", ctx => { return ctx.results })
363
- }
364
- }
365
- ```
366
-
367
- **How SPLIT Mode Works:**
368
-
369
- 1. The **splitter** function receives the context and returns an array of contexts (one per parallel task)
370
- 2. Each split context is processed in parallel through the **operation** function
371
- 3. The **rejoiner** function receives the original context and the array of settled results from `Promise.allSettled()`
372
- 4. The rejoiner combines the results and returns the updated context
373
-
374
- **Important: SPLIT uses `Promise.allSettled()`**
375
-
376
- The SPLIT mode uses `Promise.allSettled()` internally to execute parallel operations. This means your **rejoiner** function will receive an array of settlement objects, not the raw context values. Each element in the array will be either:
377
-
378
- - `{ status: "fulfilled", value: <result> }` for successful operations
379
- - `{ status: "rejected", reason: <error> }` for failed operations
380
-
381
- Your rejoiner must handle settled results accordingly. You can process them however you need - check each `status` manually, or use helper utilities like those in `@gesslar/toolkit`:
382
-
383
- ```js
384
- import { Util } from "@gesslar/toolkit"
385
-
386
- #rejoin = (originalCtx, settledResults) => {
387
- // settledResults is an array of settlement objects
388
- // Each has either { status: "fulfilled", value: ... }
389
- // or { status: "rejected", reason: ... }
390
-
391
- // Example: extract only successful results
392
- originalCtx.results = Util.fulfilledValues(settledResults)
393
-
394
- // Example: check for any failures
395
- if (Util.anyRejected(settledResults)) {
396
- originalCtx.errors = Util.rejectedReasons(
397
- Util.settledAndRejected(settledResults)
398
- )
399
- }
400
-
401
- return originalCtx
402
- }
403
- ```
404
-
405
- **Nested Pipelines with SPLIT:**
406
-
407
- You can use nested ActionBuilders with SPLIT mode for complex parallel workflows:
408
-
409
- ```js
410
- class NestedParallel {
411
- #split = (ctx) => ctx.batches.map(batch => ({ batch }))
412
-
413
- #rejoin = (original, results) => {
414
- original.processed = results.flatMap(r => r.batch)
415
- return original
416
- }
417
-
418
- setup(builder) {
419
- builder
420
- .do("parallel", ACTIVITY.SPLIT, this.#split, this.#rejoin,
421
- new ActionBuilder(this)
422
- .do("step1", ctx => { /* ... */ })
423
- .do("step2", ctx => { /* ... */ })
424
- )
425
- }
426
- }
427
- ```
428
-
429
- ### Mode Constraints
430
-
431
- - **Only one mode per activity**: Each activity can have only one mode. Attempting to combine modes will throw an error
432
- - **SPLIT requires both functions**: The splitter and rejoiner are both mandatory for SPLIT mode
433
- - **Predicates must return boolean**: All predicates (WHILE, UNTIL, IF, BREAK, CONTINUE) should return `true` or `false`
434
- - **BREAK/CONTINUE require loop context**: These modes only work inside a nested ActionBuilder within a WHILE or UNTIL loop
435
-
436
- ### Mode Summary Table
437
-
438
- | Mode | Signature | Predicate Timing | Use Case |
439
- | ------------ | ---------------------------------------------------------- | ---------------- | ------------------------------------------- |
440
- | **Default** | `.do(name, operation)` | N/A | Execute once per context |
441
- | **WHILE** | `.do(name, ACTIVITY.WHILE, predicate, operation)` | Before iteration | Loop while condition is true |
442
- | **UNTIL** | `.do(name, ACTIVITY.UNTIL, predicate, operation)` | After iteration | Loop until condition is true |
443
- | **IF** | `.do(name, ACTIVITY.IF, predicate, operation)` | Before execution | Conditional execution (once or skip) |
444
- | **BREAK** | `.do(name, ACTIVITY.BREAK, predicate)` | When reached | Exit enclosing WHILE/UNTIL loop |
445
- | **CONTINUE** | `.do(name, ACTIVITY.CONTINUE, predicate)` | When reached | Skip to next iteration of enclosing loop |
446
- | **SPLIT** | `.do(name, ACTIVITY.SPLIT, splitter, rejoiner, operation)` | N/A | Parallel execution with split/rejoin |
447
-
448
- ## Running Actions: `run()` vs `pipe()`
449
-
450
- ActionRunner provides two methods for executing your action pipelines:
451
-
452
- ### `run(context)` - Single Context Execution
453
-
454
- Executes the pipeline once with a single context. Returns the final context value directly, or throws if an error occurs.
455
-
456
- ```js
457
- const builder = new ActionBuilder(new MyAction())
458
- const runner = new ActionRunner(builder)
459
-
460
- try {
461
- const result = await runner.run({input: "data"})
462
- console.log(result) // Final context value
463
- } catch (error) {
464
- console.error("Pipeline failed:", error)
465
- }
466
- ```
467
-
468
- **Use `run()` when:**
469
-
470
- - Processing a single context
471
- - You want errors to throw immediately
472
- - You prefer traditional try/catch error handling
473
-
474
- ### `pipe(contexts, maxConcurrent)` - Concurrent Batch Execution
475
-
476
- Executes the pipeline concurrently across multiple contexts with a configurable concurrency limit. Returns an array of **settled results** - never throws on individual pipeline failures.
477
-
478
- ```js
479
- const builder = new ActionBuilder(new MyAction())
480
- const runner = new ActionRunner(builder)
481
-
482
- const contexts = [{id: 1}, {id: 2}, {id: 3}]
483
- const results = await runner.pipe(contexts, 4) // Max 4 concurrent
484
-
485
- results.forEach((result, i) => {
486
- if (result.status === "fulfilled") {
487
- console.log(`Context ${i} succeeded:`, result.value)
488
- } else {
489
- console.error(`Context ${i} failed:`, result.reason)
490
- }
491
- })
492
- ```
493
-
494
- **Use `pipe()` when:**
495
-
496
- - Processing multiple contexts in parallel
497
- - You want to control concurrency (default: 10)
498
- - You need all results (both successes and failures)
499
- - Error handling should be at the call site
500
-
501
- **Important: `pipe()` returns settled results**
502
-
503
- The `pipe()` method uses `Promise.allSettled()` internally and returns an array of settlement objects:
504
-
505
- - `{status: "fulfilled", value: <result>}` for successful executions
506
- - `{status: "rejected", reason: <error>}` for failed executions
507
-
508
- This design ensures error handling responsibility stays at the call site - you decide how to handle failures rather than the framework deciding for you.
509
-
510
- ## Pipeline Completion: `done()`
511
-
512
- The `done()` method registers a callback that executes after all activities in the pipeline complete, regardless of whether an error occurred. This is useful for cleanup, finalization, or returning a transformed result.
513
-
514
- ```js
515
- import { ActionBuilder, ActionRunner } from "@gesslar/actioneer"
516
-
517
- class MyAction {
518
- setup(builder) {
519
- builder
520
- .do("step1", ctx => { ctx.a = 1 })
521
- .do("step2", ctx => { ctx.b = 2 })
522
- .done(ctx => {
523
- // This runs after all activities complete
524
- return { total: ctx.a + ctx.b }
525
- })
526
- }
527
- }
528
-
529
- const builder = new ActionBuilder(new MyAction())
530
- const runner = new ActionRunner(builder)
531
- const result = await runner.run({})
532
- console.log(result) // { total: 3 }
533
- ```
534
-
535
- ### Key Behaviors
536
-
537
- - **Always executes**: The `done()` callback runs even if an earlier activity throws an error (similar to `finally` in try/catch)
538
- - **Top-level only**: The callback only runs for the outermost pipeline, not for nested builders inside loops (WHILE/UNTIL). However, for SPLIT activities, `done()` runs for each split context since each is an independent execution
539
- - **Transform the result**: Whatever you return from `done()` becomes the final pipeline result
540
- - **Access to action context**: The callback is bound to the action instance, so `this` refers to your action class
541
- - **Async support**: The callback can be async and return a Promise
542
-
543
- ### Use Cases
544
-
545
- **Cleanup resources:**
546
-
547
- ```js
548
- builder
549
- .do("openConnection", ctx => { ctx.conn = openDb() })
550
- .do("query", ctx => { ctx.data = ctx.conn.query("SELECT *") })
551
- .done(ctx => {
552
- ctx.conn.close() // Always close, even on error
553
- return ctx.data
554
- })
555
- ```
556
-
557
- **Transform the final result:**
558
-
559
- ```js
560
- builder
561
- .do("gather", ctx => { ctx.items = [1, 2, 3] })
562
- .do("process", ctx => { ctx.items = ctx.items.map(x => x * 2) })
563
- .done(ctx => ctx.items) // Return just the items array, not the whole context
564
- ```
565
-
566
- **Logging and metrics:**
567
-
568
- ```js
569
- builder
570
- .do("start", ctx => { ctx.startTime = Date.now() })
571
- .do("work", ctx => { /* ... */ })
572
- .done(ctx => {
573
- console.log(`Pipeline completed in ${Date.now() - ctx.startTime}ms`)
574
- return ctx
575
- })
576
- ```
577
-
578
- ## ActionHooks
579
-
580
- Actioneer supports lifecycle hooks that can execute before and after each activity in your pipeline. Hooks can be configured by file path (Node.js only) or by providing a pre-instantiated hooks object (Node.js and browser).
581
-
582
- ### Hook System Overview
583
-
584
- The hook system allows you to:
585
-
586
- - Execute code before and after each activity in your pipeline
587
- - Implement setup and cleanup logic
588
- - Add observability and logging to your pipelines
589
- - Modify or inspect the context flowing through activities
590
-
591
- ### Configuring Hooks
592
-
593
- #### Browser: Pre-instantiated Hooks
594
-
595
- In browser environments, you must provide pre-instantiated hooks objects:
596
-
597
- ```js
598
- import {ActionBuilder, ActionRunner} from "@gesslar/actioneer"
599
-
600
- class MyActionHooks {
601
- constructor({debug}) {
602
- this.debug = debug
603
- }
604
-
605
- async before$prepare(context) {
606
- this.debug("About to prepare", context)
607
- }
608
-
609
- async after$prepare(context) {
610
- this.debug("Finished preparing", context)
611
- }
612
- }
613
-
614
- const hooks = new MyActionHooks({debug: console.log})
615
-
616
- class MyAction {
617
- setup(builder) {
618
- builder
619
- .withHooks(hooks)
620
- .do("prepare", ctx => { ctx.count = 0 })
621
- .do("work", ctx => { ctx.count += 1 })
622
- }
623
- }
624
-
625
- const builder = new ActionBuilder(new MyAction())
626
- const runner = new ActionRunner(builder)
627
- const result = await runner.pipe([{}], 4)
628
- ```
629
-
630
- #### Node.js: File-based or Pre-instantiated
631
-
632
- **Option 1: Load hooks from a file** (Node.js only)
633
-
634
- ```js
635
- import {ActionBuilder, ActionRunner} from "@gesslar/actioneer"
636
-
637
- class MyAction {
638
- setup(builder) {
639
- builder
640
- .withHooksFile("./hooks/MyActionHooks.js", "MyActionHooks")
641
- .do("prepare", ctx => { ctx.count = 0 })
642
- .do("work", ctx => { ctx.count += 1 })
643
- }
644
- }
645
-
646
- const builder = new ActionBuilder(new MyAction())
647
- const runner = new ActionRunner(builder)
648
- const result = await runner.pipe([{}], 4)
649
- ```
650
-
651
- **Option 2: Provide a pre-instantiated hooks object** (Node.js and browser)
652
-
653
- ```js
654
- import {ActionBuilder, ActionRunner} from "@gesslar/actioneer"
655
- import {MyActionHooks} from "./hooks/MyActionHooks.js"
656
-
657
- const hooks = new MyActionHooks({debug: console.log})
658
-
659
- class MyAction {
660
- setup(builder) {
661
- builder
662
- .withHooks(hooks)
663
- .do("prepare", ctx => { ctx.count = 0 })
664
- .do("work", ctx => { ctx.count += 1 })
665
- }
666
- }
667
-
668
- const builder = new ActionBuilder(new MyAction())
669
- const runner = new ActionRunner(builder)
670
- const result = await runner.pipe([{}], 4)
671
- ```
672
-
673
- ### Writing Hooks
674
-
675
- Hooks are classes exported from a module. The hook methods follow a naming convention: `event$activityName`.
676
-
677
- ```js
678
- // hooks/MyActionHooks.js
679
- export class MyActionHooks {
680
- constructor({ debug }) {
681
- this.debug = debug
682
- }
683
-
684
- // Hook that runs before the "prepare" activity
685
- async before$prepare(context) {
686
- this.debug("About to prepare", context)
687
- }
688
-
689
- // Hook that runs after the "prepare" activity
690
- async after$prepare(context) {
691
- this.debug("Finished preparing", context)
692
- }
693
-
694
- // Hook that runs before the "work" activity
695
- async before$work(context) {
696
- this.debug("Starting work", context)
697
- }
698
-
699
- // Hook that runs after the "work" activity
700
- async after$work(context) {
701
- this.debug("Work complete", context)
702
- }
703
-
704
- // Optional: setup hook runs once at initialization
705
- async setup(args) {
706
- this.debug("Hooks initialized")
707
- }
708
-
709
- // Optional: cleanup hook for teardown
710
- async cleanup(args) {
711
- this.debug("Hooks cleaned up")
712
- }
713
- }
714
- ```
715
-
716
- ### Hook Naming Convention
717
-
718
- Activity names are transformed to hook method names:
719
-
720
- - Spaces are removed and words are camelCased: `"do work"` → `before$doWork` / `after$doWork`
721
- - Non-word characters are stripped: `"step-1"` → `before$step1` / `after$step1`
722
- - First word stays lowercase: `"Prepare Data"` → `before$prepareData` / `after$prepareData`
723
-
724
- ### Hook Timeout
725
-
726
- By default, hooks have a 1-second (1000ms) timeout. If a hook exceeds this timeout, the pipeline will throw a `Sass` error. You can configure the timeout when creating the hooks:
727
-
728
- ```js
729
- new ActionHooks({
730
- actionKind: "MyActionHooks",
731
- hooksFile: "./hooks.js",
732
- hookTimeout: 5000, // 5 seconds
733
- debug: console.log
734
- })
735
- ```
736
-
737
- ### Nested Pipelines and Hooks
738
-
739
- When you nest ActionBuilders (for branching or parallel execution), the parent's hooks are automatically passed to all children, ensuring consistent hook behavior throughout the entire pipeline hierarchy.
740
-
741
- ### Optional TypeScript (local, opt-in)
742
-
743
- This project intentionally avoids committing TypeScript tool configuration. If you'd like to use TypeScript's checker locally (for editor integration or optional JSDoc checking), you can drop a `tsconfig.json` in your working copy — `tsconfig.json` is already in the repository `.gitignore`, so feel free to typecheck yourselves into oblivion.
744
-
745
- Two common local options:
746
-
747
- - Editor/resolve-only (no checking): set `moduleResolution`/`module` and `noEmit` so the editor resolves imports consistently without typechecking.
748
- - Local JSDoc checks: set `allowJs: true` and `checkJs: true` with `noEmit: true` and `strict: false` to let the TypeScript checker validate JSDoc without enforcing strict typing.
749
-
750
- Examples of minimal configs and one-liners to run them are in the project discussion; use them locally if you want an optional safety net. The repository will not require or enforce these files.
138
+ - [Activity Modes](https://actioneer.gesslar.io/guides/activity-modes/) — the six execution modes (`WHILE`, `UNTIL`, `IF`, `BREAK`, `CONTINUE`, `SPLIT`)
139
+ - [Control Flow](https://actioneer.gesslar.io/guides/control-flow/) — `BREAK` and `CONTINUE` inside loops
140
+ - [Parallelism with SPLIT](https://actioneer.gesslar.io/guides/split/) split/rejoin and settled results
141
+ - [run() vs pipe()](https://actioneer.gesslar.io/guides/run-vs-pipe/) — single vs concurrent execution
142
+ - [Finalizing with done()](https://actioneer.gesslar.io/guides/done/) — cleanup and result shaping
143
+ - [Lifecycle Hooks](https://actioneer.gesslar.io/guides/hooks/) — `before$` / `after$` hooks
144
+ - [API Reference](https://actioneer.gesslar.io/reference/action-builder/) — `ActionBuilder`, `ActionRunner`, `Activity`, `ActionHooks`, `Piper`
751
145
 
752
146
  ## Testing
753
147
 
@@ -770,7 +164,7 @@ Tests are organized in `tests/unit/` with one file per class. All tests use Node
770
164
 
771
165
  ## Publishing
772
166
 
773
- This repository is prepared for npm publishing. The package uses ESM and targets Node 20+. The `files` field includes the `src/` folder and types. If you publish, ensure the `version` in `package.json` is updated and you have an npm token configured on the CI runner.
167
+ This repository is prepared for npm publishing. The package uses ESM and targets Node 24+. The `files` field includes the `src/` folder and types. If you publish, ensure the `version` in `package.json` is updated and you have an npm token configured on the CI runner.
774
168
 
775
169
  A simple publish checklist:
776
170
 
@@ -784,17 +178,6 @@ A simple publish checklist:
784
178
 
785
179
  Contributions and issues are welcome. Please open issues for feature requests or bugs. If you're submitting a PR, include tests for new behavior where possible.
786
180
 
787
- ## License
788
-
789
- `@gesslar/actioneer` is released into the public domain under the [Unlicense](LICENSE.txt).
790
-
791
- This package includes or depends on third-party components under their own
792
- licenses:
793
-
794
- | Dependency | License |
795
- | --- | --- |
796
- | [@gesslar/toolkit](https://github.com/gesslar/toolkit) | 0BSD |
797
-
798
181
  ## Most Portum
799
182
 
800
183
  As this is my repo, I have some opinions I would like to express and be made clear.
@@ -804,3 +187,14 @@ As this is my repo, I have some opinions I would like to express and be made cle
804
187
  - Thank you, I love you. BYEBYE!
805
188
 
806
189
  🤗
190
+
191
+ ## License
192
+
193
+ `@gesslar/actioneer` is released under the [0BSD](LICENSE.txt).
194
+
195
+ This package includes or depends on third-party components under their own
196
+ licenses:
197
+
198
+ | Dependency | License |
199
+ | --- | --- |
200
+ | [@gesslar/toolkit](https://github.com/gesslar/toolkit) | 0BSD |
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "gesslar",
6
6
  "url": "https://gesslar.dev"
7
7
  },
8
- "version": "3.0.1",
8
+ "version": "3.1.0",
9
9
  "license": "0BSD",
10
10
  "homepage": "https://github.com/gesslar/toolkit#readme",
11
11
  "repository": {
@@ -41,11 +41,11 @@
41
41
  },
42
42
  "files": [
43
43
  "src/",
44
- "UNLICENSE.txt"
44
+ "LICENSE.txt"
45
45
  ],
46
46
  "sideEffects": false,
47
47
  "engines": {
48
- "node": ">=24.11.0"
48
+ "node": ">=24"
49
49
  },
50
50
  "scripts": {
51
51
  "lint": "eslint src/",
@@ -62,11 +62,11 @@
62
62
  "major": "npm version major"
63
63
  },
64
64
  "dependencies": {
65
- "@gesslar/toolkit": "^5.0.0"
65
+ "@gesslar/toolkit": "^5.5.2"
66
66
  },
67
67
  "devDependencies": {
68
- "@gesslar/uglier": "^2.4.0",
69
- "eslint": "^10.2.0",
70
- "typescript": "^6.0.2"
68
+ "@gesslar/uglier": "^2.4.1",
69
+ "eslint": "^10.4.1",
70
+ "typescript": "^6.0.3"
71
71
  }
72
72
  }
@@ -51,6 +51,16 @@ import {ACTIVITY} from "./Activity.js"
51
51
  * @class ActionBuilder
52
52
  */
53
53
  export default class ActionBuilder {
54
+ /**
55
+ * The ActionHooks class used to resolve hooks. Defaults to the
56
+ * browser-compatible implementation (pre-instantiated hooks only). The Node
57
+ * entry point overrides this with the file-loading subclass so that
58
+ * {@link ActionBuilder#withHooksFile} works.
59
+ *
60
+ * @type {typeof ActionHooks}
61
+ */
62
+ static HooksClass = ActionHooks
63
+
54
64
  /** @type {ActionBuilderAction?} */
55
65
  #action = null
56
66
  /** @type {Map<string|symbol, ActivityDefinition>} */
@@ -334,23 +344,29 @@ export default class ActionBuilder {
334
344
  }
335
345
 
336
346
  async #getHooks() {
337
- const newHooks = ActionHooks.new
347
+ const HooksClass = ActionBuilder.HooksClass
338
348
 
339
349
  const hooks = this.#hooks
340
350
  if(hooks) {
341
- // If hooks is already an ActionHooks instance, use it directly
351
+ // If hooks is already an ActionHooks instance, use it directly.
352
+ // The base class catches subclass instances too.
342
353
  if(hooks instanceof ActionHooks)
343
354
  return hooks
344
355
 
345
356
  // Otherwise, wrap it in a new ActionHooks instance
346
- return await newHooks({hooks}, this.#debug)
357
+ return await HooksClass.new({hooks}, this.#debug)
347
358
  }
348
359
 
349
360
  const hooksFile = this.#hooksFile
350
361
  const hooksKind = this.#hooksKind
351
362
 
363
+ // File loading is only available on the Node HooksClass; the loader keys the
364
+ // class to instantiate off `actionKind`.
352
365
  if(hooksFile && hooksKind)
353
- return await newHooks({hooksFile,hooksKind}, this.#debug)
366
+ return await HooksClass.new(
367
+ {hooksFile, actionKind: hooksKind},
368
+ this.#debug,
369
+ )
354
370
  }
355
371
 
356
372
  /**
@@ -63,7 +63,25 @@ export default class ActionRunner extends Piper {
63
63
  }
64
64
 
65
65
  /**
66
- * Invokes the `setup` lifecycle hook on the raw hooks object, if defined.
66
+ * Builds the ActionWrapper on first use and caches it for subsequent calls.
67
+ *
68
+ * Hooks are configured by the action's `setup()`, which only runs during
69
+ * `build()`. The setup/cleanup lifecycle hooks fire from {@link Piper#pipe}
70
+ * before any item is processed, so the wrapper must be built here too —
71
+ * otherwise the resolved hooks would not yet exist when setup runs.
72
+ *
73
+ * @returns {Promise<import("./ActionWrapper.js").default>} The built wrapper.
74
+ * @private
75
+ */
76
+ async #ensureBuilt() {
77
+ if(!this.#actionWrapper)
78
+ this.#actionWrapper = await this.#actionBuilder.build(this)
79
+
80
+ return this.#actionWrapper
81
+ }
82
+
83
+ /**
84
+ * Invokes the `setup` lifecycle hook on the resolved hooks object, if defined.
67
85
  * Registered as a Piper setup step so it fires before any items are processed.
68
86
  *
69
87
  * @param {unknown} ctx - Value passed by {@link Piper#pipe} (the items array).
@@ -71,29 +89,30 @@ export default class ActionRunner extends Piper {
71
89
  * @private
72
90
  */
73
91
  async #setupHooks(ctx) {
74
- const ab = this.#actionBuilder
75
- const ah = ab?.hooks
92
+ const wrapper = await this.#ensureBuilt()
93
+ const ah = wrapper.hooks
76
94
  const setup = ah?.setup
77
95
 
78
96
  if(setup)
79
- await setup.call(ah, ctx)
97
+ await setup.call(ah.hooks, ctx)
80
98
  }
81
99
 
82
100
  /**
83
- * Invokes the `cleanup` lifecycle hook on the raw hooks object, if defined.
84
- * Registered as a Piper teardown step so it fires after all items are processed.
101
+ * Invokes the `cleanup` lifecycle hook on the resolved hooks object, if
102
+ * defined. Registered as a Piper teardown step so it fires after all items
103
+ * are processed.
85
104
  *
86
105
  * @param {unknown} ctx - Value passed by {@link Piper#pipe} (the items array).
87
106
  * @returns {Promise<void>}
88
107
  * @private
89
108
  */
90
109
  async #cleanupHooks(ctx) {
91
- const ab = this.#actionBuilder
92
- const ah = ab?.hooks
110
+ const wrapper = await this.#ensureBuilt()
111
+ const ah = wrapper.hooks
93
112
  const cleanup = ah?.cleanup
94
113
 
95
114
  if(cleanup)
96
- await cleanup.call(ah, ctx)
115
+ await cleanup.call(ah.hooks, ctx)
97
116
  }
98
117
 
99
118
  /**
@@ -108,10 +127,7 @@ export default class ActionRunner extends Piper {
108
127
  * @throws {Tantrum} When both an activity and the done callback fail.
109
128
  */
110
129
  async run(context, parentWrapper=null) {
111
- if(!this.#actionWrapper)
112
- this.#actionWrapper = await this.#actionBuilder.build(this)
113
-
114
- const actionWrapper = this.#actionWrapper
130
+ const actionWrapper = await this.#ensureBuilt()
115
131
  const activities = Array.from(actionWrapper.activities)
116
132
 
117
133
  let caughtError = null
@@ -113,4 +113,13 @@ export default class ActionWrapper {
113
113
  get action() {
114
114
  return this.#action
115
115
  }
116
+
117
+ /**
118
+ * Get the resolved hooks manager.
119
+ *
120
+ * @returns {import("./ActionHooks.js").default?} Hooks manager or null.
121
+ */
122
+ get hooks() {
123
+ return this.#hooks
124
+ }
116
125
  }
@@ -170,9 +170,9 @@ export default class Piper extends NotifyClass {
170
170
  * @param {Array<unknown>} settled - Results from settleAll
171
171
  * @throws {Tantrum} - If any settled result was rejected
172
172
  */
173
- #processResult(_message, settled) {
173
+ #processResult(message, settled) {
174
174
  if(Promised.hasRejected(settled))
175
- Promised.throw(settled)
175
+ Promised.throw(message, settled)
176
176
  }
177
177
 
178
178
  /**
package/src/index.js CHANGED
@@ -1,9 +1,14 @@
1
1
  // Browser-compatible base classes
2
- export {default as ActionBuilder} from "./browser/lib/ActionBuilder.js"
2
+ import ActionBuilder from "./browser/lib/ActionBuilder.js"
3
+ import ActionHooks from "./lib/ActionHooks.js"
4
+
5
+ // Node-enhanced ActionHooks (extends browser, adds FileObject support). Wiring
6
+ // it into the builder makes withHooksFile() load hooks from disk under the Node
7
+ // entry point, while the browser entry keeps the pre-instantiated-only default.
8
+ ActionBuilder.HooksClass = ActionHooks
9
+
10
+ export {ActionBuilder, ActionHooks}
3
11
  export {default as ActionRunner} from "./browser/lib/ActionRunner.js"
4
12
  export {default as ActionWrapper} from "./browser/lib/ActionWrapper.js"
5
13
  export {default as Activity, ACTIVITY} from "./browser/lib/Activity.js"
6
14
  export {default as Piper} from "./browser/lib/Piper.js"
7
-
8
- // Node-enhanced version (extends browser, adds FileObject support)
9
- export {default as ActionHooks} from "./lib/ActionHooks.js"
@@ -75,11 +75,11 @@ export default class ActionHooks extends BrowserActionHooks {
75
75
 
76
76
  const hooksFile = new FileObject(config.hooksFile)
77
77
 
78
- debug("Loading hooks from %o", 2, hooksFile.uri)
79
- debug("Checking hooks file exists: %o", 2, hooksFile.uri)
78
+ debug("Loading hooks from %o", 2, hooksFile.path)
79
+ debug("Checking hooks file exists: %o", 2, hooksFile.path)
80
80
 
81
81
  if(!await hooksFile.exists)
82
- throw Sass.new(`No such hooks file, ${hooksFile.uri}`)
82
+ throw Sass.new(`No such hooks file, ${hooksFile.path}`)
83
83
 
84
84
  try {
85
85
  const hooksImport = await hooksFile.import()
@@ -100,7 +100,7 @@ export default class ActionHooks extends BrowserActionHooks {
100
100
  // Create instance with loaded hooks
101
101
  return new ActionHooks({...config, hooks, debug})
102
102
  } catch(error) {
103
- debug("Failed to load hooks %o: %o", 1, hooksFile.uri, error.message)
103
+ debug("Failed to load hooks %o: %o", 1, hooksFile.path, error.message)
104
104
 
105
105
  return null
106
106
  }
@@ -44,6 +44,15 @@
44
44
  * @class ActionBuilder
45
45
  */
46
46
  export default class ActionBuilder {
47
+ /**
48
+ * The ActionHooks class used to resolve hooks. Defaults to the
49
+ * browser-compatible implementation (pre-instantiated hooks only). The Node
50
+ * entry point overrides this with the file-loading subclass so that
51
+ * {@link ActionBuilder#withHooksFile} works.
52
+ *
53
+ * @type {typeof ActionHooks}
54
+ */
55
+ static HooksClass: typeof ActionHooks;
47
56
  /**
48
57
  * Creates a new ActionBuilder instance with the provided action callback.
49
58
  *
@@ -1 +1 @@
1
- {"version":3,"file":"ActionBuilder.d.ts","sourceRoot":"","sources":["../../../browser/lib/ActionBuilder.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH;IAkBE;;;;;OAKG;IACH,qBAHW,mBAAmB,mBACnB,mBAAmB,EAkB7B;IAED,yBAEC;;;;;;;;;;;;;;;IAWE,SACQ,MAAM,GAAC,MAAM,MACb,cAAc,GACZ,aAAa,CACzB;;;;;;;;IAGE,SACQ,MAAM,GAAC,MAAM,QACb,MAAM,QACN,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,GAC5C,aAAa,CACzB;;;;;;;;;IAGE,SACQ,MAAM,GAAC,MAAM,QACb,MAAM,QACN,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,MAC9C,cAAc,GAAC,aAAa,GAC1B,aAAa,CACzB;;;;;;;;;;IAGE,SACQ,MAAM,GAAC,MAAM,QACb,MAAM,YACN,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,YAC7B,CAAC,eAAe,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,KAAK,OAAO,MAC5D,cAAc,GAAC,aAAa,GAC1B,aAAa,CACzB;IAkED;;;;;;;OAOG;IACH,yBALW,MAAM,aACN,MAAM,GACJ,aAAa,CAYzB;IAED;;;;;;OAMG;IACH,iBAJW,WAAW,GACT,aAAa,CAgBzB;IAED;;;;;;OAMG;IACH,mBAHW,mBAAmB,GACjB,aAAa,CAczB;IAED;;;;;OAKG;IACH,eAHW,cAAc,GACZ,aAAa,CAOzB;IAeD;;;;;;OAMG;IACH,cAHW,YAAY,GACV,OAAO,CAAC,aAAa,CAAC,CAoClC;IAsBD;;;;;OAKG;IACH,aAFa,MAAM,cAAU,IAAI,CAIhC;;CACF;;;;sBAjWY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;;;;;;;;WAGjE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;YAQhC,mBAAmB,GAAC,IAAI;;;;WACxB,OAAO,GAAC,IAAI;;;;UACZ,MAAM,GAAC,MAAM;;;;QACb,cAAc,GAAC,OAAO,oBAAoB,EAAE,OAAO;;;;;;;;sBAEzC,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC;;;;;6BAE/C,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC;wBA1BnC,kBAAkB;6CAMA,mBAAmB;0BAPnC,oBAAoB"}
1
+ {"version":3,"file":"ActionBuilder.d.ts","sourceRoot":"","sources":["../../../browser/lib/ActionBuilder.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH;IACE;;;;;;;OAOG;IACH,mBAFU,OAAO,WAAW,CAEG;IAmB/B;;;;;OAKG;IACH,qBAHW,mBAAmB,mBACnB,mBAAmB,EAkB7B;IAED,yBAEC;;;;;;;;;;;;;;;IAWE,SACQ,MAAM,GAAC,MAAM,MACb,cAAc,GACZ,aAAa,CACzB;;;;;;;;IAGE,SACQ,MAAM,GAAC,MAAM,QACb,MAAM,QACN,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,GAC5C,aAAa,CACzB;;;;;;;;;IAGE,SACQ,MAAM,GAAC,MAAM,QACb,MAAM,QACN,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,MAC9C,cAAc,GAAC,aAAa,GAC1B,aAAa,CACzB;;;;;;;;;;IAGE,SACQ,MAAM,GAAC,MAAM,QACb,MAAM,YACN,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,YAC7B,CAAC,eAAe,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,KAAK,OAAO,MAC5D,cAAc,GAAC,aAAa,GAC1B,aAAa,CACzB;IAkED;;;;;;;OAOG;IACH,yBALW,MAAM,aACN,MAAM,GACJ,aAAa,CAYzB;IAED;;;;;;OAMG;IACH,iBAJW,WAAW,GACT,aAAa,CAgBzB;IAED;;;;;;OAMG;IACH,mBAHW,mBAAmB,GACjB,aAAa,CAczB;IAED;;;;;OAKG;IACH,eAHW,cAAc,GACZ,aAAa,CAOzB;IAeD;;;;;;OAMG;IACH,cAHW,YAAY,GACV,OAAO,CAAC,aAAa,CAAC,CAoClC;IA4BD;;;;;OAKG;IACH,aAFa,MAAM,cAAU,IAAI,CAIhC;;CACF;;;;sBAjXY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;;;;;;;;WAGjE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;YAQhC,mBAAmB,GAAC,IAAI;;;;WACxB,OAAO,GAAC,IAAI;;;;UACZ,MAAM,GAAC,MAAM;;;;QACb,cAAc,GAAC,OAAO,oBAAoB,EAAE,OAAO;;;;;;;;sBAEzC,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC;;;;;6BAE/C,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC;wBA1BnC,kBAAkB;6CAMA,mBAAmB;0BAPnC,oBAAoB"}
@@ -1 +1 @@
1
- {"version":3,"file":"ActionRunner.d.ts","sourceRoot":"","sources":["../../../browser/lib/ActionRunner.js"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH;;;;;GAKG;AAEH;;;;;;GAMG;AACH;IAaE;;;;;OAKG;IACH,2BAHW,OAAO,oBAAoB,EAAE,OAAO,GAAC,IAAI,cACzC,mBAAmB,EAoB7B;IAoCD;;;;;;;;;;OAUG;IACH,aANW,OAAO,kBACP,OAAO,oBAAoB,EAAE,OAAO,GAAC,IAAI,GACvC,OAAO,CAAC,OAAO,CAAC,CAoJ5B;;CAiGF;sBAlVY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;;;;;;;kBAT7D,YAAY"}
1
+ {"version":3,"file":"ActionRunner.d.ts","sourceRoot":"","sources":["../../../browser/lib/ActionRunner.js"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH;;;;;GAKG;AAEH;;;;;;GAMG;AACH;IAaE;;;;;OAKG;IACH,2BAHW,OAAO,oBAAoB,EAAE,OAAO,GAAC,IAAI,cACzC,mBAAmB,EAoB7B;IAuDD;;;;;;;;;;OAUG;IACH,aANW,OAAO,kBACP,OAAO,oBAAoB,EAAE,OAAO,GAAC,IAAI,GACvC,OAAO,CAAC,OAAO,CAAC,CAiJ5B;;CAiGF;sBAlWY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;;;;;;;kBAT7D,YAAY"}
@@ -58,6 +58,12 @@ export default class ActionWrapper {
58
58
  * @returns {unknown|null} Action instance or null.
59
59
  */
60
60
  get action(): unknown | null;
61
+ /**
62
+ * Get the resolved hooks manager.
63
+ *
64
+ * @returns {import("./ActionHooks.js").default?} Hooks manager or null.
65
+ */
66
+ get hooks(): import("./ActionHooks.js").default | null;
61
67
  #private;
62
68
  }
63
69
  export type WrappedActivityConfig = {
@@ -1 +1 @@
1
- {"version":3,"file":"ActionWrapper.d.ts","sourceRoot":"","sources":["../../../browser/lib/ActionWrapper.js"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH;;;;;;;;GAQG;AAEH;;GAEG;AACH;IAwBE;;;;;;;;;OASG;IACH,sEANG;QAAwD,UAAU,EAA1D,GAAG,CAAC,MAAM,GAAC,MAAM,EAAE,qBAAqB,CAAC;QACgC,KAAK,EAA9E,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;QACxB,KAAK,EAA/C,OAAO,kBAAkB,EAAE,OAAO,OAAC;QAC0B,IAAI,cAAtD,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC;QAChC,MAAM,GAArB,OAAO;KACjB,EAuBA;IAED;;;;;OAKG;IACH,UAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,kBAFa,QAAQ,CAAC,QAAQ,CAAC,CAI9B;IAED;;;;OAIG;IACH,YAFa,CAAC,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAC,IAAI,CAIjE;IAED;;;;OAIG;IACH,cAFa,OAAO,GAAC,IAAI,CAIxB;;CACF;;;;;UAzGa,MAAM,GAAC,MAAM;;;;QACb,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,GAAC,aAAa;;;;;;;;sBAElD,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC;;;;aAC9C,OAAO;;;;uBACG,MAAM,UAAU,MAAM,WAAW,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;;qBAf3D,eAAe"}
1
+ {"version":3,"file":"ActionWrapper.d.ts","sourceRoot":"","sources":["../../../browser/lib/ActionWrapper.js"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH;;;;;;;;GAQG;AAEH;;GAEG;AACH;IAwBE;;;;;;;;;OASG;IACH,sEANG;QAAwD,UAAU,EAA1D,GAAG,CAAC,MAAM,GAAC,MAAM,EAAE,qBAAqB,CAAC;QACgC,KAAK,EAA9E,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;QACxB,KAAK,EAA/C,OAAO,kBAAkB,EAAE,OAAO,OAAC;QAC0B,IAAI,cAAtD,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC;QAChC,MAAM,GAArB,OAAO;KACjB,EAuBA;IAED;;;;;OAKG;IACH,UAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,kBAFa,QAAQ,CAAC,QAAQ,CAAC,CAI9B;IAED;;;;OAIG;IACH,YAFa,CAAC,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAC,IAAI,CAIjE;IAED;;;;OAIG;IACH,cAFa,OAAO,GAAC,IAAI,CAIxB;IAED;;;;OAIG;IACH,aAFa,OAAO,kBAAkB,EAAE,OAAO,OAAC,CAI/C;;CACF;;;;;UAlHa,MAAM,GAAC,MAAM;;;;QACb,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,GAAC,aAAa;;;;;;;;sBAElD,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC;;;;aAC9C,OAAO;;;;uBACG,MAAM,UAAU,MAAM,WAAW,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;;qBAf3D,eAAe"}
@@ -1,7 +1,8 @@
1
- export { default as ActionBuilder } from "./browser/lib/ActionBuilder.js";
2
1
  export { default as ActionRunner } from "./browser/lib/ActionRunner.js";
3
2
  export { default as ActionWrapper } from "./browser/lib/ActionWrapper.js";
4
3
  export { default as Piper } from "./browser/lib/Piper.js";
5
- export { default as ActionHooks } from "./lib/ActionHooks.js";
4
+ import ActionBuilder from "./browser/lib/ActionBuilder.js";
5
+ import ActionHooks from "./lib/ActionHooks.js";
6
+ export { ActionBuilder, ActionHooks };
6
7
  export { default as Activity, ACTIVITY } from "./browser/lib/Activity.js";
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.js"],"names":[],"mappings":""}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.js"],"names":[],"mappings":";;;0BAC0B,gCAAgC;wBAClC,sBAAsB"}