@usearazzo/runner 1.0.1-alpha.14 → 1.0.1-alpha.16

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/CHANGELOG.md CHANGED
@@ -3,6 +3,18 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [1.0.1-alpha.16](https://github.com/usearazzo/arazzo-toolkit/compare/v1.0.1-alpha.15...v1.0.1-alpha.16) (2026-10-28)
7
+
8
+ ### Bug Fixes
9
+
10
+ - **runner:** merge workflow default actions into steps by name ([#288](https://github.com/usearazzo/arazzo-toolkit/issues/288)) ([8ee0ba3](https://github.com/usearazzo/arazzo-toolkit/commit/8ee0ba387c475fef329c7d094e10ed3b2b0753c1)), closes [#117](https://github.com/usearazzo/arazzo-toolkit/issues/117)
11
+
12
+ ## [1.0.1-alpha.15](https://github.com/usearazzo/arazzo-toolkit/compare/v1.0.1-alpha.14...v1.0.1-alpha.15) (2026-10-28)
13
+
14
+ ### Bug Fixes
15
+
16
+ - **runner:** reject an unreadable successCriteria before any request ([#284](https://github.com/usearazzo/arazzo-toolkit/issues/284)) ([11662f5](https://github.com/usearazzo/arazzo-toolkit/commit/11662f5e603909e356e95f0daa85a7e245667920)), closes [#127](https://github.com/usearazzo/arazzo-toolkit/issues/127)
17
+
6
18
  ## [1.0.1-alpha.14](https://github.com/usearazzo/arazzo-toolkit/compare/v1.0.1-alpha.13...v1.0.1-alpha.14) (2026-10-27)
7
19
 
8
20
  ### Bug Fixes
@@ -12097,8 +12097,10 @@ __webpack_require__.r(__webpack_exports__);
12097
12097
  /* harmony import */ var _action_ActionResolver_ts__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(51097);
12098
12098
  /* harmony import */ var _OpenAPIOperationLocatorNormalizer_ts__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(7308);
12099
12099
  /* harmony import */ var _errors_ExecutionError_ts__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(17658);
12100
- /* harmony import */ var _errors_RuntimeExpressionError_ts__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(48770);
12101
- /* harmony import */ var _abort_ts__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(99628);
12100
+ /* harmony import */ var _errors_ResolverError_ts__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(8696);
12101
+ /* harmony import */ var _errors_RuntimeExpressionError_ts__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(48770);
12102
+ /* harmony import */ var _abort_ts__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(99628);
12103
+
12102
12104
 
12103
12105
 
12104
12106
 
@@ -12231,6 +12233,7 @@ class StepExecutor {
12231
12233
  reason: 'workflow-step'
12232
12234
  });
12233
12235
  }
12236
+ this.assertSuccessCriteria(step);
12234
12237
 
12235
12238
  // locate which operation the step invokes — reduced to a (document, JSON
12236
12239
  // Pointer) locator that the operation executor extracts, normalizes,
@@ -12252,8 +12255,8 @@ class StepExecutor {
12252
12255
  // still reach this line — and this is the last moment before the step has a
12253
12256
  // live side effect. The signal stays in the bag, so a request already in
12254
12257
  // flight is aborted by the transport as before.
12255
- const signal = (0,_abort_ts__WEBPACK_IMPORTED_MODULE_12__.readAbortSignal)(executeOptions);
12256
- (0,_abort_ts__WEBPACK_IMPORTED_MODULE_12__.throwIfAborted)(signal, {
12258
+ const signal = (0,_abort_ts__WEBPACK_IMPORTED_MODULE_13__.readAbortSignal)(executeOptions);
12259
+ (0,_abort_ts__WEBPACK_IMPORTED_MODULE_13__.throwIfAborted)(signal, {
12257
12260
  stepId
12258
12261
  });
12259
12262
 
@@ -12274,7 +12277,7 @@ class StepExecutor {
12274
12277
  // cancelled, it did not: reporting it as the abort keeps one error shape
12275
12278
  // whether the run was withdrawn between two steps or mid-flight, and keeps
12276
12279
  // the whole feature from reading differently per transport.
12277
- ;(0,_abort_ts__WEBPACK_IMPORTED_MODULE_12__.throwIfAborted)(signal, {
12280
+ ;(0,_abort_ts__WEBPACK_IMPORTED_MODULE_13__.throwIfAborted)(signal, {
12278
12281
  stepId
12279
12282
  });
12280
12283
  throw error;
@@ -12326,9 +12329,48 @@ class StepExecutor {
12326
12329
  });
12327
12330
  }
12328
12331
 
12332
+ /**
12333
+ * Throws {@link ResolverError} unless the step's `successCriteria` is absent
12334
+ * or a list of Criterion Objects: `malformed-criteria` for one that is
12335
+ * present but not a list, `malformed-criterion` for an entry that is not a
12336
+ * Criterion Object. Skipping an unreadable entry would turn the author's
12337
+ * assertion into a vacuous pass, so it is an authoring error, as an action's
12338
+ * unreadable `criteria` is in {@link ActionResolver}.
12339
+ *
12340
+ * Called before the step's request is sent, so no live side effect precedes
12341
+ * the error. Public because the workflow executor checks every step of a
12342
+ * workflow with it before any of them runs, a step targeting a `workflowId`
12343
+ * included. It passes `workflowId`, which the error then carries: step ids
12344
+ * are only unique within a workflow.
12345
+ */
12346
+ assertSuccessCriteria(step, workflowId) {
12347
+ const criteria = step.successCriteria;
12348
+ if (criteria === undefined) return;
12349
+ const scope = {
12350
+ ...(workflowId === undefined ? {} : {
12351
+ workflowId
12352
+ }),
12353
+ stepId: (0,_speclynx_apidom_core__WEBPACK_IMPORTED_MODULE_0__["default"])(step.stepId),
12354
+ target: 'successCriteria'
12355
+ };
12356
+ if (!(0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_1__.isArrayElement)(criteria)) {
12357
+ throw new _errors_ResolverError_ts__WEBPACK_IMPORTED_MODULE_11__["default"]("A step's `successCriteria` is present but is not a list", {
12358
+ ...scope,
12359
+ reason: 'malformed-criteria'
12360
+ });
12361
+ }
12362
+ if (![...criteria].every(_speclynx_apidom_ns_arazzo_1__WEBPACK_IMPORTED_MODULE_2__.isCriterionElement)) {
12363
+ throw new _errors_ResolverError_ts__WEBPACK_IMPORTED_MODULE_11__["default"]("A step's `successCriteria` contains an entry that is not a Criterion Object", {
12364
+ ...scope,
12365
+ reason: 'malformed-criterion'
12366
+ });
12367
+ }
12368
+ }
12369
+
12329
12370
  /**
12330
12371
  * Evaluates the step's `successCriteria`; all criteria must pass. A step with
12331
- * no criteria succeeds on a received response.
12372
+ * no criteria succeeds on a received response. An unreadable
12373
+ * `successCriteria` throws, see {@link StepExecutor.assertSuccessCriteria}.
12332
12374
  *
12333
12375
  * Public for the same reason as {@link StepExecutor.selectActions}: a step
12334
12376
  * targeting a `workflowId` is run by the workflow executor and never reaches
@@ -12336,15 +12378,12 @@ class StepExecutor {
12336
12378
  * assertion about the step and must be evaluated somewhere.
12337
12379
  */
12338
12380
  evaluateCriteria(step, context) {
12381
+ this.assertSuccessCriteria(step);
12339
12382
  const criteria = step.successCriteria;
12340
- // no (or non-array) successCriteria: the step succeeds on a received response.
12341
- if (!(0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_1__.isArrayElement)(criteria)) return true;
12342
- for (const criterion of criteria) {
12343
- if (!(0,_speclynx_apidom_ns_arazzo_1__WEBPACK_IMPORTED_MODULE_2__.isCriterionElement)(criterion)) continue;
12344
- const met = this.#criterionEvaluator.evaluate(criterion, expression => this.#evaluate(context, expression));
12345
- if (!met) return false;
12346
- }
12347
- return true;
12383
+ if (criteria === undefined) return true;
12384
+
12385
+ // assertSuccessCriteria above guarantees every entry is a Criterion Object
12386
+ return [...criteria].every(criterion => this.#criterionEvaluator.evaluate(criterion, expression => this.#evaluate(context, expression)));
12348
12387
  }
12349
12388
 
12350
12389
  /**
@@ -12377,7 +12416,7 @@ class StepExecutor {
12377
12416
  // components. A condition on an HTTP exchange cannot apply to a step
12378
12417
  // that calls a workflow, so the action does not match; the run does not
12379
12418
  // abort over a default written for the operation steps.
12380
- if (error instanceof _errors_RuntimeExpressionError_ts__WEBPACK_IMPORTED_MODULE_11__["default"] && error.reason === 'unavailable-expression') {
12419
+ if (error instanceof _errors_RuntimeExpressionError_ts__WEBPACK_IMPORTED_MODULE_12__["default"] && error.reason === 'unavailable-expression') {
12381
12420
  return false;
12382
12421
  }
12383
12422
  throw error;
@@ -13279,6 +13318,10 @@ class WorkflowExecutor {
13279
13318
  // at `#result` where it used to be resolved, means the throw lands before
13280
13319
  // the first request rather than after the last.
13281
13320
  this.#validateWorkflowOutputsShape(workflow, workflowId);
13321
+ // and to every step's `successCriteria`, a step calling a workflow
13322
+ // included: an unreadable assertion found at step three must not cost the
13323
+ // run the requests of steps one and two.
13324
+ for (const step of steps) this.#stepExecutor.assertSuccessCriteria(step, workflowId);
13282
13325
  const dependencies = await this.#runDependencies(workflow, invocation, scope);
13283
13326
  if (dependencies.some(dependency => this.#settledFailed(dependency))) {
13284
13327
  // a declared prerequisite did not complete, so this workflow cannot be
@@ -14916,23 +14959,32 @@ class ArazzoWorkflowNormalizer {
14916
14959
  }
14917
14960
 
14918
14961
  /**
14919
- * Inherits the workflow's `successActions` / `failureActions` into each step
14920
- * that declares no `onSuccess` / `onFailure` of its own.
14962
+ * Merges the workflow's `successActions` / `failureActions` into each step's
14963
+ * `onSuccess` / `onFailure`.
14921
14964
  *
14922
- * Per Arazzo 1.0.1 both lists are "applicable for all steps described under
14923
- * this workflow", and a step's own list **overrides** the corresponding
14924
- * workflow one — wholesale, with no per-action merge, which is where this
14925
- * differs from the parameters above. Success and failure fall back
14926
- * independently: a step may override only its `onFailure` and still inherit
14927
- * the workflow's `successActions`.
14965
+ * Per Arazzo both lists are "applicable for all steps described under this
14966
+ * workflow" and "can be overridden at the step level but cannot be removed
14967
+ * there". The required action `name` is what makes both halves hold: a
14968
+ * step's action replaces the workflow action of the same `name`, and every
14969
+ * workflow action the step does not name still applies. The effective list is
14970
+ * the step's own actions in order, then the workflow actions it did not
14971
+ * override, in theirs — order matters, as selection is first-match-wins on
14972
+ * `criteria`. So a step with no list, or with `[]`, gets every workflow
14973
+ * action. The step's own list is kept exactly as written, even a duplicate
14974
+ * `name` in it, which the validator reports: inheritance only adds to it.
14975
+ * Within the workflow's list the first action with a given `name` wins.
14976
+ * Success and failure merge independently.
14928
14977
  *
14929
- * Presence is tested with `hasKey`, not truthiness: a step declaring an empty
14930
- * list (`onSuccess: []`) has *overridden* the default with an empty set of
14931
- * actions, not asked for one — it is skipped, as is a step whose `onSuccess`
14932
- * is present but not a list, for the same reason the parameters pass leaves a
14933
- * malformed list alone. Testing the key is also what makes the pass
14934
- * idempotent: after the first run the step has it, so a workflow reached again
14935
- * through the registry cache is skipped.
14978
+ * An entry without a readable `name` (an unresolved Reusable Object, a
14979
+ * scalar someone put in the list) neither overrides nor is overridden: it
14980
+ * keeps its place, and is added only if that same element is not already in
14981
+ * the list. A step whose `onSuccess` is present but not a list is left
14982
+ * alone, for the same reason the parameters pass leaves a malformed list
14983
+ * alone — overwriting it would erase what makes the document invalid.
14984
+ *
14985
+ * The pass is idempotent, so a workflow reached again through the registry
14986
+ * cache is merged into once: on a second pass every inherited action is
14987
+ * already in the step's list, under its own `name` or as the same element.
14936
14988
  *
14937
14989
  * Unlike parameters there is no step-kind filter — an action names a
14938
14990
  * transition within the workflow, which is as meaningful for a step targeting
@@ -14959,13 +15011,34 @@ class ArazzoWorkflowNormalizer {
14959
15011
  if (!inheritSuccess && !inheritFailure) return;
14960
15012
  for (const step of workflow.steps) {
14961
15013
  if (!(0,_speclynx_apidom_ns_arazzo_1__WEBPACK_IMPORTED_MODULE_1__.isStepElement)(step)) continue;
14962
- if (inheritSuccess && !step.hasKey('onSuccess')) {
14963
- step.onSuccess = new _speclynx_apidom_ns_arazzo_1__WEBPACK_IMPORTED_MODULE_3__["default"]([...successActions]);
15014
+ if (inheritSuccess && (!step.hasKey('onSuccess') || (0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_6__.isArrayElement)(step.onSuccess))) {
15015
+ step.onSuccess = new _speclynx_apidom_ns_arazzo_1__WEBPACK_IMPORTED_MODULE_3__["default"](ArazzoWorkflowNormalizer.#mergeActions([...(step.onSuccess ?? [])], [...successActions]));
15016
+ }
15017
+ if (inheritFailure && (!step.hasKey('onFailure') || (0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_6__.isArrayElement)(step.onFailure))) {
15018
+ step.onFailure = new _speclynx_apidom_ns_arazzo_1__WEBPACK_IMPORTED_MODULE_2__["default"](ArazzoWorkflowNormalizer.#mergeActions([...(step.onFailure ?? [])], [...failureActions]));
14964
15019
  }
14965
- if (inheritFailure && !step.hasKey('onFailure')) {
14966
- step.onFailure = new _speclynx_apidom_ns_arazzo_1__WEBPACK_IMPORTED_MODULE_2__["default"]([...failureActions]);
15020
+ }
15021
+ }
15022
+
15023
+ /**
15024
+ * The step's actions as written, followed by each workflow action whose
15025
+ * `name` neither the step nor an earlier workflow action carries; a nameless
15026
+ * workflow entry is added unless that same element is already present.
15027
+ */
15028
+ static #mergeActions(own, inherited) {
15029
+ const nameOf = action => (0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_6__.isObjectElement)(action) ? (0,_speclynx_apidom_core__WEBPACK_IMPORTED_MODULE_5__["default"])(action.get('name')) : undefined;
15030
+ const names = new Set(own.map(nameOf));
15031
+ const merged = [...own];
15032
+ for (const action of inherited) {
15033
+ const name = nameOf(action);
15034
+ if (typeof name !== 'string') {
15035
+ if (!merged.includes(action)) merged.push(action);
15036
+ } else if (!names.has(name)) {
15037
+ names.add(name);
15038
+ merged.push(action);
14967
15039
  }
14968
15040
  }
15041
+ return merged;
14969
15042
  }
14970
15043
  }
14971
15044
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (ArazzoWorkflowNormalizer);