@usearazzo/runner 0.0.0-stage → 1.0.1-alpha.11
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 +37 -0
- package/LICENSE +202 -0
- package/NOTICE +20 -0
- package/README.md +163 -2
- package/dist/arazzo-runner.browser.js +113245 -0
- package/dist/arazzo-runner.browser.min.js +1 -0
- package/package.json +95 -4
- package/src/ArazzoRunner.cjs +122 -0
- package/src/ArazzoRunner.mjs +113 -0
- package/src/action/ActionResolver.cjs +160 -0
- package/src/action/ActionResolver.mjs +150 -0
- package/src/assembler/OpenAPI2DocumentAssembler.cjs +111 -0
- package/src/assembler/OpenAPI2DocumentAssembler.mjs +104 -0
- package/src/assembler/OpenAPI30DocumentAssembler.cjs +110 -0
- package/src/assembler/OpenAPI30DocumentAssembler.mjs +103 -0
- package/src/assembler/OpenAPI31DocumentAssembler.cjs +111 -0
- package/src/assembler/OpenAPI31DocumentAssembler.mjs +104 -0
- package/src/assembler/OpenAPIDocumentAssembler.cjs +58 -0
- package/src/assembler/OpenAPIDocumentAssembler.mjs +50 -0
- package/src/client/HTTPClient.cjs +5 -0
- package/src/client/HTTPClient.mjs +1 -0
- package/src/client/HTTPClientFetch.cjs +16 -0
- package/src/client/HTTPClientFetch.mjs +10 -0
- package/src/client/OpenAPIOperationRequest.cjs +5 -0
- package/src/client/OpenAPIOperationRequest.mjs +1 -0
- package/src/client/OpenAPIOperationResponse.cjs +42 -0
- package/src/client/OpenAPIOperationResponse.mjs +36 -0
- package/src/client/OpenAPIOperationResponseNormalizer.cjs +48 -0
- package/src/client/OpenAPIOperationResponseNormalizer.mjs +40 -0
- package/src/client/ParameterDelivery.cjs +119 -0
- package/src/client/ParameterDelivery.mjs +113 -0
- package/src/constants.cjs +9 -0
- package/src/constants.mjs +3 -0
- package/src/criterion/CriterionEvaluator.cjs +205 -0
- package/src/criterion/CriterionEvaluator.mjs +196 -0
- package/src/criterion/JSONPathCriterionEvaluator.cjs +47 -0
- package/src/criterion/JSONPathCriterionEvaluator.mjs +40 -0
- package/src/criterion/RegexCriterionEvaluator.cjs +67 -0
- package/src/criterion/RegexCriterionEvaluator.mjs +60 -0
- package/src/criterion/SimpleCriterionEvaluator.cjs +50 -0
- package/src/criterion/SimpleCriterionEvaluator.mjs +43 -0
- package/src/criterion/XPathCriterionEvaluator.cjs +117 -0
- package/src/criterion/XPathCriterionEvaluator.mjs +109 -0
- package/src/document/APIDocument.cjs +35 -0
- package/src/document/APIDocument.mjs +30 -0
- package/src/document/ArazzoDocument.cjs +81 -0
- package/src/document/ArazzoDocument.mjs +74 -0
- package/src/document/ArazzoSourceDescriptionIndex.cjs +26 -0
- package/src/document/ArazzoSourceDescriptionIndex.mjs +20 -0
- package/src/document/ArazzoStepIndex.cjs +25 -0
- package/src/document/ArazzoStepIndex.mjs +19 -0
- package/src/document/ArazzoWorkflowIndex.cjs +17 -0
- package/src/document/ArazzoWorkflowIndex.mjs +11 -0
- package/src/document/OpenAPIDocument.cjs +28 -0
- package/src/document/OpenAPIDocument.mjs +21 -0
- package/src/document/OpenAPIOperationIndex.cjs +24 -0
- package/src/document/OpenAPIOperationIndex.mjs +18 -0
- package/src/document/ParameterIdentity.cjs +93 -0
- package/src/document/ParameterIdentity.mjs +88 -0
- package/src/document/openapi-types.cjs +5 -0
- package/src/document/openapi-types.mjs +1 -0
- package/src/errors/ArazzoRunnerError.cjs +10 -0
- package/src/errors/ArazzoRunnerError.mjs +5 -0
- package/src/errors/AssemblerError.cjs +11 -0
- package/src/errors/AssemblerError.mjs +4 -0
- package/src/errors/ClientError.cjs +11 -0
- package/src/errors/ClientError.mjs +4 -0
- package/src/errors/CriterionError.cjs +11 -0
- package/src/errors/CriterionError.mjs +4 -0
- package/src/errors/ExecutionError.cjs +11 -0
- package/src/errors/ExecutionError.mjs +4 -0
- package/src/errors/ExtractionError.cjs +11 -0
- package/src/errors/ExtractionError.mjs +4 -0
- package/src/errors/InvalidEntryDocumentError.cjs +11 -0
- package/src/errors/InvalidEntryDocumentError.mjs +4 -0
- package/src/errors/NormalizationError.cjs +11 -0
- package/src/errors/NormalizationError.mjs +4 -0
- package/src/errors/ResolverError.cjs +11 -0
- package/src/errors/ResolverError.mjs +4 -0
- package/src/errors/RuntimeExpressionError.cjs +11 -0
- package/src/errors/RuntimeExpressionError.mjs +4 -0
- package/src/errors/UnmatchedProviderError.cjs +11 -0
- package/src/errors/UnmatchedProviderError.mjs +4 -0
- package/src/executor/ArazzoWorkflowLocatorNormalizer.cjs +147 -0
- package/src/executor/ArazzoWorkflowLocatorNormalizer.mjs +137 -0
- package/src/executor/OpenAPIOperationExecutor.cjs +458 -0
- package/src/executor/OpenAPIOperationExecutor.mjs +447 -0
- package/src/executor/OpenAPIOperationLocatorNormalizer.cjs +197 -0
- package/src/executor/OpenAPIOperationLocatorNormalizer.mjs +189 -0
- package/src/executor/SourceDescriptionsLocatorNormalizer.cjs +44 -0
- package/src/executor/SourceDescriptionsLocatorNormalizer.mjs +38 -0
- package/src/executor/StepExecutor.cjs +333 -0
- package/src/executor/StepExecutor.mjs +326 -0
- package/src/executor/StepRetryRunner.cjs +226 -0
- package/src/executor/StepRetryRunner.mjs +215 -0
- package/src/executor/StepTransitionInterpreter.cjs +159 -0
- package/src/executor/StepTransitionInterpreter.mjs +151 -0
- package/src/executor/WorkflowCallStack.cjs +116 -0
- package/src/executor/WorkflowCallStack.mjs +106 -0
- package/src/executor/WorkflowExecutor.cjs +1091 -0
- package/src/executor/WorkflowExecutor.mjs +1077 -0
- package/src/executor/abort.cjs +70 -0
- package/src/executor/abort.mjs +60 -0
- package/src/expression/RuntimeExpressionContext.cjs +5 -0
- package/src/expression/RuntimeExpressionContext.mjs +1 -0
- package/src/expression/RuntimeExpressionEvaluator.cjs +337 -0
- package/src/expression/RuntimeExpressionEvaluator.mjs +328 -0
- package/src/extractor/ArazzoStepExtractor.cjs +48 -0
- package/src/extractor/ArazzoStepExtractor.mjs +41 -0
- package/src/extractor/ArazzoWorkflowExtractor.cjs +50 -0
- package/src/extractor/ArazzoWorkflowExtractor.mjs +43 -0
- package/src/extractor/OpenAPIOperationExtractor.cjs +84 -0
- package/src/extractor/OpenAPIOperationExtractor.mjs +77 -0
- package/src/index.cjs +426 -0
- package/src/index.mjs +75 -0
- package/src/normalizer/ArazzoStepNormalizer.cjs +23 -0
- package/src/normalizer/ArazzoStepNormalizer.mjs +17 -0
- package/src/normalizer/ArazzoWorkflowNormalizer.cjs +214 -0
- package/src/normalizer/ArazzoWorkflowNormalizer.mjs +206 -0
- package/src/normalizer/OpenAPI2OperationNormalizer.cjs +128 -0
- package/src/normalizer/OpenAPI2OperationNormalizer.mjs +120 -0
- package/src/normalizer/OpenAPI30OperationNormalizer.cjs +129 -0
- package/src/normalizer/OpenAPI30OperationNormalizer.mjs +121 -0
- package/src/normalizer/OpenAPI31OperationNormalizer.cjs +131 -0
- package/src/normalizer/OpenAPI31OperationNormalizer.mjs +123 -0
- package/src/normalizer/OpenAPIOperationNormalizer.cjs +58 -0
- package/src/normalizer/OpenAPIOperationNormalizer.mjs +50 -0
- package/src/registry/DocumentRegistry.cjs +160 -0
- package/src/registry/DocumentRegistry.mjs +151 -0
- package/src/registry/providers/ArazzoDocumentRegistryProvider.cjs +154 -0
- package/src/registry/providers/ArazzoDocumentRegistryProvider.mjs +146 -0
- package/src/registry/providers/DocumentRegistryProvider.cjs +31 -0
- package/src/registry/providers/DocumentRegistryProvider.mjs +25 -0
- package/src/registry/providers/OpenAPIDocumentRegistryProvider.cjs +122 -0
- package/src/registry/providers/OpenAPIDocumentRegistryProvider.mjs +114 -0
- package/src/resolver/ArazzoValueResolver.cjs +42 -0
- package/src/resolver/ArazzoValueResolver.mjs +37 -0
- package/src/resolver/OpenAPIOperationParameterResolver.cjs +117 -0
- package/src/resolver/OpenAPIOperationParameterResolver.mjs +110 -0
- package/src/resolver/OutputResolver.cjs +71 -0
- package/src/resolver/OutputResolver.mjs +64 -0
- package/src/resolver/RequestBodyResolver.cjs +227 -0
- package/src/resolver/RequestBodyResolver.mjs +220 -0
- package/src/resolver/ResolverScope.cjs +5 -0
- package/src/resolver/ResolverScope.mjs +1 -0
- package/src/resolver/StepParameterResolver.cjs +22 -0
- package/src/resolver/StepParameterResolver.mjs +15 -0
- package/src/resolver/WorkflowParameterResolver.cjs +73 -0
- package/src/resolver/WorkflowParameterResolver.mjs +66 -0
- package/src/state/WorkflowExecutionState.cjs +99 -0
- package/src/state/WorkflowExecutionState.mjs +93 -0
- package/src/vendor/swagger-client.cjs +1 -0
- package/src/vendor/swagger-client.mjs +1 -0
- package/types/runner.d.ts +2410 -0
package/package.json
CHANGED
|
@@ -1,6 +1,97 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usearazzo/runner",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.1-alpha.11",
|
|
4
|
+
"description": "Runner for Arazzo Workflows.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"arazzo",
|
|
7
|
+
"arazzo-specification",
|
|
8
|
+
"runner",
|
|
9
|
+
"execute",
|
|
10
|
+
"executor",
|
|
11
|
+
"workflow",
|
|
12
|
+
"workflows",
|
|
13
|
+
"api",
|
|
14
|
+
"api-workflow"
|
|
15
|
+
],
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public",
|
|
18
|
+
"registry": "https://registry.npmjs.org",
|
|
19
|
+
"provenance": true,
|
|
20
|
+
"tag": "latest",
|
|
21
|
+
"timeout": 60000
|
|
22
|
+
},
|
|
23
|
+
"type": "module",
|
|
24
|
+
"sideEffects": false,
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=20.10.0"
|
|
27
|
+
},
|
|
28
|
+
"unpkg": "./dist/arazzo-runner.browser.min.js",
|
|
29
|
+
"main": "./src/index.cjs",
|
|
30
|
+
"exports": {
|
|
31
|
+
"types": "./types/runner.d.ts",
|
|
32
|
+
"import": "./src/index.mjs",
|
|
33
|
+
"require": "./src/index.cjs"
|
|
34
|
+
},
|
|
35
|
+
"types": "./types/runner.d.ts",
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "npm run clean && npm run build:es && run-p --max-parallel ${CPU_CORES:-2} typescript:declaration build:cjs build:umd:browser",
|
|
38
|
+
"build:es": "npm run build:swagger-client && cross-env BABEL_ENV=es babel src --out-dir src --extensions '.ts' --out-file-extension '.mjs' --root-mode 'upward'",
|
|
39
|
+
"build:cjs": "cross-env BABEL_ENV=cjs babel src --out-dir src --extensions '.ts' --out-file-extension '.cjs' --root-mode 'upward'",
|
|
40
|
+
"build:umd:browser": "cross-env BABEL_ENV=browser webpack --config config/webpack/browser.config.js --progress",
|
|
41
|
+
"build:swagger-client": "webpack --config config/webpack/swagger-client.config.js --progress",
|
|
42
|
+
"lint": "eslint ./",
|
|
43
|
+
"lint:fix": "eslint ./ --fix",
|
|
44
|
+
"clean": "rimraf --glob 'src/**/*.mjs' 'src/**/*.cjs' 'test/**/*.mjs' ./dist ./types",
|
|
45
|
+
"typescript:check-types": "tsc --noEmit",
|
|
46
|
+
"typescript:declaration": "tsc -p tsconfig.declaration.json && api-extractor run -l -c ./config/api-extractor/api-extractor.json",
|
|
47
|
+
"test": "npm run build:es && cross-env BABEL_ENV=es babel test --out-dir test --extensions '.ts' --out-file-extension '.mjs' --root-mode 'upward' && cross-env NODE_ENV=test mocha",
|
|
48
|
+
"test:e2e": "npm run build:es && cross-env BABEL_ENV=es babel test --out-dir test --extensions '.ts' --out-file-extension '.mjs' --root-mode 'upward' && cross-env NODE_ENV=test mocha --config .mocharc.e2e.json",
|
|
49
|
+
"prepack": "copyfiles -u 2 ../../LICENSE . && copyfiles -u 2 ../../NOTICE .",
|
|
50
|
+
"postpack": "rimraf NOTICE LICENSE"
|
|
51
|
+
},
|
|
52
|
+
"repository": {
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "git+https://github.com/usearazzo/arazzo-toolkit.git"
|
|
55
|
+
},
|
|
56
|
+
"author": "Vladimir Gorej <vladimir.gorej@gmail.com>",
|
|
57
|
+
"license": "Apache-2.0",
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"@babel/runtime-corejs3": "^8.0.7",
|
|
60
|
+
"@speclynx/apidom-core": "^6.1.0",
|
|
61
|
+
"@speclynx/apidom-datamodel": "^6.1.0",
|
|
62
|
+
"@speclynx/apidom-error": "^6.1.0",
|
|
63
|
+
"@speclynx/apidom-json-pointer": "^6.1.0",
|
|
64
|
+
"@speclynx/apidom-ns-arazzo-1": "^6.1.0",
|
|
65
|
+
"@speclynx/apidom-ns-openapi-2": "^6.1.0",
|
|
66
|
+
"@speclynx/apidom-ns-openapi-3-0": "^6.1.0",
|
|
67
|
+
"@speclynx/apidom-ns-openapi-3-1": "^6.1.0",
|
|
68
|
+
"@speclynx/apidom-reference": "^6.1.0",
|
|
69
|
+
"@speclynx/apidom-traverse": "^6.1.0",
|
|
70
|
+
"@swaggerexpert/arazzo-criterion": "^1.0.1",
|
|
71
|
+
"@swaggerexpert/arazzo-runtime-expression": "^3.3.0",
|
|
72
|
+
"@swaggerexpert/json-pointer": "^3.0.2",
|
|
73
|
+
"@swaggerexpert/jsonpath": "^4.0.5",
|
|
74
|
+
"@swaggerexpert/media-types": "^1.0.1",
|
|
75
|
+
"@usearazzo/parser": "1.0.1-alpha.11",
|
|
76
|
+
"@usearazzo/resolver": "1.0.1-alpha.11",
|
|
77
|
+
"@xmldom/xmldom": "^0.9.12",
|
|
78
|
+
"fontoxpath": "^3.34.0",
|
|
79
|
+
"ramda": "^0.32.0",
|
|
80
|
+
"ramda-adjunct": "^6.1.0",
|
|
81
|
+
"type-fest": "^5.10.0"
|
|
82
|
+
},
|
|
83
|
+
"files": [
|
|
84
|
+
"src/**/*.mjs",
|
|
85
|
+
"src/**/*.cjs",
|
|
86
|
+
"dist/",
|
|
87
|
+
"types/runner.d.ts",
|
|
88
|
+
"LICENSE",
|
|
89
|
+
"NOTICE",
|
|
90
|
+
"README.md",
|
|
91
|
+
"CHANGELOG.md"
|
|
92
|
+
],
|
|
93
|
+
"devDependencies": {
|
|
94
|
+
"swagger-client": "^3.38.4"
|
|
95
|
+
},
|
|
96
|
+
"gitHead": "3cfffaf0045eff162d73df30f840c35cc593af77"
|
|
97
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.default = void 0;
|
|
8
|
+
var _DocumentRegistry = _interopRequireDefault(require("./registry/DocumentRegistry.cjs"));
|
|
9
|
+
var _OpenAPIOperationExecutor = _interopRequireDefault(require("./executor/OpenAPIOperationExecutor.cjs"));
|
|
10
|
+
var _StepExecutor = _interopRequireDefault(require("./executor/StepExecutor.cjs"));
|
|
11
|
+
var _WorkflowExecutor = _interopRequireDefault(require("./executor/WorkflowExecutor.cjs"));
|
|
12
|
+
var _InvalidEntryDocumentError = _interopRequireDefault(require("./errors/InvalidEntryDocumentError.cjs"));
|
|
13
|
+
/**
|
|
14
|
+
* Options for {@link ArazzoRunner.load}.
|
|
15
|
+
*
|
|
16
|
+
* Every option is a seam of a building block the runner wires: `registry` is
|
|
17
|
+
* the {@link DocumentRegistry} the documents load into (a fresh one with the
|
|
18
|
+
* default providers when omitted), `httpClient` and `requestInterceptor` go to
|
|
19
|
+
* the {@link OpenAPIOperationExecutor}, and the rest go to the
|
|
20
|
+
* {@link WorkflowExecutor}.
|
|
21
|
+
* @public
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Options for the ArazzoRunner constructor.
|
|
26
|
+
* @public
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Runs the workflows of one Arazzo document.
|
|
31
|
+
*
|
|
32
|
+
* A thin facade over the building blocks: it wires a {@link DocumentRegistry},
|
|
33
|
+
* an {@link OpenAPIOperationExecutor}, a {@link StepExecutor} and a
|
|
34
|
+
* {@link WorkflowExecutor} with their defaults, so running a workflow takes a
|
|
35
|
+
* `load` and an `execute`. The building blocks stay public for callers that
|
|
36
|
+
* need to compose them differently.
|
|
37
|
+
* @public
|
|
38
|
+
*/
|
|
39
|
+
class ArazzoRunner {
|
|
40
|
+
document;
|
|
41
|
+
registry;
|
|
42
|
+
#executor;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Loads the entry Arazzo document at `uri` (a file system path or URL) and
|
|
46
|
+
* returns a runner bound to it.
|
|
47
|
+
*
|
|
48
|
+
* @throws UnmatchedProviderError - When no provider can load the document
|
|
49
|
+
* @throws InvalidEntryDocumentError - When the document is not an Arazzo
|
|
50
|
+
* document, or the given registry already backs another entry document
|
|
51
|
+
*/
|
|
52
|
+
static async load(uri, options = {}) {
|
|
53
|
+
const {
|
|
54
|
+
registry = new _DocumentRegistry.default(),
|
|
55
|
+
...rest
|
|
56
|
+
} = options;
|
|
57
|
+
// acquiring a second entry would pin it for good and, through the LRU
|
|
58
|
+
// order, could displace the first as the registry's entry; a registry that
|
|
59
|
+
// already backs one only looks the document up.
|
|
60
|
+
const entry = registry.entryDocument ?? (await registry.acquireEntryDocument(uri));
|
|
61
|
+
const document = await registry.acquire(uri);
|
|
62
|
+
if (document !== entry) {
|
|
63
|
+
throw new _InvalidEntryDocumentError.default(`Document at "${uri}" is not the entry document of the given registry`, {
|
|
64
|
+
uri
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return new ArazzoRunner({
|
|
68
|
+
...rest,
|
|
69
|
+
document: entry,
|
|
70
|
+
registry
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Binds a runner to an entry document the caller already acquired.
|
|
76
|
+
*
|
|
77
|
+
* @throws InvalidEntryDocumentError - When `document` is not the entry document of `registry`
|
|
78
|
+
*/
|
|
79
|
+
constructor(options) {
|
|
80
|
+
const {
|
|
81
|
+
document,
|
|
82
|
+
registry,
|
|
83
|
+
httpClient,
|
|
84
|
+
requestInterceptor,
|
|
85
|
+
...workflowExecutorOptions
|
|
86
|
+
} = options;
|
|
87
|
+
|
|
88
|
+
// a registry pins every entry document it acquires but reports only the
|
|
89
|
+
// first as its entry, so one registry serves one entry document.
|
|
90
|
+
if (registry.entryDocument !== document) {
|
|
91
|
+
throw new _InvalidEntryDocumentError.default(`Document at "${document.uri}" is not the entry document of the given registry`, {
|
|
92
|
+
uri: document.uri
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
const operationExecutor = new _OpenAPIOperationExecutor.default({
|
|
96
|
+
httpClient,
|
|
97
|
+
requestInterceptor
|
|
98
|
+
});
|
|
99
|
+
const stepExecutor = new _StepExecutor.default({
|
|
100
|
+
document,
|
|
101
|
+
registry,
|
|
102
|
+
operationExecutor
|
|
103
|
+
});
|
|
104
|
+
this.document = document;
|
|
105
|
+
this.registry = registry;
|
|
106
|
+
this.#executor = new _WorkflowExecutor.default({
|
|
107
|
+
...workflowExecutorOptions,
|
|
108
|
+
document,
|
|
109
|
+
registry,
|
|
110
|
+
stepExecutor
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Runs the named workflow to completion, returning its outcome; see
|
|
116
|
+
* {@link WorkflowExecutor.execute}.
|
|
117
|
+
*/
|
|
118
|
+
execute(workflowId, options = {}) {
|
|
119
|
+
return this.#executor.execute(workflowId, options);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
var _default = exports.default = ArazzoRunner;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import DocumentRegistry from "./registry/DocumentRegistry.mjs";
|
|
2
|
+
import OpenAPIOperationExecutor from "./executor/OpenAPIOperationExecutor.mjs";
|
|
3
|
+
import StepExecutor from "./executor/StepExecutor.mjs";
|
|
4
|
+
import WorkflowExecutor from "./executor/WorkflowExecutor.mjs";
|
|
5
|
+
import InvalidEntryDocumentError from "./errors/InvalidEntryDocumentError.mjs";
|
|
6
|
+
/**
|
|
7
|
+
* Options for {@link ArazzoRunner.load}.
|
|
8
|
+
*
|
|
9
|
+
* Every option is a seam of a building block the runner wires: `registry` is
|
|
10
|
+
* the {@link DocumentRegistry} the documents load into (a fresh one with the
|
|
11
|
+
* default providers when omitted), `httpClient` and `requestInterceptor` go to
|
|
12
|
+
* the {@link OpenAPIOperationExecutor}, and the rest go to the
|
|
13
|
+
* {@link WorkflowExecutor}.
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Options for the ArazzoRunner constructor.
|
|
18
|
+
* @public
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Runs the workflows of one Arazzo document.
|
|
22
|
+
*
|
|
23
|
+
* A thin facade over the building blocks: it wires a {@link DocumentRegistry},
|
|
24
|
+
* an {@link OpenAPIOperationExecutor}, a {@link StepExecutor} and a
|
|
25
|
+
* {@link WorkflowExecutor} with their defaults, so running a workflow takes a
|
|
26
|
+
* `load` and an `execute`. The building blocks stay public for callers that
|
|
27
|
+
* need to compose them differently.
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
class ArazzoRunner {
|
|
31
|
+
document;
|
|
32
|
+
registry;
|
|
33
|
+
#executor;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Loads the entry Arazzo document at `uri` (a file system path or URL) and
|
|
37
|
+
* returns a runner bound to it.
|
|
38
|
+
*
|
|
39
|
+
* @throws UnmatchedProviderError - When no provider can load the document
|
|
40
|
+
* @throws InvalidEntryDocumentError - When the document is not an Arazzo
|
|
41
|
+
* document, or the given registry already backs another entry document
|
|
42
|
+
*/
|
|
43
|
+
static async load(uri, options = {}) {
|
|
44
|
+
const {
|
|
45
|
+
registry = new DocumentRegistry(),
|
|
46
|
+
...rest
|
|
47
|
+
} = options;
|
|
48
|
+
// acquiring a second entry would pin it for good and, through the LRU
|
|
49
|
+
// order, could displace the first as the registry's entry; a registry that
|
|
50
|
+
// already backs one only looks the document up.
|
|
51
|
+
const entry = registry.entryDocument ?? (await registry.acquireEntryDocument(uri));
|
|
52
|
+
const document = await registry.acquire(uri);
|
|
53
|
+
if (document !== entry) {
|
|
54
|
+
throw new InvalidEntryDocumentError(`Document at "${uri}" is not the entry document of the given registry`, {
|
|
55
|
+
uri
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return new ArazzoRunner({
|
|
59
|
+
...rest,
|
|
60
|
+
document: entry,
|
|
61
|
+
registry
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Binds a runner to an entry document the caller already acquired.
|
|
67
|
+
*
|
|
68
|
+
* @throws InvalidEntryDocumentError - When `document` is not the entry document of `registry`
|
|
69
|
+
*/
|
|
70
|
+
constructor(options) {
|
|
71
|
+
const {
|
|
72
|
+
document,
|
|
73
|
+
registry,
|
|
74
|
+
httpClient,
|
|
75
|
+
requestInterceptor,
|
|
76
|
+
...workflowExecutorOptions
|
|
77
|
+
} = options;
|
|
78
|
+
|
|
79
|
+
// a registry pins every entry document it acquires but reports only the
|
|
80
|
+
// first as its entry, so one registry serves one entry document.
|
|
81
|
+
if (registry.entryDocument !== document) {
|
|
82
|
+
throw new InvalidEntryDocumentError(`Document at "${document.uri}" is not the entry document of the given registry`, {
|
|
83
|
+
uri: document.uri
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
const operationExecutor = new OpenAPIOperationExecutor({
|
|
87
|
+
httpClient,
|
|
88
|
+
requestInterceptor
|
|
89
|
+
});
|
|
90
|
+
const stepExecutor = new StepExecutor({
|
|
91
|
+
document,
|
|
92
|
+
registry,
|
|
93
|
+
operationExecutor
|
|
94
|
+
});
|
|
95
|
+
this.document = document;
|
|
96
|
+
this.registry = registry;
|
|
97
|
+
this.#executor = new WorkflowExecutor({
|
|
98
|
+
...workflowExecutorOptions,
|
|
99
|
+
document,
|
|
100
|
+
registry,
|
|
101
|
+
stepExecutor
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Runs the named workflow to completion, returning its outcome; see
|
|
107
|
+
* {@link WorkflowExecutor.execute}.
|
|
108
|
+
*/
|
|
109
|
+
execute(workflowId, options = {}) {
|
|
110
|
+
return this.#executor.execute(workflowId, options);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
export default ArazzoRunner;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.default = void 0;
|
|
8
|
+
var _apidomDatamodel = require("@speclynx/apidom-datamodel");
|
|
9
|
+
var _apidomNsArazzo = require("@speclynx/apidom-ns-arazzo-1");
|
|
10
|
+
var _ResolverError = _interopRequireDefault(require("../errors/ResolverError.cjs"));
|
|
11
|
+
/**
|
|
12
|
+
* Determines whether a single criterion is met.
|
|
13
|
+
*
|
|
14
|
+
* Bridged to a criterion evaluator
|
|
15
|
+
* (`(criterion) => criterionEvaluator.evaluate(criterion, resolve)`); an
|
|
16
|
+
* unresolvable/failing criterion is `false`, not an error.
|
|
17
|
+
* @public
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The action selected for a step outcome — a Success or Failure Action element.
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Which of a step's two action lists is being resolved. See
|
|
27
|
+
* {@link ActionResolver.#resolveAll} for why it's needed and why it's baked
|
|
28
|
+
* in by the public method rather than taken from the caller. Internal: never
|
|
29
|
+
* leaks into the public API.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Selects the actions to take for a step outcome from its `onSuccess` /
|
|
34
|
+
* `onFailure` list.
|
|
35
|
+
*
|
|
36
|
+
* Actions are tried in order and every one whose `criteria` all pass is
|
|
37
|
+
* returned (an action with no criteria always matches). Action elements are
|
|
38
|
+
* returned as-is — interpreting them (branching on `type`, reading
|
|
39
|
+
* `stepId`/`workflowId`/`retryAfter`/`retryLimit`) is the caller's concern, and
|
|
40
|
+
* keeping them elements preserves the document provenance. The usual caller
|
|
41
|
+
* acts on the first and takes an empty result as "no action matched", applying
|
|
42
|
+
* the path default — the next sequential step on success, break-and-return on
|
|
43
|
+
* failure.
|
|
44
|
+
*
|
|
45
|
+
* A step's list is the only list there is: Reusable Object entries are already
|
|
46
|
+
* inlined by workflow normalization, and the workflow-level
|
|
47
|
+
* `successActions` / `failureActions` a step falls back to are inherited into
|
|
48
|
+
* `onSuccess` / `onFailure` by the same pass, so a well-formed document reaches
|
|
49
|
+
* this point as the step's own list of concrete action elements.
|
|
50
|
+
* @public
|
|
51
|
+
*/
|
|
52
|
+
class ActionResolver {
|
|
53
|
+
/**
|
|
54
|
+
* Returns every `onSuccess` action whose criteria are all met, in list order.
|
|
55
|
+
*
|
|
56
|
+
* The whole matching chain rather than only the first, because the caller
|
|
57
|
+
* needs both: it acts on `[0]`, and the one honoring "retryLimit exhausted
|
|
58
|
+
* prior to subsequent failure actions" walks the rest, falling from an
|
|
59
|
+
* exhausted `retry` to the next matching action without re-evaluating
|
|
60
|
+
* criteria. Empty when the list is absent or nothing matches.
|
|
61
|
+
*
|
|
62
|
+
* `scope` names the step this list belongs to, for a thrown
|
|
63
|
+
* {@link ResolverError}.
|
|
64
|
+
*
|
|
65
|
+
* A well-formed list whose entry is not a Success/Failure Action Object
|
|
66
|
+
* throws rather than being skipped: an unrecognized entry is indistinguishable
|
|
67
|
+
* from a step that deliberately declared no action for it, and the `goto` /
|
|
68
|
+
* `end` its author was reaching for would otherwise never happen without a
|
|
69
|
+
* word said about why.
|
|
70
|
+
*/
|
|
71
|
+
resolveOnSuccess(actions, isCriterionMet, scope) {
|
|
72
|
+
// safe: `#resolveAll` validates every entry as *a* Success/Failure Action
|
|
73
|
+
// Object, not one matching this list's own field, but a well-formed
|
|
74
|
+
// `StepOnSuccessElement` only ever refracts Success Action entries — the
|
|
75
|
+
// apidom refractor types list entries positionally at parse time.
|
|
76
|
+
return this.#resolveAll(actions, isCriterionMet, 'onSuccess', scope);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Returns every `onFailure` action whose criteria are all met, in list order.
|
|
81
|
+
*
|
|
82
|
+
* Same matching and error behavior as {@link ActionResolver.resolveOnSuccess} —
|
|
83
|
+
* see there for the full rationale — mirrored for the step's other list.
|
|
84
|
+
*/
|
|
85
|
+
resolveOnFailure(actions, isCriterionMet, scope) {
|
|
86
|
+
// safe: see the same-named comment in `resolveOnSuccess` above.
|
|
87
|
+
return this.#resolveAll(actions, isCriterionMet, 'onFailure', scope);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Shared implementation behind {@link ActionResolver.resolveOnSuccess} and
|
|
92
|
+
* {@link ActionResolver.resolveOnFailure}.
|
|
93
|
+
*
|
|
94
|
+
* `field` names which of the step's two lists this is, for the same
|
|
95
|
+
* `ResolverError` reason `scope` names the step: the one case that needs it —
|
|
96
|
+
* a list that is present but not a list — is exactly the case where the
|
|
97
|
+
* element's own type no longer distinguishes them. Baked in by the public
|
|
98
|
+
* method rather than taken from the caller.
|
|
99
|
+
*/
|
|
100
|
+
#resolveAll(actions, isCriterionMet, field, scope) {
|
|
101
|
+
if (actions === undefined) return [];
|
|
102
|
+
// present but scalar: walking it would fail as a bare
|
|
103
|
+
// `TypeError: actions is not iterable`.
|
|
104
|
+
if (!(0, _apidomDatamodel.isArrayElement)(actions)) {
|
|
105
|
+
throw new _ResolverError.default(`\`${field}\` is present but is not a list`, {
|
|
106
|
+
...scope,
|
|
107
|
+
target: field,
|
|
108
|
+
reason: 'malformed-actions'
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
const matched = [];
|
|
112
|
+
for (const action of actions) {
|
|
113
|
+
if (!(0, _apidomNsArazzo.isSuccessActionElement)(action) && !(0, _apidomNsArazzo.isFailureActionElement)(action)) {
|
|
114
|
+
throw new _ResolverError.default(`\`${field}\` contains an entry that is not a Success/Failure Action Object`, {
|
|
115
|
+
...scope,
|
|
116
|
+
target: field,
|
|
117
|
+
reason: 'malformed-action-entry'
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
if (this.#criteriaMet(action, isCriterionMet, scope)) {
|
|
121
|
+
matched.push(action);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return matched;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Whether every criterion of the action passes. An action with no criteria
|
|
129
|
+
* matches vacuously.
|
|
130
|
+
*
|
|
131
|
+
* A `criteria` that is present but not a list, or that contains an entry
|
|
132
|
+
* that is not a Criterion Object, throws either way: an entry the resolver
|
|
133
|
+
* cannot read and a container it cannot read are both a document that does
|
|
134
|
+
* not say what its author meant, the same as an unrecognized entry in the
|
|
135
|
+
* action list itself.
|
|
136
|
+
*/
|
|
137
|
+
#criteriaMet(action, isCriterionMet, scope) {
|
|
138
|
+
const criteria = action.criteria;
|
|
139
|
+
if (criteria === undefined) return true;
|
|
140
|
+
if (!(0, _apidomDatamodel.isArrayElement)(criteria)) {
|
|
141
|
+
throw new _ResolverError.default("An action's `criteria` is present but is not a list", {
|
|
142
|
+
...scope,
|
|
143
|
+
target: 'criteria',
|
|
144
|
+
reason: 'malformed-criteria'
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
for (const criterion of criteria) {
|
|
148
|
+
if (!(0, _apidomNsArazzo.isCriterionElement)(criterion)) {
|
|
149
|
+
throw new _ResolverError.default("An action's `criteria` contains an entry that is not a Criterion Object", {
|
|
150
|
+
...scope,
|
|
151
|
+
target: 'criteria',
|
|
152
|
+
reason: 'malformed-criterion'
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
if (!isCriterionMet(criterion)) return false;
|
|
156
|
+
}
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
var _default = exports.default = ActionResolver;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { isArrayElement } from '@speclynx/apidom-datamodel';
|
|
2
|
+
import { isSuccessActionElement, isFailureActionElement, isCriterionElement } from '@speclynx/apidom-ns-arazzo-1';
|
|
3
|
+
import ResolverError from "../errors/ResolverError.mjs";
|
|
4
|
+
/**
|
|
5
|
+
* Determines whether a single criterion is met.
|
|
6
|
+
*
|
|
7
|
+
* Bridged to a criterion evaluator
|
|
8
|
+
* (`(criterion) => criterionEvaluator.evaluate(criterion, resolve)`); an
|
|
9
|
+
* unresolvable/failing criterion is `false`, not an error.
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* The action selected for a step outcome — a Success or Failure Action element.
|
|
14
|
+
* @public
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Which of a step's two action lists is being resolved. See
|
|
18
|
+
* {@link ActionResolver.#resolveAll} for why it's needed and why it's baked
|
|
19
|
+
* in by the public method rather than taken from the caller. Internal: never
|
|
20
|
+
* leaks into the public API.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Selects the actions to take for a step outcome from its `onSuccess` /
|
|
24
|
+
* `onFailure` list.
|
|
25
|
+
*
|
|
26
|
+
* Actions are tried in order and every one whose `criteria` all pass is
|
|
27
|
+
* returned (an action with no criteria always matches). Action elements are
|
|
28
|
+
* returned as-is — interpreting them (branching on `type`, reading
|
|
29
|
+
* `stepId`/`workflowId`/`retryAfter`/`retryLimit`) is the caller's concern, and
|
|
30
|
+
* keeping them elements preserves the document provenance. The usual caller
|
|
31
|
+
* acts on the first and takes an empty result as "no action matched", applying
|
|
32
|
+
* the path default — the next sequential step on success, break-and-return on
|
|
33
|
+
* failure.
|
|
34
|
+
*
|
|
35
|
+
* A step's list is the only list there is: Reusable Object entries are already
|
|
36
|
+
* inlined by workflow normalization, and the workflow-level
|
|
37
|
+
* `successActions` / `failureActions` a step falls back to are inherited into
|
|
38
|
+
* `onSuccess` / `onFailure` by the same pass, so a well-formed document reaches
|
|
39
|
+
* this point as the step's own list of concrete action elements.
|
|
40
|
+
* @public
|
|
41
|
+
*/
|
|
42
|
+
class ActionResolver {
|
|
43
|
+
/**
|
|
44
|
+
* Returns every `onSuccess` action whose criteria are all met, in list order.
|
|
45
|
+
*
|
|
46
|
+
* The whole matching chain rather than only the first, because the caller
|
|
47
|
+
* needs both: it acts on `[0]`, and the one honoring "retryLimit exhausted
|
|
48
|
+
* prior to subsequent failure actions" walks the rest, falling from an
|
|
49
|
+
* exhausted `retry` to the next matching action without re-evaluating
|
|
50
|
+
* criteria. Empty when the list is absent or nothing matches.
|
|
51
|
+
*
|
|
52
|
+
* `scope` names the step this list belongs to, for a thrown
|
|
53
|
+
* {@link ResolverError}.
|
|
54
|
+
*
|
|
55
|
+
* A well-formed list whose entry is not a Success/Failure Action Object
|
|
56
|
+
* throws rather than being skipped: an unrecognized entry is indistinguishable
|
|
57
|
+
* from a step that deliberately declared no action for it, and the `goto` /
|
|
58
|
+
* `end` its author was reaching for would otherwise never happen without a
|
|
59
|
+
* word said about why.
|
|
60
|
+
*/
|
|
61
|
+
resolveOnSuccess(actions, isCriterionMet, scope) {
|
|
62
|
+
// safe: `#resolveAll` validates every entry as *a* Success/Failure Action
|
|
63
|
+
// Object, not one matching this list's own field, but a well-formed
|
|
64
|
+
// `StepOnSuccessElement` only ever refracts Success Action entries — the
|
|
65
|
+
// apidom refractor types list entries positionally at parse time.
|
|
66
|
+
return this.#resolveAll(actions, isCriterionMet, 'onSuccess', scope);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Returns every `onFailure` action whose criteria are all met, in list order.
|
|
71
|
+
*
|
|
72
|
+
* Same matching and error behavior as {@link ActionResolver.resolveOnSuccess} —
|
|
73
|
+
* see there for the full rationale — mirrored for the step's other list.
|
|
74
|
+
*/
|
|
75
|
+
resolveOnFailure(actions, isCriterionMet, scope) {
|
|
76
|
+
// safe: see the same-named comment in `resolveOnSuccess` above.
|
|
77
|
+
return this.#resolveAll(actions, isCriterionMet, 'onFailure', scope);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Shared implementation behind {@link ActionResolver.resolveOnSuccess} and
|
|
82
|
+
* {@link ActionResolver.resolveOnFailure}.
|
|
83
|
+
*
|
|
84
|
+
* `field` names which of the step's two lists this is, for the same
|
|
85
|
+
* `ResolverError` reason `scope` names the step: the one case that needs it —
|
|
86
|
+
* a list that is present but not a list — is exactly the case where the
|
|
87
|
+
* element's own type no longer distinguishes them. Baked in by the public
|
|
88
|
+
* method rather than taken from the caller.
|
|
89
|
+
*/
|
|
90
|
+
#resolveAll(actions, isCriterionMet, field, scope) {
|
|
91
|
+
if (actions === undefined) return [];
|
|
92
|
+
// present but scalar: walking it would fail as a bare
|
|
93
|
+
// `TypeError: actions is not iterable`.
|
|
94
|
+
if (!isArrayElement(actions)) {
|
|
95
|
+
throw new ResolverError(`\`${field}\` is present but is not a list`, {
|
|
96
|
+
...scope,
|
|
97
|
+
target: field,
|
|
98
|
+
reason: 'malformed-actions'
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
const matched = [];
|
|
102
|
+
for (const action of actions) {
|
|
103
|
+
if (!isSuccessActionElement(action) && !isFailureActionElement(action)) {
|
|
104
|
+
throw new ResolverError(`\`${field}\` contains an entry that is not a Success/Failure Action Object`, {
|
|
105
|
+
...scope,
|
|
106
|
+
target: field,
|
|
107
|
+
reason: 'malformed-action-entry'
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
if (this.#criteriaMet(action, isCriterionMet, scope)) {
|
|
111
|
+
matched.push(action);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return matched;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Whether every criterion of the action passes. An action with no criteria
|
|
119
|
+
* matches vacuously.
|
|
120
|
+
*
|
|
121
|
+
* A `criteria` that is present but not a list, or that contains an entry
|
|
122
|
+
* that is not a Criterion Object, throws either way: an entry the resolver
|
|
123
|
+
* cannot read and a container it cannot read are both a document that does
|
|
124
|
+
* not say what its author meant, the same as an unrecognized entry in the
|
|
125
|
+
* action list itself.
|
|
126
|
+
*/
|
|
127
|
+
#criteriaMet(action, isCriterionMet, scope) {
|
|
128
|
+
const criteria = action.criteria;
|
|
129
|
+
if (criteria === undefined) return true;
|
|
130
|
+
if (!isArrayElement(criteria)) {
|
|
131
|
+
throw new ResolverError("An action's `criteria` is present but is not a list", {
|
|
132
|
+
...scope,
|
|
133
|
+
target: 'criteria',
|
|
134
|
+
reason: 'malformed-criteria'
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
for (const criterion of criteria) {
|
|
138
|
+
if (!isCriterionElement(criterion)) {
|
|
139
|
+
throw new ResolverError("An action's `criteria` contains an entry that is not a Criterion Object", {
|
|
140
|
+
...scope,
|
|
141
|
+
target: 'criteria',
|
|
142
|
+
reason: 'malformed-criterion'
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
if (!isCriterionMet(criterion)) return false;
|
|
146
|
+
}
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
export default ActionResolver;
|