@usearazzo/runner 0.0.0-stage → 1.0.1-alpha.10
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 +31 -0
- package/LICENSE +202 -0
- package/NOTICE +20 -0
- package/README.md +777 -2
- package/dist/arazzo-runner.browser.js +113254 -0
- package/dist/arazzo-runner.browser.min.js +1 -0
- package/package.json +91 -4
- 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 +419 -0
- package/src/index.mjs +73 -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 +2341 -0
|
@@ -0,0 +1,227 @@
|
|
|
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 _ramda = require("ramda");
|
|
9
|
+
var _apidomCore = require("@speclynx/apidom-core");
|
|
10
|
+
var _apidomDatamodel = require("@speclynx/apidom-datamodel");
|
|
11
|
+
var _jsonPointer = require("@swaggerexpert/json-pointer");
|
|
12
|
+
var _arazzoRuntimeExpression = require("@swaggerexpert/arazzo-runtime-expression");
|
|
13
|
+
var _apidomNsArazzo = require("@speclynx/apidom-ns-arazzo-1");
|
|
14
|
+
var _ResolverError = _interopRequireDefault(require("../errors/ResolverError.cjs"));
|
|
15
|
+
var _ArazzoValueResolver = _interopRequireDefault(require("./ArazzoValueResolver.cjs"));
|
|
16
|
+
/**
|
|
17
|
+
* Matches a canonical non-negative integer (RFC 6901 array index): no leading
|
|
18
|
+
* zeros other than `0` itself.
|
|
19
|
+
*/
|
|
20
|
+
const ARRAY_INDEX = /^(0|[1-9][0-9]*)$/;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Marks a bare-expression payload value that did not resolve. Its container
|
|
24
|
+
* decides what "not provided" means there: an object member is omitted, while
|
|
25
|
+
* an array element or the whole payload throws.
|
|
26
|
+
*/
|
|
27
|
+
const UNRESOLVED = Symbol('unresolved');
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* A resolved request body: the payload with all replacements applied, plus the
|
|
31
|
+
* declared content type when present.
|
|
32
|
+
* @public
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Resolves a step's `requestBody` to a concrete payload.
|
|
37
|
+
*
|
|
38
|
+
* The `payload` is resolved first. Per the specification it "can contain"
|
|
39
|
+
* runtime expressions, so it is walked: every string in it — the payload
|
|
40
|
+
* itself, or any value nested in its objects and arrays — that is a whole
|
|
41
|
+
* runtime expression resolves to its typed value, and every other string has
|
|
42
|
+
* its embedded `{expression}` occurrences interpolated (tolerantly, so literal
|
|
43
|
+
* braces such as a JSON template's own are kept). Object keys and resolved
|
|
44
|
+
* values are never evaluated.
|
|
45
|
+
*
|
|
46
|
+
* An unresolved expression reads as "not provided": an object member is
|
|
47
|
+
* omitted, while a whole-expression payload, an array element or an embedded
|
|
48
|
+
* expression — none of which can be omitted — throws {@link ResolverError}
|
|
49
|
+
* (`unresolved-expression`), as does an invalid embedded expression
|
|
50
|
+
* (`invalid-expression`).
|
|
51
|
+
*
|
|
52
|
+
* Then each `replacements` entry is applied — its `value` is resolved by the
|
|
53
|
+
* family-wide literal-vs-expression rule of {@link ArazzoValueResolver} and set
|
|
54
|
+
* into the payload at the replacement's `target` JSON Pointer. A replacement
|
|
55
|
+
* whose value does not resolve is skipped, leaving the payload as authored.
|
|
56
|
+
*
|
|
57
|
+
* `target` may be a JSON Pointer or an XPath per the specification; only JSON
|
|
58
|
+
* Pointer targets are supported — an XPath target throws {@link ResolverError}.
|
|
59
|
+
* @public
|
|
60
|
+
*/
|
|
61
|
+
class RequestBodyResolver extends _ArazzoValueResolver.default {
|
|
62
|
+
/**
|
|
63
|
+
* Resolves the request body, returning its payload and content type. Returns
|
|
64
|
+
* `undefined` when there is no request body.
|
|
65
|
+
*
|
|
66
|
+
* `scope` names the step in a thrown {@link ResolverError}.
|
|
67
|
+
*/
|
|
68
|
+
resolve(requestBody, resolve, scope) {
|
|
69
|
+
if (requestBody === undefined) return undefined;
|
|
70
|
+
|
|
71
|
+
// present but scalar: `.payload`, `.replacements` and `.contentType` are
|
|
72
|
+
// all plain `undefined` on a non-map element, so the step would silently
|
|
73
|
+
// send no body and report success.
|
|
74
|
+
if (!(0, _apidomDatamodel.isObjectElement)(requestBody)) {
|
|
75
|
+
throw new _ResolverError.default('`requestBody` is present but is not a map', {
|
|
76
|
+
...scope,
|
|
77
|
+
target: 'requestBody',
|
|
78
|
+
reason: 'malformed-request-body'
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
const authoredPayload = (0, _apidomCore.toValue)(requestBody.payload);
|
|
82
|
+
let payload = this.#requireResolved(authoredPayload, this.#resolvePayloadValue(authoredPayload, [], resolve, scope), [], scope);
|
|
83
|
+
if (requestBody.replacements !== undefined) {
|
|
84
|
+
// present but scalar: walking it would fail as a bare
|
|
85
|
+
// `TypeError: requestBody.replacements is not iterable`.
|
|
86
|
+
if (!(0, _apidomDatamodel.isArrayElement)(requestBody.replacements)) {
|
|
87
|
+
throw new _ResolverError.default('`requestBody.replacements` is present but is not a list', {
|
|
88
|
+
...scope,
|
|
89
|
+
target: 'requestBody.replacements',
|
|
90
|
+
reason: 'malformed-replacements'
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
for (const replacement of requestBody.replacements) {
|
|
94
|
+
if (!(0, _apidomNsArazzo.isPayloadReplacementElement)(replacement)) continue;
|
|
95
|
+
const target = (0, _apidomCore.toValue)(replacement.target);
|
|
96
|
+
if (typeof target !== 'string') continue;
|
|
97
|
+
const value = this.resolveValue(replacement.value, resolve);
|
|
98
|
+
if (value === undefined) continue;
|
|
99
|
+
payload = this.#applyReplacement(payload, target, value, scope);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const contentType = (0, _apidomDatamodel.isStringElement)(requestBody.contentType) ? (0, _apidomCore.toValue)(requestBody.contentType) : undefined;
|
|
103
|
+
return contentType === undefined ? {
|
|
104
|
+
payload
|
|
105
|
+
} : {
|
|
106
|
+
payload,
|
|
107
|
+
contentType
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Resolves one authored payload value at the `tokens` path, recursing into
|
|
113
|
+
* objects and arrays. Returns {@link UNRESOLVED} for a bare expression that
|
|
114
|
+
* did not resolve, for its container to handle.
|
|
115
|
+
*/
|
|
116
|
+
#resolvePayloadValue(value, tokens, resolve, scope) {
|
|
117
|
+
if (typeof value === 'string') return this.#resolvePayloadString(value, tokens, resolve, scope);
|
|
118
|
+
if (Array.isArray(value)) {
|
|
119
|
+
return value.map((item, index) => {
|
|
120
|
+
const itemTokens = [...tokens, String(index)];
|
|
121
|
+
const resolved = this.#resolvePayloadValue(item, itemTokens, resolve, scope);
|
|
122
|
+
return this.#requireResolved(item, resolved, itemTokens, scope);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
if (value !== null && typeof value === 'object') {
|
|
126
|
+
// `fromEntries` defines own properties, so an authored `__proto__` key
|
|
127
|
+
// stays a plain member instead of replacing the prototype.
|
|
128
|
+
return Object.fromEntries(Object.entries(value).map(([key, member]) => [key, this.#resolvePayloadValue(member, [...tokens, key], resolve, scope)]).filter(([, resolved]) => resolved !== UNRESOLVED));
|
|
129
|
+
}
|
|
130
|
+
return value;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Resolves one authored payload string: a whole runtime expression to its
|
|
135
|
+
* typed value (or {@link UNRESOLVED}), anything else by tolerant
|
|
136
|
+
* interpolation of its embedded `{expression}` occurrences.
|
|
137
|
+
*/
|
|
138
|
+
#resolvePayloadString(value, tokens, resolve, scope) {
|
|
139
|
+
if ((0, _arazzoRuntimeExpression.test)(value)) {
|
|
140
|
+
const resolved = resolve(value);
|
|
141
|
+
return resolved === undefined ? UNRESOLVED : resolved;
|
|
142
|
+
}
|
|
143
|
+
return (0, _arazzoRuntimeExpression.interpolate)(value, expression => {
|
|
144
|
+
const resolved = resolve(expression);
|
|
145
|
+
if (resolved === undefined) throw this.#unresolvedError(expression, tokens, scope);
|
|
146
|
+
return resolved;
|
|
147
|
+
}, {
|
|
148
|
+
strict: false,
|
|
149
|
+
onError: ({
|
|
150
|
+
text
|
|
151
|
+
}) => {
|
|
152
|
+
throw new _ResolverError.default(`Invalid runtime expression "${text}" in ${this.#payloadTarget(tokens)}`, {
|
|
153
|
+
...scope,
|
|
154
|
+
target: this.#payloadTarget(tokens),
|
|
155
|
+
reason: 'invalid-expression'
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Throws for an unresolved bare expression where omission is not possible —
|
|
163
|
+
* the whole payload or an array element; passes every other value through.
|
|
164
|
+
*/
|
|
165
|
+
#requireResolved(authored, resolved, tokens, scope) {
|
|
166
|
+
if (resolved === UNRESOLVED) throw this.#unresolvedError(authored, tokens, scope);
|
|
167
|
+
return resolved;
|
|
168
|
+
}
|
|
169
|
+
#unresolvedError(expression, tokens, scope) {
|
|
170
|
+
const target = this.#payloadTarget(tokens);
|
|
171
|
+
return new _ResolverError.default(`Runtime expression "${expression}" in ${target} did not resolve`, {
|
|
172
|
+
...scope,
|
|
173
|
+
target,
|
|
174
|
+
reason: 'unresolved-expression'
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Names a payload location for errors: `requestBody.payload` itself, or a
|
|
180
|
+
* member as a JSON Pointer fragment (e.g. `requestBody.payload#/order/petId`).
|
|
181
|
+
*/
|
|
182
|
+
#payloadTarget(tokens) {
|
|
183
|
+
return tokens.length === 0 ? 'requestBody.payload' : `requestBody.payload#${(0, _jsonPointer.compile)(tokens)}`;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Immutably sets `value` into `payload` at the `target` JSON Pointer,
|
|
188
|
+
* returning a new payload (the input is never mutated, so a payload aliased
|
|
189
|
+
* from a runtime expression's resolved value — e.g. `$inputs.order` — is not
|
|
190
|
+
* corrupted). Throws {@link ResolverError} for a non-JSON-Pointer target
|
|
191
|
+
* (e.g. XPath) or a target that does not resolve within the payload.
|
|
192
|
+
*/
|
|
193
|
+
#applyReplacement(payload, target, value, scope) {
|
|
194
|
+
if (!(0, _jsonPointer.testJSONPointer)(target)) {
|
|
195
|
+
throw new _ResolverError.default(`Unsupported requestBody replacement target "${target}" (expected JSON Pointer)`, {
|
|
196
|
+
...scope,
|
|
197
|
+
target,
|
|
198
|
+
reason: 'unsupported-target'
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// an empty pointer targets the payload root — replace the whole payload.
|
|
203
|
+
const tokens = this.#pathTokens(target);
|
|
204
|
+
if (tokens.length === 0) return value;
|
|
205
|
+
|
|
206
|
+
// the target must resolve against the payload; `hasPath` also rejects
|
|
207
|
+
// prototype-chain tokens (e.g. `__proto__`) since they are not own paths.
|
|
208
|
+
if (!(0, _ramda.hasPath)(tokens, payload)) {
|
|
209
|
+
throw new _ResolverError.default(`requestBody replacement target "${target}" does not resolve in the payload`, {
|
|
210
|
+
...scope,
|
|
211
|
+
target,
|
|
212
|
+
reason: 'unresolved-target'
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
return (0, _ramda.assocPath)(tokens, value, payload);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Parses a JSON Pointer into path tokens, coercing an array-index token to a
|
|
220
|
+
* number so it indexes an array rather than converting it to an object key
|
|
221
|
+
* (Ramda's `assocPath` distinguishes numeric from string keys).
|
|
222
|
+
*/
|
|
223
|
+
#pathTokens(target) {
|
|
224
|
+
return (0, _jsonPointer.parse)(target).tree.map(token => ARRAY_INDEX.test(token) ? Number(token) : token);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
var _default = exports.default = RequestBodyResolver;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { assocPath, hasPath } from 'ramda';
|
|
2
|
+
import { toValue } from '@speclynx/apidom-core';
|
|
3
|
+
import { isArrayElement, isObjectElement, isStringElement } from '@speclynx/apidom-datamodel';
|
|
4
|
+
import { compile as compileJSONPointer, parse as parseJSONPointer, testJSONPointer } from '@swaggerexpert/json-pointer';
|
|
5
|
+
import { interpolate, test as isRuntimeExpression } from '@swaggerexpert/arazzo-runtime-expression';
|
|
6
|
+
import { isPayloadReplacementElement } from '@speclynx/apidom-ns-arazzo-1';
|
|
7
|
+
import ResolverError from "../errors/ResolverError.mjs";
|
|
8
|
+
import ArazzoValueResolver from "./ArazzoValueResolver.mjs";
|
|
9
|
+
/**
|
|
10
|
+
* Matches a canonical non-negative integer (RFC 6901 array index): no leading
|
|
11
|
+
* zeros other than `0` itself.
|
|
12
|
+
*/
|
|
13
|
+
const ARRAY_INDEX = /^(0|[1-9][0-9]*)$/;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Marks a bare-expression payload value that did not resolve. Its container
|
|
17
|
+
* decides what "not provided" means there: an object member is omitted, while
|
|
18
|
+
* an array element or the whole payload throws.
|
|
19
|
+
*/
|
|
20
|
+
const UNRESOLVED = Symbol('unresolved');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A resolved request body: the payload with all replacements applied, plus the
|
|
24
|
+
* declared content type when present.
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Resolves a step's `requestBody` to a concrete payload.
|
|
30
|
+
*
|
|
31
|
+
* The `payload` is resolved first. Per the specification it "can contain"
|
|
32
|
+
* runtime expressions, so it is walked: every string in it — the payload
|
|
33
|
+
* itself, or any value nested in its objects and arrays — that is a whole
|
|
34
|
+
* runtime expression resolves to its typed value, and every other string has
|
|
35
|
+
* its embedded `{expression}` occurrences interpolated (tolerantly, so literal
|
|
36
|
+
* braces such as a JSON template's own are kept). Object keys and resolved
|
|
37
|
+
* values are never evaluated.
|
|
38
|
+
*
|
|
39
|
+
* An unresolved expression reads as "not provided": an object member is
|
|
40
|
+
* omitted, while a whole-expression payload, an array element or an embedded
|
|
41
|
+
* expression — none of which can be omitted — throws {@link ResolverError}
|
|
42
|
+
* (`unresolved-expression`), as does an invalid embedded expression
|
|
43
|
+
* (`invalid-expression`).
|
|
44
|
+
*
|
|
45
|
+
* Then each `replacements` entry is applied — its `value` is resolved by the
|
|
46
|
+
* family-wide literal-vs-expression rule of {@link ArazzoValueResolver} and set
|
|
47
|
+
* into the payload at the replacement's `target` JSON Pointer. A replacement
|
|
48
|
+
* whose value does not resolve is skipped, leaving the payload as authored.
|
|
49
|
+
*
|
|
50
|
+
* `target` may be a JSON Pointer or an XPath per the specification; only JSON
|
|
51
|
+
* Pointer targets are supported — an XPath target throws {@link ResolverError}.
|
|
52
|
+
* @public
|
|
53
|
+
*/
|
|
54
|
+
class RequestBodyResolver extends ArazzoValueResolver {
|
|
55
|
+
/**
|
|
56
|
+
* Resolves the request body, returning its payload and content type. Returns
|
|
57
|
+
* `undefined` when there is no request body.
|
|
58
|
+
*
|
|
59
|
+
* `scope` names the step in a thrown {@link ResolverError}.
|
|
60
|
+
*/
|
|
61
|
+
resolve(requestBody, resolve, scope) {
|
|
62
|
+
if (requestBody === undefined) return undefined;
|
|
63
|
+
|
|
64
|
+
// present but scalar: `.payload`, `.replacements` and `.contentType` are
|
|
65
|
+
// all plain `undefined` on a non-map element, so the step would silently
|
|
66
|
+
// send no body and report success.
|
|
67
|
+
if (!isObjectElement(requestBody)) {
|
|
68
|
+
throw new ResolverError('`requestBody` is present but is not a map', {
|
|
69
|
+
...scope,
|
|
70
|
+
target: 'requestBody',
|
|
71
|
+
reason: 'malformed-request-body'
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
const authoredPayload = toValue(requestBody.payload);
|
|
75
|
+
let payload = this.#requireResolved(authoredPayload, this.#resolvePayloadValue(authoredPayload, [], resolve, scope), [], scope);
|
|
76
|
+
if (requestBody.replacements !== undefined) {
|
|
77
|
+
// present but scalar: walking it would fail as a bare
|
|
78
|
+
// `TypeError: requestBody.replacements is not iterable`.
|
|
79
|
+
if (!isArrayElement(requestBody.replacements)) {
|
|
80
|
+
throw new ResolverError('`requestBody.replacements` is present but is not a list', {
|
|
81
|
+
...scope,
|
|
82
|
+
target: 'requestBody.replacements',
|
|
83
|
+
reason: 'malformed-replacements'
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
for (const replacement of requestBody.replacements) {
|
|
87
|
+
if (!isPayloadReplacementElement(replacement)) continue;
|
|
88
|
+
const target = toValue(replacement.target);
|
|
89
|
+
if (typeof target !== 'string') continue;
|
|
90
|
+
const value = this.resolveValue(replacement.value, resolve);
|
|
91
|
+
if (value === undefined) continue;
|
|
92
|
+
payload = this.#applyReplacement(payload, target, value, scope);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const contentType = isStringElement(requestBody.contentType) ? toValue(requestBody.contentType) : undefined;
|
|
96
|
+
return contentType === undefined ? {
|
|
97
|
+
payload
|
|
98
|
+
} : {
|
|
99
|
+
payload,
|
|
100
|
+
contentType
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Resolves one authored payload value at the `tokens` path, recursing into
|
|
106
|
+
* objects and arrays. Returns {@link UNRESOLVED} for a bare expression that
|
|
107
|
+
* did not resolve, for its container to handle.
|
|
108
|
+
*/
|
|
109
|
+
#resolvePayloadValue(value, tokens, resolve, scope) {
|
|
110
|
+
if (typeof value === 'string') return this.#resolvePayloadString(value, tokens, resolve, scope);
|
|
111
|
+
if (Array.isArray(value)) {
|
|
112
|
+
return value.map((item, index) => {
|
|
113
|
+
const itemTokens = [...tokens, String(index)];
|
|
114
|
+
const resolved = this.#resolvePayloadValue(item, itemTokens, resolve, scope);
|
|
115
|
+
return this.#requireResolved(item, resolved, itemTokens, scope);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
if (value !== null && typeof value === 'object') {
|
|
119
|
+
// `fromEntries` defines own properties, so an authored `__proto__` key
|
|
120
|
+
// stays a plain member instead of replacing the prototype.
|
|
121
|
+
return Object.fromEntries(Object.entries(value).map(([key, member]) => [key, this.#resolvePayloadValue(member, [...tokens, key], resolve, scope)]).filter(([, resolved]) => resolved !== UNRESOLVED));
|
|
122
|
+
}
|
|
123
|
+
return value;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Resolves one authored payload string: a whole runtime expression to its
|
|
128
|
+
* typed value (or {@link UNRESOLVED}), anything else by tolerant
|
|
129
|
+
* interpolation of its embedded `{expression}` occurrences.
|
|
130
|
+
*/
|
|
131
|
+
#resolvePayloadString(value, tokens, resolve, scope) {
|
|
132
|
+
if (isRuntimeExpression(value)) {
|
|
133
|
+
const resolved = resolve(value);
|
|
134
|
+
return resolved === undefined ? UNRESOLVED : resolved;
|
|
135
|
+
}
|
|
136
|
+
return interpolate(value, expression => {
|
|
137
|
+
const resolved = resolve(expression);
|
|
138
|
+
if (resolved === undefined) throw this.#unresolvedError(expression, tokens, scope);
|
|
139
|
+
return resolved;
|
|
140
|
+
}, {
|
|
141
|
+
strict: false,
|
|
142
|
+
onError: ({
|
|
143
|
+
text
|
|
144
|
+
}) => {
|
|
145
|
+
throw new ResolverError(`Invalid runtime expression "${text}" in ${this.#payloadTarget(tokens)}`, {
|
|
146
|
+
...scope,
|
|
147
|
+
target: this.#payloadTarget(tokens),
|
|
148
|
+
reason: 'invalid-expression'
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Throws for an unresolved bare expression where omission is not possible —
|
|
156
|
+
* the whole payload or an array element; passes every other value through.
|
|
157
|
+
*/
|
|
158
|
+
#requireResolved(authored, resolved, tokens, scope) {
|
|
159
|
+
if (resolved === UNRESOLVED) throw this.#unresolvedError(authored, tokens, scope);
|
|
160
|
+
return resolved;
|
|
161
|
+
}
|
|
162
|
+
#unresolvedError(expression, tokens, scope) {
|
|
163
|
+
const target = this.#payloadTarget(tokens);
|
|
164
|
+
return new ResolverError(`Runtime expression "${expression}" in ${target} did not resolve`, {
|
|
165
|
+
...scope,
|
|
166
|
+
target,
|
|
167
|
+
reason: 'unresolved-expression'
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Names a payload location for errors: `requestBody.payload` itself, or a
|
|
173
|
+
* member as a JSON Pointer fragment (e.g. `requestBody.payload#/order/petId`).
|
|
174
|
+
*/
|
|
175
|
+
#payloadTarget(tokens) {
|
|
176
|
+
return tokens.length === 0 ? 'requestBody.payload' : `requestBody.payload#${compileJSONPointer(tokens)}`;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Immutably sets `value` into `payload` at the `target` JSON Pointer,
|
|
181
|
+
* returning a new payload (the input is never mutated, so a payload aliased
|
|
182
|
+
* from a runtime expression's resolved value — e.g. `$inputs.order` — is not
|
|
183
|
+
* corrupted). Throws {@link ResolverError} for a non-JSON-Pointer target
|
|
184
|
+
* (e.g. XPath) or a target that does not resolve within the payload.
|
|
185
|
+
*/
|
|
186
|
+
#applyReplacement(payload, target, value, scope) {
|
|
187
|
+
if (!testJSONPointer(target)) {
|
|
188
|
+
throw new ResolverError(`Unsupported requestBody replacement target "${target}" (expected JSON Pointer)`, {
|
|
189
|
+
...scope,
|
|
190
|
+
target,
|
|
191
|
+
reason: 'unsupported-target'
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// an empty pointer targets the payload root — replace the whole payload.
|
|
196
|
+
const tokens = this.#pathTokens(target);
|
|
197
|
+
if (tokens.length === 0) return value;
|
|
198
|
+
|
|
199
|
+
// the target must resolve against the payload; `hasPath` also rejects
|
|
200
|
+
// prototype-chain tokens (e.g. `__proto__`) since they are not own paths.
|
|
201
|
+
if (!hasPath(tokens, payload)) {
|
|
202
|
+
throw new ResolverError(`requestBody replacement target "${target}" does not resolve in the payload`, {
|
|
203
|
+
...scope,
|
|
204
|
+
target,
|
|
205
|
+
reason: 'unresolved-target'
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
return assocPath(tokens, value, payload);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Parses a JSON Pointer into path tokens, coercing an array-index token to a
|
|
213
|
+
* number so it indexes an array rather than converting it to an object key
|
|
214
|
+
* (Ramda's `assocPath` distinguishes numeric from string keys).
|
|
215
|
+
*/
|
|
216
|
+
#pathTokens(target) {
|
|
217
|
+
return parseJSONPointer(target).tree.map(token => ARRAY_INDEX.test(token) ? Number(token) : token);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
export default RequestBodyResolver;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
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 _ArazzoValueResolver = _interopRequireDefault(require("./ArazzoValueResolver.cjs"));
|
|
9
|
+
/**
|
|
10
|
+
* Resolves a step's `parameters` to a plain map of resolved values.
|
|
11
|
+
*
|
|
12
|
+
* What a parameter's `value` means is the family-wide rule of
|
|
13
|
+
* {@link ArazzoValueResolver}; how the resolved values are *keyed* is the subclass's
|
|
14
|
+
* policy, one per step target — {@link OpenAPIOperationParameterResolver} keys
|
|
15
|
+
* request delivery for a step targeting an operation,
|
|
16
|
+
* {@link WorkflowParameterResolver} keys a sub-workflow's inputs for a step
|
|
17
|
+
* targeting a `workflowId`. Each executor constructs the one resolver its kind
|
|
18
|
+
* of step calls for.
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
class StepParameterResolver extends _ArazzoValueResolver.default {}
|
|
22
|
+
var _default = exports.default = StepParameterResolver;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import ArazzoValueResolver from "./ArazzoValueResolver.mjs";
|
|
2
|
+
/**
|
|
3
|
+
* Resolves a step's `parameters` to a plain map of resolved values.
|
|
4
|
+
*
|
|
5
|
+
* What a parameter's `value` means is the family-wide rule of
|
|
6
|
+
* {@link ArazzoValueResolver}; how the resolved values are *keyed* is the subclass's
|
|
7
|
+
* policy, one per step target — {@link OpenAPIOperationParameterResolver} keys
|
|
8
|
+
* request delivery for a step targeting an operation,
|
|
9
|
+
* {@link WorkflowParameterResolver} keys a sub-workflow's inputs for a step
|
|
10
|
+
* targeting a `workflowId`. Each executor constructs the one resolver its kind
|
|
11
|
+
* of step calls for.
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
class StepParameterResolver extends ArazzoValueResolver {}
|
|
15
|
+
export default StepParameterResolver;
|
|
@@ -0,0 +1,73 @@
|
|
|
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 _apidomCore = require("@speclynx/apidom-core");
|
|
9
|
+
var _apidomDatamodel = require("@speclynx/apidom-datamodel");
|
|
10
|
+
var _apidomNsArazzo = require("@speclynx/apidom-ns-arazzo-1");
|
|
11
|
+
var _ResolverError = _interopRequireDefault(require("../errors/ResolverError.cjs"));
|
|
12
|
+
var _StepParameterResolver = _interopRequireDefault(require("./StepParameterResolver.cjs"));
|
|
13
|
+
/**
|
|
14
|
+
* Resolves the `parameters` of a step targeting a `workflowId` into the
|
|
15
|
+
* sub-workflow's inputs.
|
|
16
|
+
*
|
|
17
|
+
* Values follow the family-wide literal-vs-expression rule of
|
|
18
|
+
* {@link ArazzoValueResolver}. Keys are bare parameter names: per the
|
|
19
|
+
* specification, "when the step in context specifies a `workflowId`, then all
|
|
20
|
+
* parameters map to workflow inputs" — which are keyed by name alone, even
|
|
21
|
+
* for an inherited parameter that carries an `in`. Locations are not
|
|
22
|
+
* consulted, so two parameters differing only in `in` collapse by name here,
|
|
23
|
+
* which for inputs is the override mechanism, not a loss.
|
|
24
|
+
*
|
|
25
|
+
* The first parameter to claim a name wins: the list is ordered by
|
|
26
|
+
* precedence, most specific first, as `ArazzoWorkflowNormalizer` leaves it
|
|
27
|
+
* once a step's own parameters have been merged with the ones it inherits —
|
|
28
|
+
* the override order the specification requires.
|
|
29
|
+
* @public
|
|
30
|
+
*/
|
|
31
|
+
class WorkflowParameterResolver extends _StepParameterResolver.default {
|
|
32
|
+
/**
|
|
33
|
+
* Resolves each parameter's `value`, returning a `name` → value map.
|
|
34
|
+
* Returns an empty object when there are no parameters.
|
|
35
|
+
*
|
|
36
|
+
* `scope` names the step in a thrown {@link ResolverError}.
|
|
37
|
+
*/
|
|
38
|
+
resolve(parameters, resolve, scope) {
|
|
39
|
+
const result = {};
|
|
40
|
+
if (parameters === undefined) return result;
|
|
41
|
+
// present but scalar: walking it would fail as a bare
|
|
42
|
+
// `TypeError: parameters is not iterable`.
|
|
43
|
+
if (!(0, _apidomDatamodel.isArrayElement)(parameters)) {
|
|
44
|
+
throw new _ResolverError.default('`parameters` is present but is not a list', {
|
|
45
|
+
...scope,
|
|
46
|
+
target: 'parameters',
|
|
47
|
+
reason: 'malformed-parameters'
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
for (const parameter of parameters) {
|
|
51
|
+
if (!(0, _apidomNsArazzo.isParameterElement)(parameter)) continue;
|
|
52
|
+
const name = (0, _apidomCore.toValue)(parameter.name);
|
|
53
|
+
if (typeof name !== 'string') continue;
|
|
54
|
+
// first entry wins — see the precedence note above. `Object.hasOwn` rather
|
|
55
|
+
// than `name in result`, so a parameter named `toString` is not mistaken
|
|
56
|
+
// for one already resolved.
|
|
57
|
+
if (Object.hasOwn(result, name)) continue;
|
|
58
|
+
|
|
59
|
+
// defined rather than assigned: a name like `__proto__` hits the
|
|
60
|
+
// Object.prototype accessor on bracket assignment, so no own property is
|
|
61
|
+
// ever created and the input is silently lost — and an object value
|
|
62
|
+
// additionally rewrites the record's prototype
|
|
63
|
+
Object.defineProperty(result, name, {
|
|
64
|
+
value: this.resolveValue(parameter.value, resolve),
|
|
65
|
+
enumerable: true,
|
|
66
|
+
writable: true,
|
|
67
|
+
configurable: true
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
var _default = exports.default = WorkflowParameterResolver;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { toValue } from '@speclynx/apidom-core';
|
|
2
|
+
import { isArrayElement } from '@speclynx/apidom-datamodel';
|
|
3
|
+
import { isParameterElement } from '@speclynx/apidom-ns-arazzo-1';
|
|
4
|
+
import ResolverError from "../errors/ResolverError.mjs";
|
|
5
|
+
import StepParameterResolver from "./StepParameterResolver.mjs";
|
|
6
|
+
/**
|
|
7
|
+
* Resolves the `parameters` of a step targeting a `workflowId` into the
|
|
8
|
+
* sub-workflow's inputs.
|
|
9
|
+
*
|
|
10
|
+
* Values follow the family-wide literal-vs-expression rule of
|
|
11
|
+
* {@link ArazzoValueResolver}. Keys are bare parameter names: per the
|
|
12
|
+
* specification, "when the step in context specifies a `workflowId`, then all
|
|
13
|
+
* parameters map to workflow inputs" — which are keyed by name alone, even
|
|
14
|
+
* for an inherited parameter that carries an `in`. Locations are not
|
|
15
|
+
* consulted, so two parameters differing only in `in` collapse by name here,
|
|
16
|
+
* which for inputs is the override mechanism, not a loss.
|
|
17
|
+
*
|
|
18
|
+
* The first parameter to claim a name wins: the list is ordered by
|
|
19
|
+
* precedence, most specific first, as `ArazzoWorkflowNormalizer` leaves it
|
|
20
|
+
* once a step's own parameters have been merged with the ones it inherits —
|
|
21
|
+
* the override order the specification requires.
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
class WorkflowParameterResolver extends StepParameterResolver {
|
|
25
|
+
/**
|
|
26
|
+
* Resolves each parameter's `value`, returning a `name` → value map.
|
|
27
|
+
* Returns an empty object when there are no parameters.
|
|
28
|
+
*
|
|
29
|
+
* `scope` names the step in a thrown {@link ResolverError}.
|
|
30
|
+
*/
|
|
31
|
+
resolve(parameters, resolve, scope) {
|
|
32
|
+
const result = {};
|
|
33
|
+
if (parameters === undefined) return result;
|
|
34
|
+
// present but scalar: walking it would fail as a bare
|
|
35
|
+
// `TypeError: parameters is not iterable`.
|
|
36
|
+
if (!isArrayElement(parameters)) {
|
|
37
|
+
throw new ResolverError('`parameters` is present but is not a list', {
|
|
38
|
+
...scope,
|
|
39
|
+
target: 'parameters',
|
|
40
|
+
reason: 'malformed-parameters'
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
for (const parameter of parameters) {
|
|
44
|
+
if (!isParameterElement(parameter)) continue;
|
|
45
|
+
const name = toValue(parameter.name);
|
|
46
|
+
if (typeof name !== 'string') continue;
|
|
47
|
+
// first entry wins — see the precedence note above. `Object.hasOwn` rather
|
|
48
|
+
// than `name in result`, so a parameter named `toString` is not mistaken
|
|
49
|
+
// for one already resolved.
|
|
50
|
+
if (Object.hasOwn(result, name)) continue;
|
|
51
|
+
|
|
52
|
+
// defined rather than assigned: a name like `__proto__` hits the
|
|
53
|
+
// Object.prototype accessor on bracket assignment, so no own property is
|
|
54
|
+
// ever created and the input is silently lost — and an object value
|
|
55
|
+
// additionally rewrites the record's prototype
|
|
56
|
+
Object.defineProperty(result, name, {
|
|
57
|
+
value: this.resolveValue(parameter.value, resolve),
|
|
58
|
+
enumerable: true,
|
|
59
|
+
writable: true,
|
|
60
|
+
configurable: true
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export default WorkflowParameterResolver;
|