@gesslar/actioneer 0.2.1 → 0.2.3

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/src/lib/Piper.js CHANGED
@@ -2,20 +2,18 @@
2
2
  * Generic Pipeline - Process items through a series of steps with concurrency control
3
3
  *
4
4
  * This abstraction handles:
5
- * - Concurrent processing with configurable limits using worker pool pattern
6
- * - Pipeline of processing steps executed sequentially per item
5
+ * - Concurrent processing with configurable limits
6
+ * - Pipeline of processing steps
7
+ * - Result categorization (success/warning/error)
7
8
  * - Setup/cleanup lifecycle hooks
8
9
  * - Error handling and reporting
9
- * - Dynamic worker spawning to maintain concurrency
10
10
  */
11
11
 
12
12
  import {Sass, Tantrum, Util} from "@gesslar/toolkit"
13
13
 
14
14
  export default class Piper {
15
- /** @type {(message: string, level?: number, ...args: Array<unknown>) => void} */
16
15
  #debug
17
16
 
18
- /** @type {Map<string, Set<unknown>>} */
19
17
  #lifeCycle = new Map([
20
18
  ["setup", new Set()],
21
19
  ["process", new Set()],
@@ -32,19 +30,14 @@ export default class Piper {
32
30
  }
33
31
 
34
32
  /**
35
- * Add a processing step to the pipeline.
36
- * Each step is executed sequentially per item.
33
+ * Add a processing step to the pipeline
37
34
  *
38
35
  * @param {(context: unknown) => Promise<unknown>|unknown} fn Function that processes an item
39
- * @param {{name: string, required?: boolean}} options Step options (name is required)
36
+ * @param {{name?: string, required?: boolean}} [options] Step options
40
37
  * @param {unknown} [newThis] Optional this binding
41
38
  * @returns {Piper} The pipeline instance (for chaining)
42
- * @throws {Sass} If name is not provided in options
43
39
  */
44
40
  addStep(fn, options = {}, newThis) {
45
- if(options.name == null)
46
- throw Sass.new("Missing name for step.")
47
-
48
41
  this.#lifeCycle.get("process").add({
49
42
  fn: fn.bind(newThis ?? this),
50
43
  name: options.name || `Step ${this.#lifeCycle.get("process").size + 1}`,
@@ -82,70 +75,33 @@ export default class Piper {
82
75
  }
83
76
 
84
77
  /**
85
- * Process items through the pipeline with concurrency control using a worker pool pattern.
86
- * Workers are spawned up to maxConcurrent limit, and as workers complete, new workers
87
- * are spawned to maintain concurrency until all items are processed.
88
- *
89
- * This implementation uses dynamic worker spawning to maintain concurrency:
90
- * - Initial workers are spawned up to maxConcurrent limit
91
- * - As each worker completes (success OR failure), a replacement worker is spawned if items remain
92
- * - Worker spawning occurs in finally block to ensure resilience to individual worker failures
93
- * - All results are collected with {ok, value} or {ok: false, error} structure
94
- * - Processing continues even if individual workers fail, collecting all errors
78
+ * Process items through the pipeline with concurrency control
95
79
  *
96
80
  * @param {Array<unknown>|unknown} items - Items to process
97
- * @param {number} [maxConcurrent] - Maximum concurrent items to process (default: 10)
98
- * @returns {Promise<Array<{ok: boolean, value?: unknown, error?: Sass}>>} - Results with success/failure status
99
- * @throws {Sass} If setup or teardown fails
81
+ * @param {number} maxConcurrent - Maximum concurrent items to process
82
+ * @returns {Promise<Array<unknown>>} - Collected results from steps
100
83
  */
101
84
  async pipe(items, maxConcurrent = 10) {
102
85
  items = Array.isArray(items)
103
86
  ? items
104
87
  : [items]
105
88
 
106
- const pipeResult = []
107
-
108
- let pendingCount = 0
109
- let resolveAll
110
- const allDone = new Promise(resolve => {
111
- resolveAll = resolve
112
- })
89
+ let itemIndex = 0
90
+ const allResults = []
113
91
 
114
- /**
115
- * Worker function that processes one item and potentially spawns a replacement.
116
- * Uses shift() to atomically retrieve items from the queue, ensuring no duplicate processing.
117
- * Spawns replacement workers in the finally block to guarantee resilience to errors.
118
- *
119
- * @private
120
- */
121
92
  const processWorker = async() => {
122
- if(items.length === 0) {
123
- pendingCount--
124
-
125
- if(pendingCount === 0)
126
- resolveAll()
127
-
128
- return
129
- }
130
-
131
- const item = items.shift()
132
-
133
- try {
134
- const result = await this.#processWorker(item)
135
- pipeResult.push({ok: true, value: result})
136
- } catch(error) {
137
- pipeResult.push({ok: false, error: Sass.new("Processing pipeline item.", error)})
138
- } finally {
139
- // Spawn a replacement worker if there are more items
140
- if(items.length > 0) {
141
- pendingCount++
142
- processWorker() // Don't await - let it run in parallel
93
+ while(true) {
94
+ const currentIndex = itemIndex++
95
+ if(currentIndex >= items.length)
96
+ break
97
+
98
+ const item = items[currentIndex]
99
+ try {
100
+ const result = await this.#processItem(item)
101
+ allResults.push(result)
102
+ } catch(error) {
103
+ throw Sass.new("Processing pipeline item.", error)
143
104
  }
144
-
145
- if(--pendingCount === 0)
146
- resolveAll()
147
-
148
- this.#debug("pendingCount = %o", 2, pendingCount)
149
105
  }
150
106
  }
151
107
 
@@ -156,19 +112,15 @@ export default class Piper {
156
112
 
157
113
  try {
158
114
  // Start workers up to maxConcurrent limit
115
+ const workers = []
159
116
  const workerCount = Math.min(maxConcurrent, items.length)
160
- pendingCount = workerCount
161
117
 
162
- if(workerCount === 0) {
163
- resolveAll() // No items to process
164
- } else {
165
- for(let i = 0; i < workerCount; i++) {
166
- processWorker() // Don't await - let them all run in parallel
167
- }
168
- }
118
+ for(let i = 0; i < workerCount; i++)
119
+ workers.push(processWorker())
169
120
 
170
121
  // Wait for all workers to complete
171
- await allDone
122
+ const processResult = await Util.settleAll(workers)
123
+ this.#processResult("Processing pipeline.", processResult)
172
124
  } finally {
173
125
  // Run cleanup hooks
174
126
  const teardownResult = await Util.settleAll(
@@ -177,31 +129,7 @@ export default class Piper {
177
129
  this.#processResult("Tearing down the pipeline.", teardownResult)
178
130
  }
179
131
 
180
- return pipeResult
181
- }
182
-
183
- /**
184
- * Process a single item through all pipeline steps.
185
- *
186
- * @param {unknown} item The item to process
187
- * @returns {Promise<unknown>} Result from the final step
188
- * @private
189
- */
190
- async #processWorker(item) {
191
- try {
192
- // Execute each step in sequence
193
- let result = item
194
-
195
- for(const step of this.#lifeCycle.get("process")) {
196
- this.#debug("Executing step: %o", 4, step.name)
197
-
198
- result = await step.fn(result) ?? result
199
- }
200
-
201
- return result
202
- } catch(error) {
203
- throw Sass.new("Processing an item.", error)
204
- }
132
+ return allResults
205
133
  }
206
134
 
207
135
  /**
@@ -218,4 +146,29 @@ export default class Piper {
218
146
  settled.filter(r => r.status==="rejected").map(r => r.reason)
219
147
  )
220
148
  }
149
+
150
+ /**
151
+ * Process a single item through all pipeline steps
152
+ *
153
+ * @param {unknown} item The item to process
154
+ * @returns {Promise<unknown>} Result from the final step
155
+ * @private
156
+ */
157
+ async #processItem(item) {
158
+ // Execute each step in sequence
159
+ let result = item
160
+
161
+ for(const step of this.#lifeCycle.get("process")) {
162
+ this.#debug("Executing step: %o", 4, step.name)
163
+
164
+ try {
165
+ result = await step.fn(result) ?? result
166
+ } catch(error) {
167
+ if(step.required)
168
+ throw Sass.new(`Processing required step "${step.name}".`, error)
169
+ }
170
+ }
171
+
172
+ return result
173
+ }
221
174
  }
@@ -21,8 +21,6 @@
21
21
  * @property {ActionFunction|import("./ActionWrapper.js").default} op Operation to execute.
22
22
  * @property {number} [kind] Optional kind flags from {@link ActivityFlags}.
23
23
  * @property {(context: unknown) => boolean|Promise<boolean>} [pred] Loop predicate.
24
- * @property {(context: unknown) => unknown} [splitter] Function to split context for parallel execution (SPLIT activities).
25
- * @property {(originalContext: unknown, splitResults: unknown) => unknown} [rejoiner] Function to rejoin split results (SPLIT activities).
26
24
  */
27
25
  /**
28
26
  * @typedef {(context: unknown) => unknown|Promise<unknown>} ActionFunction
@@ -51,16 +49,10 @@ export default class ActionBuilder {
51
49
  /**
52
50
  * Creates a new ActionBuilder instance with the provided action callback.
53
51
  *
54
- * @param {ActionBuilderAction} [action] - Base action invoked by the runner when a block satisfies the configured structure.
55
- * @param {ActionBuilderConfig} [config] - Options
52
+ * @param {ActionBuilderAction} [action] Base action invoked by the runner when a block satisfies the configured structure.
53
+ * @param {ActionBuilderConfig} [config] Options
56
54
  */
57
55
  constructor(action?: ActionBuilderAction, { tag, debug }?: ActionBuilderConfig)
58
- /**
59
- * Get the builder's tag symbol.
60
- *
61
- * @returns {symbol|null} The tag symbol for this builder instance
62
- */
63
- get tag(): symbol | null
64
56
  /**
65
57
  * Register an activity that the runner can execute.
66
58
  *
@@ -83,16 +75,6 @@ export default class ActionBuilder {
83
75
  * @returns {ActionBuilder}
84
76
  */
85
77
  do(name: string | symbol, kind: number, pred: (context: unknown) => boolean | Promise<boolean>, op: ActionFunction | import('./ActionWrapper.js').default): ActionBuilder
86
- /**
87
- * @overload
88
- * @param {string|symbol} name Activity name
89
- * @param {number} kind Kind bitfield (ACTIVITY.SPLIT).
90
- * @param {(context: unknown) => unknown} splitter Function to split context for parallel execution.
91
- * @param {(originalContext: unknown, splitResults: unknown) => unknown} rejoiner Function to rejoin split results with original context.
92
- * @param {ActionFunction|ActionBuilder} op Operation or nested ActionBuilder to execute on split context.
93
- * @returns {ActionBuilder}
94
- */
95
- do(name: string | symbol, kind: number, splitter: (context: unknown) => unknown, rejoiner: (originalContext: unknown, splitResults: unknown) => unknown, op: ActionFunction | ActionBuilder): ActionBuilder
96
78
  /**
97
79
  * Configure hooks to be loaded from a file when the action is built.
98
80
  *
@@ -110,14 +92,6 @@ export default class ActionBuilder {
110
92
  * @throws {Sass} If hooks have already been configured.
111
93
  */
112
94
  withHooks(hooks: import('./ActionHooks.js').default): ActionBuilder
113
- /**
114
- * Configure hooks using an ActionHooks instance directly (typically used internally).
115
- *
116
- * @param {import("./ActionHooks.js").default} actionHooks Pre-configured ActionHooks instance.
117
- * @returns {ActionBuilder} The builder instance for chaining.
118
- * @throws {Sass} If hooks have already been configured.
119
- */
120
- withActionHooks(actionHooks: import('./ActionHooks.js').default): ActionBuilder
121
95
  /**
122
96
  * Finalises the builder and returns a payload that can be consumed by the
123
97
  * runner.
@@ -125,12 +99,6 @@ export default class ActionBuilder {
125
99
  * @returns {Promise<import("./ActionWrapper.js").default>} Payload consumed by the {@link ActionRunner} constructor.
126
100
  */
127
101
  build(): Promise<import('./ActionWrapper.js').default>
128
- /**
129
- * Check if this builder has ActionHooks configured.
130
- *
131
- * @returns {boolean} True if ActionHooks have been configured.
132
- */
133
- get hasActionHooks(): boolean
134
102
  #private
135
103
  }
136
104
  export type ActionRunner = import('./ActionRunner.js').default
@@ -181,14 +149,6 @@ export type ActivityDefinition = {
181
149
  * Loop predicate.
182
150
  */
183
151
  pred?: ((context: unknown) => boolean | Promise<boolean>) | undefined;
184
- /**
185
- * Function to split context for parallel execution (SPLIT activities).
186
- */
187
- splitter?: ((context: unknown) => unknown) | undefined;
188
- /**
189
- * Function to rejoin split results (SPLIT activities).
190
- */
191
- rejoiner?: ((originalContext: unknown, splitResults: unknown) => unknown) | undefined;
192
152
  }
193
153
  export type ActionFunction = (context: unknown) => unknown | Promise<unknown>
194
154
  //# sourceMappingURL=ActionBuilder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ActionBuilder.d.ts","sourceRoot":"","sources":["../../lib/ActionBuilder.js"],"names":[],"mappings":"AAKA,kEAAkE;AAClE,uEAAuE;AAEvE;;GAEG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;;;;;;;GAUG;AAEH;;GAEG;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH;IA2BE;;;;;OAKG;IACH,qBAHW,mBAAmB,mBACnB,mBAAmB,EAe7B;IA5BD;;;;OAIG;IACH,WAFa,MAAM,GAAC,IAAI,CAIvB;;;;;;;;;;;;;IA8BE,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,MAC9C,cAAc,GAAC,OAAO,oBAAoB,EAAE,OAAO,GACjD,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;IAsDD;;;;;;;OAOG;IACH,yBALW,MAAM,aACN,MAAM,GACJ,aAAa,CAUzB;IAED;;;;;;OAMG;IACH,iBAJW,OAAO,kBAAkB,EAAE,OAAO,GAChC,aAAa,CASzB;IAED;;;;;;OAMG;IACH,6BAJW,OAAO,kBAAkB,EAAE,OAAO,GAChC,aAAa,CASzB;IA2BD;;;;;OAKG;IACH,SAFa,OAAO,CAAC,OAAO,oBAAoB,EAAE,OAAO,CAAC,CAiBzD;IAED;;;;OAIG;IACH,sBAFa,OAAO,CAInB;;CAiCF;2BAlUa,OAAO,mBAAmB,EAAE,OAAO;4BACnC,cAAc,eAAe,EAAE,QAAQ;sBAGxC,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;;;;;WAKjE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;YAYhC,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;;;;0BACpC,OAAO,KAAK,OAAO;;;;kCACX,OAAO,gBAAgB,OAAO,KAAK,OAAO;;6BAI7D,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC"}
1
+ {"version":3,"file":"ActionBuilder.d.ts","sourceRoot":"","sources":["../../lib/ActionBuilder.js"],"names":[],"mappings":"AAKA,kEAAkE;AAClE,uEAAuE;AAEvE;;GAEG;AAEH;;;;GAIG;AAEH;;;;GAIG;AAEH;;;;;;;;GAQG;AAEH;;GAEG;AAEH;;;;;;;;;;;;;;;;;;;GAmBG;AACH;IAaE;;;;;OAKG;IACH,qBAHW,mBAAmB,mBACnB,mBAAmB,EAe7B;;;;;;;;;;;;;IASE,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,MAC9C,cAAc,GAAC,OAAO,oBAAoB,EAAE,OAAO,GACjD,aAAa,CACzB;IA4CD;;;;;;;OAOG;IACH,yBALW,MAAM,aACN,MAAM,GACJ,aAAa,CAYzB;IAED;;;;;;OAMG;IACH,iBAJW,OAAO,kBAAkB,EAAE,OAAO,GAChC,aAAa,CAWzB;IAeD;;;;;OAKG;IACH,SAFa,OAAO,CAAC,OAAO,oBAAoB,EAAE,OAAO,CAAC,CAmBzD;;CAeF;2BA9Oa,OAAO,mBAAmB,EAAE,OAAO;4BACnC,cAAc,eAAe,EAAE,QAAQ;sBAGxC,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;;;;;WAKjE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;YAYhC,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;;6BAI/C,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC"}
@@ -3,10 +3,11 @@
3
3
  */
4
4
  /**
5
5
  * @typedef {object} ActionHooksConfig
6
- * @property {string} [actionKind] Action identifier shared between runner and hooks.
7
- * @property {FileObject|string} [hooksFile] File handle or path used to import the hooks module.
8
- * @property {unknown} [hooksObject] Already-instantiated hooks implementation (skips loading).
6
+ * @property {string} actionKind Action identifier shared between runner and hooks.
7
+ * @property {FileObject} hooksFile File handle used to import the hooks module.
8
+ * @property {unknown} [hooks] Already-instantiated hooks implementation (skips loading).
9
9
  * @property {number} [hookTimeout] Timeout applied to hook execution in milliseconds.
10
+ * @property {DebugFn} debug Logger to emit diagnostics.
10
11
  */
11
12
  /**
12
13
  * @typedef {Record<string, (context: unknown) => Promise<unknown>|unknown>} HookModule
@@ -20,38 +21,37 @@ export default class ActionHooks {
20
21
  /**
21
22
  * Static factory method to create and initialize a hook manager.
22
23
  * Loads hooks from the specified file and returns an initialized instance.
23
- * If a hooksObject is provided in config, it's used directly; otherwise, hooks are loaded from file.
24
+ * Override loadHooks() in subclasses to customize hook loading logic.
24
25
  *
25
- * @param {ActionHooksConfig} config Configuration object with hooks settings
26
+ * @param {ActionHooksConfig} config Same configuration object as constructor
26
27
  * @param {DebugFn} debug The debug function.
27
- * @returns {Promise<ActionHooks>} Initialized hook manager
28
+ * @returns {Promise<ActionHooks|null>} Initialized hook manager or null if no hooks found
28
29
  */
29
- static 'new'(config: ActionHooksConfig, debug: DebugFn): Promise<ActionHooks>
30
+ static 'new'(config: ActionHooksConfig, debug: DebugFn): Promise<ActionHooks | null>
30
31
  /**
31
32
  * Creates a new ActionHook instance.
32
33
  *
33
34
  * @param {ActionHooksConfig} config Configuration values describing how to load the hooks.
34
- * @param {(message: string, level?: number, ...args: Array<unknown>) => void} debug Debug function
35
35
  */
36
- constructor({ actionKind, hooksFile, hooksObject, hookTimeout }: ActionHooksConfig, debug: (message: string, level?: number, ...args: Array<unknown>) => void)
36
+ constructor({ actionKind, hooksFile, hooks, hookTimeout, debug }: ActionHooksConfig)
37
37
  /**
38
38
  * Gets the action identifier.
39
39
  *
40
- * @returns {string|null} Action identifier or instance
40
+ * @returns {string} Action identifier or instance
41
41
  */
42
- get actionKind(): string | null
42
+ get actionKind(): string
43
43
  /**
44
44
  * Gets the hooks file object.
45
45
  *
46
- * @returns {FileObject|null} File object containing hooks
46
+ * @returns {FileObject} File object containing hooks
47
47
  */
48
- get hooksFile(): FileObject | null
48
+ get hooksFile(): FileObject
49
49
  /**
50
50
  * Gets the loaded hooks object.
51
51
  *
52
- * @returns {HookModule|null} Hooks object or null if not loaded
52
+ * @returns {object|null} Hooks object or null if not loaded
53
53
  */
54
- get hooks(): HookModule | null
54
+ get hooks(): object | null
55
55
  /**
56
56
  * Gets the hook execution timeout in milliseconds.
57
57
  *
@@ -71,15 +71,12 @@ export default class ActionHooks {
71
71
  */
72
72
  get cleanup(): (args: object) => unknown | null
73
73
  /**
74
- * Invoke a dynamically-named hook such as `before$foo` or `after$foo`.
75
- * The hook name is constructed by combining the kind with the activity name.
76
- * Symbols are converted to their description. Non-alphanumeric characters are filtered out.
74
+ * Invoke a dynamically-named hook such as `before$foo`.
77
75
  *
78
76
  * @param {'before'|'after'|'setup'|'cleanup'|string} kind Hook namespace.
79
77
  * @param {string|symbol} activityName Activity identifier.
80
78
  * @param {unknown} context Pipeline context supplied to the hook.
81
79
  * @returns {Promise<void>}
82
- * @throws {Sass} If the hook execution fails or exceeds timeout.
83
80
  */
84
81
  callHook(kind: 'before' | 'after' | 'setup' | 'cleanup' | string, activityName: string | symbol, context: unknown): Promise<void>
85
82
  #private
@@ -89,19 +86,23 @@ export type ActionHooksConfig = {
89
86
  /**
90
87
  * Action identifier shared between runner and hooks.
91
88
  */
92
- actionKind?: string | undefined;
89
+ actionKind: string;
93
90
  /**
94
- * File handle or path used to import the hooks module.
91
+ * File handle used to import the hooks module.
95
92
  */
96
- hooksFile?: string | FileObject | undefined;
93
+ hooksFile: FileObject;
97
94
  /**
98
95
  * Already-instantiated hooks implementation (skips loading).
99
96
  */
100
- hooksObject?: unknown;
97
+ hooks?: unknown;
101
98
  /**
102
99
  * Timeout applied to hook execution in milliseconds.
103
100
  */
104
101
  hookTimeout?: number | undefined;
102
+ /**
103
+ * Logger to emit diagnostics.
104
+ */
105
+ debug: DebugFn;
105
106
  }
106
107
  export type HookModule = Record<string, (context: unknown) => Promise<unknown> | unknown>
107
108
  import { FileObject } from '@gesslar/toolkit'
@@ -1 +1 @@
1
- {"version":3,"file":"ActionHooks.d.ts","sourceRoot":"","sources":["../../lib/ActionHooks.js"],"names":[],"mappings":"AAGA;;GAEG;AAEH;;;;;;GAMG;AAEH;;GAEG;AAEH;;;;GAIG;AACH;IAmFE;;;;;;;;OAQG;IACH,qBAJW,iBAAiB,SACjB,OAAO,GACL,OAAO,CAAC,WAAW,CAAC,CA2ChC;IAzHD;;;;;OAKG;IACH,iEAHW,iBAAiB,SACjB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI,EAW5E;IAED;;;;OAIG;IACH,kBAFa,MAAM,GAAC,IAAI,CAIvB;IAED;;;;OAIG;IACH,iBAFa,UAAU,GAAC,IAAI,CAI3B;IAED;;;;OAIG;IACH,aAFa,UAAU,GAAC,IAAI,CAI3B;IAED;;;;OAIG;IACH,eAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,aAFa,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAC,IAAI,CAI1C;IAED;;;;OAIG;IACH,eAFa,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAC,IAAI,CAI1C;IAsDD;;;;;;;;;;OAUG;IACH,eANW,QAAQ,GAAC,OAAO,GAAC,OAAO,GAAC,SAAS,GAAC,MAAM,gBACzC,MAAM,GAAC,MAAM,WACb,OAAO,GACL,OAAO,CAAC,IAAI,CAAC,CAyDzB;;CA6BF;sBAzPY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;;;;;;;;;;;;;kBAOjE,OAAO;;;;;;yBAKR,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,GAAC,OAAO,CAAC;2BAfzB,kBAAkB"}
1
+ {"version":3,"file":"ActionHooks.d.ts","sourceRoot":"","sources":["../../lib/ActionHooks.js"],"names":[],"mappings":"AAGA;;GAEG;AAEH;;;;;;;GAOG;AAEH;;GAEG;AAEH;;;;GAIG;AACH;IA+EE;;;;;;;;OAQG;IACH,qBAJW,iBAAiB,SACjB,OAAO,GACL,OAAO,CAAC,WAAW,GAAC,IAAI,CAAC,CA2CrC;IArHD;;;;OAIG;IACH,kEAFW,iBAAiB,EAQ3B;IAED;;;;OAIG;IACH,kBAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,iBAFa,UAAU,CAItB;IAED;;;;OAIG;IACH,aAFa,MAAM,GAAC,IAAI,CAIvB;IAED;;;;OAIG;IACH,eAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,aAFa,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAC,IAAI,CAI1C;IAED;;;;OAIG;IACH,eAFa,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAC,IAAI,CAI1C;IAsDD;;;;;;;OAOG;IACH,eALW,QAAQ,GAAC,OAAO,GAAC,OAAO,GAAC,SAAS,GAAC,MAAM,gBACzC,MAAM,GAAC,MAAM,WACb,OAAO,GACL,OAAO,CAAC,IAAI,CAAC,CAwDzB;;CAmBF;sBAzOY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;;;;;gBAKjE,MAAM;;;;eACN,UAAU;;;;YACV,OAAO;;;;;;;;WAEP,OAAO;;yBAIR,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,GAAC,OAAO,CAAC;2BAhBzB,kBAAkB"}
@@ -22,12 +22,10 @@ export default class ActionRunner extends Piper {
22
22
  constructor(actionBuilder: import('./ActionBuilder.js').default | null, { debug }?: ActionRunnerOptions)
23
23
  /**
24
24
  * Executes the configured action pipeline.
25
- * Builds the ActionWrapper on first run and caches it for subsequent calls.
26
- * Supports WHILE, UNTIL, and SPLIT activity kinds.
27
25
  *
28
26
  * @param {unknown} context - Seed value passed to the first activity.
29
- * @returns {Promise<unknown>} Final value produced by the pipeline.
30
- * @throws {Sass} When no activities are registered, conflicting activity kinds are used, or execution fails.
27
+ * @returns {Promise<unknown>} Final value produced by the pipeline, or null when a parallel stage reports failures.
28
+ * @throws {Sass} When no activities are registered or required parallel builders are missing.
31
29
  */
32
30
  run(context: unknown): Promise<unknown>
33
31
  #private
@@ -1 +1 @@
1
- {"version":3,"file":"ActionRunner.d.ts","sourceRoot":"","sources":["../../lib/ActionRunner.js"],"names":[],"mappings":"AAMA;;GAEG;AAEH;;;GAGG;AACH;;;;;;GAMG;AACH;IAaE;;;;;OAKG;IACH,2BAHW,OAAO,oBAAoB,EAAE,OAAO,GAAC,IAAI,cACzC,mBAAmB,EAkB7B;IAED;;;;;;;;OAQG;IACH,aAJW,OAAO,GACL,OAAO,CAAC,OAAO,CAAC,CA4E5B;;CAwFF;sBA7NY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;;;;;;;kBAH7D,YAAY"}
1
+ {"version":3,"file":"ActionRunner.d.ts","sourceRoot":"","sources":["../../lib/ActionRunner.js"],"names":[],"mappings":"AAMA;;GAEG;AAEH;;;GAGG;AACH;;;;;;GAMG;AACH;IAUE;;;;;OAKG;IACH,2BAHW,OAAO,oBAAoB,EAAE,OAAO,GAAC,IAAI,cACzC,mBAAmB,EAgB7B;IAED;;;;;;OAMG;IACH,aAJW,OAAO,GACL,OAAO,CAAC,OAAO,CAAC,CA+C5B;;CA2CF;sBA5IY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;;;;;;;kBAH7D,YAAY"}
@@ -1,11 +1,9 @@
1
1
  /**
2
2
  * @typedef {object} WrappedActivityConfig
3
3
  * @property {string|symbol} name Activity identifier used by hooks/logs.
4
- * @property {(context: unknown) => unknown|Promise<unknown>|import("./ActionBuilder.js").default} op Operation or nested ActionBuilder to execute.
4
+ * @property {(context: unknown) => unknown|Promise<unknown>|ActionWrapper} op Operation or nested wrapper to execute.
5
5
  * @property {number} [kind] Optional loop semantic flags.
6
6
  * @property {(context: unknown) => boolean|Promise<boolean>} [pred] Predicate tied to WHILE/UNTIL semantics.
7
- * @property {(context: unknown) => unknown} [splitter] Splitter function for SPLIT activities.
8
- * @property {(originalContext: unknown, splitResults: unknown) => unknown} [rejoiner] Rejoiner function for SPLIT activities.
9
7
  * @property {unknown} [action] Parent action instance supplied when invoking the op.
10
8
  * @property {(message: string, level?: number, ...args: Array<unknown>) => void} [debug] Optional logger reference.
11
9
  */
@@ -19,15 +17,11 @@ export default class ActionWrapper {
19
17
  /**
20
18
  * Create a wrapper from the builder payload.
21
19
  *
22
- * @param {object} config Builder payload containing activities + logger
23
- * @param {Map<string|symbol, WrappedActivityConfig>} config.activities Activities map
24
- * @param {(message: string, level?: number, ...args: Array<unknown>) => void} config.debug Debug function
25
- * @param {object} config.hooks Hooks object
20
+ * @param {{activities: Map<string|symbol, WrappedActivityConfig>, debug: (message: string, level?: number, ...args: Array<unknown>) => void}} init Builder payload containing activities + logger.
26
21
  */
27
- constructor(config: {
22
+ constructor({ activities, hooks, debug }: {
28
23
  activities: Map<string | symbol, WrappedActivityConfig>;
29
24
  debug: (message: string, level?: number, ...args: Array<unknown>) => void;
30
- hooks: object;
31
25
  })
32
26
  /**
33
27
  * Iterator over the registered activities.
@@ -43,9 +37,9 @@ export type WrappedActivityConfig = {
43
37
  */
44
38
  name: string | symbol;
45
39
  /**
46
- * Operation or nested ActionBuilder to execute.
40
+ * Operation or nested wrapper to execute.
47
41
  */
48
- op: (context: unknown) => unknown | Promise<unknown> | import('./ActionBuilder.js').default;
42
+ op: (context: unknown) => unknown | Promise<unknown> | ActionWrapper;
49
43
  /**
50
44
  * Optional loop semantic flags.
51
45
  */
@@ -54,14 +48,6 @@ export type WrappedActivityConfig = {
54
48
  * Predicate tied to WHILE/UNTIL semantics.
55
49
  */
56
50
  pred?: ((context: unknown) => boolean | Promise<boolean>) | undefined;
57
- /**
58
- * Splitter function for SPLIT activities.
59
- */
60
- splitter?: ((context: unknown) => unknown) | undefined;
61
- /**
62
- * Rejoiner function for SPLIT activities.
63
- */
64
- rejoiner?: ((originalContext: unknown, splitResults: unknown) => unknown) | undefined;
65
51
  /**
66
52
  * Parent action instance supplied when invoking the op.
67
53
  */
@@ -1 +1 @@
1
- {"version":3,"file":"ActionWrapper.d.ts","sourceRoot":"","sources":["../../lib/ActionWrapper.js"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AAEH;;GAEG;AAEH;;GAEG;AACH;IAqBE;;;;;;;OAOG;IACH,oBAJG;QAA0D,UAAU,EAA5D,GAAG,CAAC,MAAM,GAAC,MAAM,EAAE,qBAAqB,CAAC;QACkC,KAAK,EAAhF,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;QACnD,KAAK,EAApB,MAAM;KAChB,EAUA;IAOD;;;;OAIG;IACH,kBAFa,gBAAgB,CAI5B;;CACF;;;;;UAtEa,MAAM,GAAC,MAAM;;;;QACb,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,GAAC,OAAO,oBAAoB,EAAE,OAAO;;;;;;;;sBAEzE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC;;;;0BACpC,OAAO,KAAK,OAAO;;;;kCACX,OAAO,gBAAgB,OAAO,KAAK,OAAO;;;;aAC5D,OAAO;;;;uBACG,MAAM,UAAU,MAAM,WAAW,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI;;+BAInE,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC;qBAf1B,eAAe"}
1
+ {"version":3,"file":"ActionWrapper.d.ts","sourceRoot":"","sources":["../../lib/ActionWrapper.js"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH;;GAEG;AAEH;;GAEG;AACH;IAgBE;;;;OAIG;IACH,0CAFW;QAAC,UAAU,EAAE,GAAG,CAAC,MAAM,GAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;QAAC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,IAAI,CAAA;KAAC,EAW5I;IAOD;;;;OAIG;IACH,kBAFa,gBAAgB,CAI5B;;CACF;;;;;UA5Da,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;;+BAInE,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC;qBAb1B,eAAe"}
@@ -1,5 +1,6 @@
1
1
  /**
2
- *
2
+ * Activity bit flags recognised by the builder. The flag decides
3
+ * loop semantics for an activity.
3
4
  */
4
5
  export type ACTIVITY = number
5
6
  /** @typedef {import("./ActionHooks.js").default} ActionHooks */
@@ -9,38 +10,24 @@ export type ACTIVITY = number
9
10
  *
10
11
  * @readonly
11
12
  * @enum {number}
12
- * @property {number} WHILE - Execute activity while predicate returns true (2)
13
- * @property {number} UNTIL - Execute activity until predicate returns false (4)
14
- * @property {number} SPLIT - Execute activity with split/rejoin pattern for parallel execution (8)
15
13
  */
16
14
  export const ACTIVITY: Readonly<{
17
15
  WHILE: number;
18
16
  UNTIL: number;
19
- SPLIT: number;
20
17
  }>
21
18
  export default class Activity {
22
19
  /**
23
20
  * Construct an Activity definition wrapper.
24
21
  *
25
- * @param {object} init - Initial properties describing the activity operation, loop semantics, and predicate
26
- * @param {unknown} init.action - Parent action instance
27
- * @param {string|symbol} init.name - Activity identifier
28
- * @param {(context: unknown) => unknown|Promise<unknown>|import("./ActionBuilder.js").default} init.op - Operation to execute
29
- * @param {number} [init.kind] - Optional loop semantics flags
30
- * @param {(context: unknown) => boolean|Promise<boolean>} [init.pred] - Optional predicate for WHILE/UNTIL
31
- * @param {ActionHooks} [init.hooks] - Optional hooks instance
32
- * @param {(context: unknown) => unknown} [init.splitter] - Optional splitter function for SPLIT activities
33
- * @param {(originalContext: unknown, splitResults: unknown) => unknown} [init.rejoiner] - Optional rejoiner function for SPLIT activities
22
+ * @param {{action: unknown, name: string, op: (context: unknown) => unknown|Promise<unknown>|unknown, kind?: number, pred?: (context: unknown) => boolean|Promise<boolean>, hooks?: ActionHooks}} init - Initial properties describing the activity operation, loop semantics, and predicate
34
23
  */
35
- constructor({ action, name, op, kind, pred, hooks, splitter, rejoiner }: {
24
+ constructor({ action, name, op, kind, pred, hooks }: {
36
25
  action: unknown;
37
- name: string | symbol;
38
- op: (context: unknown) => unknown | Promise<unknown> | import('./ActionBuilder.js').default;
39
- kind?: number | undefined;
40
- pred?: ((context: unknown) => boolean | Promise<boolean>) | undefined;
41
- hooks?: import('./ActionHooks.js').default | undefined;
42
- splitter?: ((context: unknown) => unknown) | undefined;
43
- rejoiner?: ((originalContext: unknown, splitResults: unknown) => unknown) | undefined;
26
+ name: string;
27
+ op: (context: unknown) => unknown | Promise<unknown> | unknown;
28
+ kind?: number;
29
+ pred?: (context: unknown) => boolean | Promise<boolean>;
30
+ hooks?: ActionHooks;
44
31
  })
45
32
  /**
46
33
  * The activity name.
@@ -61,35 +48,17 @@ export default class Activity {
61
48
  */
62
49
  get pred(): (context: unknown) => boolean | Promise<boolean> | undefined
63
50
  /**
64
- * The current context (if set).
65
- *
66
- * @returns {unknown} Current context value
67
- */
68
- get context(): unknown
69
- /**
70
- * The operator kind name (Function or ActionBuilder).
51
+ * The operator kind name (Function or ActionWrapper).
71
52
  *
72
53
  * @returns {string} - Kind name extracted via Data.typeOf
73
54
  */
74
55
  get opKind(): string
75
56
  /**
76
- * The operator to execute (function or nested ActionBuilder).
57
+ * The operator to execute (function or nested wrapper).
77
58
  *
78
- * @returns {(context: unknown) => unknown|Promise<unknown>|import("./ActionBuilder.js").default} - Activity operation
59
+ * @returns {unknown} - Activity operation
79
60
  */
80
- get op(): (context: unknown) => unknown | Promise<unknown> | import('./ActionBuilder.js').default
81
- /**
82
- * The splitter function for SPLIT activities.
83
- *
84
- * @returns {((context: unknown) => unknown)|null} Splitter function or null
85
- */
86
- get splitter(): ((context: unknown) => unknown) | null
87
- /**
88
- * The rejoiner function for SPLIT activities.
89
- *
90
- * @returns {((originalContext: unknown, splitResults: unknown) => unknown)|null} Rejoiner function or null
91
- */
92
- get rejoiner(): ((originalContext: unknown, splitResults: unknown) => unknown) | null
61
+ get op(): unknown
93
62
  /**
94
63
  * The action instance this activity belongs to.
95
64
  *
@@ -100,22 +69,18 @@ export default class Activity {
100
69
  * Execute the activity with before/after hooks.
101
70
  *
102
71
  * @param {unknown} context - Mutable context flowing through the pipeline
103
- * @returns {Promise<unknown>} - Activity result
72
+ * @returns {Promise<{activityResult: unknown}>} - Activity result wrapper with new context
104
73
  */
105
- run(context: unknown): Promise<unknown>
74
+ run(context: unknown): Promise<{
75
+ activityResult: unknown;
76
+ }>
106
77
  /**
107
78
  * Attach hooks to this activity instance.
108
79
  *
109
- * @param {ActionHooks} hooks - Hooks instance with optional before$/after$ methods
80
+ * @param {unknown} hooks - Hooks instance with optional before$/after$ methods
110
81
  * @returns {this} - This activity for chaining
111
82
  */
112
- setActionHooks(hooks: ActionHooks): this
113
- /**
114
- * Get the hooks instance attached to this activity.
115
- *
116
- * @returns {ActionHooks|null} The hooks instance or null
117
- */
118
- get hooks(): ActionHooks | null
83
+ setActionHooks(hooks: unknown): this
119
84
  #private
120
85
  }
121
86
  export type ActionHooks = import('./ActionHooks.js').default
@@ -1 +1 @@
1
- {"version":3,"file":"Activity.d.ts","sourceRoot":"","sources":["../../lib/Activity.js"],"names":[],"mappings":";;;uBASU,MAAM;AAPhB,gEAAgE;AAEhE;;;;;;;;;GASG;AACH;;;;GAIE;AAEF;IAoBE;;;;;;;;;;;;OAYG;IACH,yEATG;QAAsB,MAAM,EAApB,OAAO;QACa,IAAI,EAAxB,MAAM,GAAC,MAAM;QAC6E,EAAE,EAA5F,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,GAAC,OAAO,oBAAoB,EAAE,OAAO;QACrE,IAAI;QACoC,IAAI,cAAhD,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC;QAC3B,KAAK;QACa,QAAQ,cAAnC,OAAO,KAAK,OAAO;QACuC,QAAQ,sBAA1D,OAAO,gBAAgB,OAAO,KAAK,OAAO;KACtE,EAUA;IAED;;;;OAIG;IACH,YAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,YAFa,MAAM,GAAC,IAAI,CAIvB;IAED;;;;OAIG;IACH,YAFa,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,GAAC,SAAS,CAIpE;IAED;;;;OAIG;IACH,eAFa,OAAO,CAInB;IAED;;;;OAIG;IACH,cAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,UAFa,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,GAAC,OAAO,oBAAoB,EAAE,OAAO,CAI/F;IAED;;;;OAIG;IACH,gBAFa,CAAC,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,GAAC,IAAI,CAIhD;IAED;;;;OAIG;IACH,gBAFa,CAAC,CAAC,eAAe,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,KAAK,OAAO,CAAC,GAAC,IAAI,CAI/E;IAED;;;;OAIG;IACH,cAFa,OAAO,CAInB;IAED;;;;;OAKG;IACH,aAHW,OAAO,GACL,OAAO,CAAC,OAAO,CAAC,CAa5B;IAED;;;;;OAKG;IACH,sBAHW,WAAW,GACT,IAAI,CAOhB;IAED;;;;OAIG;IACH,aAFa,WAAW,GAAC,IAAI,CAI5B;;CACF;0BAvLa,OAAO,kBAAkB,EAAE,OAAO"}
1
+ {"version":3,"file":"Activity.d.ts","sourceRoot":"","sources":["../../lib/Activity.js"],"names":[],"mappings":";;;;uBASU,MAAM;AAPhB,gEAAgE;AAEhE;;;;;;GAMG;AACH;;;GAGE;AAEF;IAQE;;;;OAIG;IACH,qDAFW;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,GAAC,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAAC,KAAK,CAAC,EAAE,WAAW,CAAA;KAAC,EAShM;IAED;;;;OAIG;IACH,YAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,YAFa,MAAM,GAAC,IAAI,CAIvB;IAED;;;;OAIG;IACH,YAFa,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAC,OAAO,CAAC,OAAO,CAAC,GAAC,SAAS,CAIpE;IAED;;;;OAIG;IACH,cAFa,MAAM,CAIlB;IAED;;;;OAIG;IACH,UAFa,OAAO,CAInB;IAED;;;;OAIG;IACH,cAFa,OAAO,CAInB;IAED;;;;;OAKG;IACH,aAHW,OAAO,GACL,OAAO,CAAC;QAAC,cAAc,EAAE,OAAO,CAAA;KAAC,CAAC,CAa9C;IAED;;;;;OAKG;IACH,sBAHW,OAAO,GACL,IAAI,CAOhB;;CACF;0BAzHa,OAAO,kBAAkB,EAAE,OAAO"}