@usearazzo/runner 0.0.0-stage → 1.0.1-alpha.7

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.
Files changed (151) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +20 -0
  3. package/README.md +784 -2
  4. package/dist/arazzo-runner.browser.js +111247 -0
  5. package/dist/arazzo-runner.browser.min.js +1 -0
  6. package/package.json +88 -4
  7. package/src/action/ActionResolver.cjs +160 -0
  8. package/src/action/ActionResolver.mjs +150 -0
  9. package/src/assembler/OpenAPI2DocumentAssembler.cjs +111 -0
  10. package/src/assembler/OpenAPI2DocumentAssembler.mjs +104 -0
  11. package/src/assembler/OpenAPI30DocumentAssembler.cjs +110 -0
  12. package/src/assembler/OpenAPI30DocumentAssembler.mjs +103 -0
  13. package/src/assembler/OpenAPI31DocumentAssembler.cjs +111 -0
  14. package/src/assembler/OpenAPI31DocumentAssembler.mjs +104 -0
  15. package/src/assembler/OpenAPIDocumentAssembler.cjs +58 -0
  16. package/src/assembler/OpenAPIDocumentAssembler.mjs +50 -0
  17. package/src/client/HTTPClient.cjs +5 -0
  18. package/src/client/HTTPClient.mjs +1 -0
  19. package/src/client/HTTPClientFetch.cjs +16 -0
  20. package/src/client/HTTPClientFetch.mjs +10 -0
  21. package/src/client/OpenAPIOperationRequest.cjs +5 -0
  22. package/src/client/OpenAPIOperationRequest.mjs +1 -0
  23. package/src/client/OpenAPIOperationResponse.cjs +42 -0
  24. package/src/client/OpenAPIOperationResponse.mjs +36 -0
  25. package/src/client/OpenAPIOperationResponseNormalizer.cjs +48 -0
  26. package/src/client/OpenAPIOperationResponseNormalizer.mjs +40 -0
  27. package/src/client/ParameterDelivery.cjs +119 -0
  28. package/src/client/ParameterDelivery.mjs +113 -0
  29. package/src/constants.cjs +9 -0
  30. package/src/constants.mjs +3 -0
  31. package/src/criterion/CriterionEvaluator.cjs +205 -0
  32. package/src/criterion/CriterionEvaluator.mjs +196 -0
  33. package/src/criterion/JSONPathCriterionEvaluator.cjs +47 -0
  34. package/src/criterion/JSONPathCriterionEvaluator.mjs +40 -0
  35. package/src/criterion/RegexCriterionEvaluator.cjs +67 -0
  36. package/src/criterion/RegexCriterionEvaluator.mjs +60 -0
  37. package/src/criterion/SimpleCriterionEvaluator.cjs +50 -0
  38. package/src/criterion/SimpleCriterionEvaluator.mjs +43 -0
  39. package/src/criterion/XPathCriterionEvaluator.cjs +117 -0
  40. package/src/criterion/XPathCriterionEvaluator.mjs +109 -0
  41. package/src/document/APIDocument.cjs +35 -0
  42. package/src/document/APIDocument.mjs +30 -0
  43. package/src/document/ArazzoDocument.cjs +81 -0
  44. package/src/document/ArazzoDocument.mjs +74 -0
  45. package/src/document/ArazzoSourceDescriptionIndex.cjs +26 -0
  46. package/src/document/ArazzoSourceDescriptionIndex.mjs +20 -0
  47. package/src/document/ArazzoStepIndex.cjs +25 -0
  48. package/src/document/ArazzoStepIndex.mjs +19 -0
  49. package/src/document/ArazzoWorkflowIndex.cjs +17 -0
  50. package/src/document/ArazzoWorkflowIndex.mjs +11 -0
  51. package/src/document/OpenAPIDocument.cjs +28 -0
  52. package/src/document/OpenAPIDocument.mjs +21 -0
  53. package/src/document/OpenAPIOperationIndex.cjs +24 -0
  54. package/src/document/OpenAPIOperationIndex.mjs +18 -0
  55. package/src/document/ParameterIdentity.cjs +93 -0
  56. package/src/document/ParameterIdentity.mjs +88 -0
  57. package/src/document/openapi-types.cjs +5 -0
  58. package/src/document/openapi-types.mjs +1 -0
  59. package/src/errors/ArazzoRunnerError.cjs +10 -0
  60. package/src/errors/ArazzoRunnerError.mjs +5 -0
  61. package/src/errors/AssemblerError.cjs +11 -0
  62. package/src/errors/AssemblerError.mjs +4 -0
  63. package/src/errors/ClientError.cjs +11 -0
  64. package/src/errors/ClientError.mjs +4 -0
  65. package/src/errors/CriterionError.cjs +11 -0
  66. package/src/errors/CriterionError.mjs +4 -0
  67. package/src/errors/ExecutionError.cjs +11 -0
  68. package/src/errors/ExecutionError.mjs +4 -0
  69. package/src/errors/ExtractionError.cjs +11 -0
  70. package/src/errors/ExtractionError.mjs +4 -0
  71. package/src/errors/InvalidEntryDocumentError.cjs +11 -0
  72. package/src/errors/InvalidEntryDocumentError.mjs +4 -0
  73. package/src/errors/NormalizationError.cjs +11 -0
  74. package/src/errors/NormalizationError.mjs +4 -0
  75. package/src/errors/ResolverError.cjs +11 -0
  76. package/src/errors/ResolverError.mjs +4 -0
  77. package/src/errors/RuntimeExpressionError.cjs +11 -0
  78. package/src/errors/RuntimeExpressionError.mjs +4 -0
  79. package/src/errors/UnmatchedProviderError.cjs +11 -0
  80. package/src/errors/UnmatchedProviderError.mjs +4 -0
  81. package/src/executor/ArazzoWorkflowLocatorNormalizer.cjs +147 -0
  82. package/src/executor/ArazzoWorkflowLocatorNormalizer.mjs +137 -0
  83. package/src/executor/OpenAPIOperationExecutor.cjs +457 -0
  84. package/src/executor/OpenAPIOperationExecutor.mjs +446 -0
  85. package/src/executor/OpenAPIOperationLocatorNormalizer.cjs +197 -0
  86. package/src/executor/OpenAPIOperationLocatorNormalizer.mjs +189 -0
  87. package/src/executor/SourceDescriptionsLocatorNormalizer.cjs +44 -0
  88. package/src/executor/SourceDescriptionsLocatorNormalizer.mjs +38 -0
  89. package/src/executor/StepExecutor.cjs +333 -0
  90. package/src/executor/StepExecutor.mjs +326 -0
  91. package/src/executor/StepRetryRunner.cjs +226 -0
  92. package/src/executor/StepRetryRunner.mjs +215 -0
  93. package/src/executor/StepTransitionInterpreter.cjs +159 -0
  94. package/src/executor/StepTransitionInterpreter.mjs +151 -0
  95. package/src/executor/WorkflowCallStack.cjs +116 -0
  96. package/src/executor/WorkflowCallStack.mjs +106 -0
  97. package/src/executor/WorkflowExecutor.cjs +1091 -0
  98. package/src/executor/WorkflowExecutor.mjs +1077 -0
  99. package/src/executor/abort.cjs +70 -0
  100. package/src/executor/abort.mjs +60 -0
  101. package/src/expression/RuntimeExpressionContext.cjs +5 -0
  102. package/src/expression/RuntimeExpressionContext.mjs +1 -0
  103. package/src/expression/RuntimeExpressionEvaluator.cjs +337 -0
  104. package/src/expression/RuntimeExpressionEvaluator.mjs +328 -0
  105. package/src/extractor/ArazzoStepExtractor.cjs +48 -0
  106. package/src/extractor/ArazzoStepExtractor.mjs +41 -0
  107. package/src/extractor/ArazzoWorkflowExtractor.cjs +50 -0
  108. package/src/extractor/ArazzoWorkflowExtractor.mjs +43 -0
  109. package/src/extractor/OpenAPIOperationExtractor.cjs +84 -0
  110. package/src/extractor/OpenAPIOperationExtractor.mjs +77 -0
  111. package/src/index.cjs +419 -0
  112. package/src/index.mjs +73 -0
  113. package/src/normalizer/ArazzoStepNormalizer.cjs +23 -0
  114. package/src/normalizer/ArazzoStepNormalizer.mjs +17 -0
  115. package/src/normalizer/ArazzoWorkflowNormalizer.cjs +214 -0
  116. package/src/normalizer/ArazzoWorkflowNormalizer.mjs +206 -0
  117. package/src/normalizer/OpenAPI2OperationNormalizer.cjs +128 -0
  118. package/src/normalizer/OpenAPI2OperationNormalizer.mjs +120 -0
  119. package/src/normalizer/OpenAPI30OperationNormalizer.cjs +129 -0
  120. package/src/normalizer/OpenAPI30OperationNormalizer.mjs +121 -0
  121. package/src/normalizer/OpenAPI31OperationNormalizer.cjs +131 -0
  122. package/src/normalizer/OpenAPI31OperationNormalizer.mjs +123 -0
  123. package/src/normalizer/OpenAPIOperationNormalizer.cjs +58 -0
  124. package/src/normalizer/OpenAPIOperationNormalizer.mjs +50 -0
  125. package/src/registry/DocumentRegistry.cjs +160 -0
  126. package/src/registry/DocumentRegistry.mjs +151 -0
  127. package/src/registry/providers/ArazzoDocumentRegistryProvider.cjs +154 -0
  128. package/src/registry/providers/ArazzoDocumentRegistryProvider.mjs +146 -0
  129. package/src/registry/providers/DocumentRegistryProvider.cjs +31 -0
  130. package/src/registry/providers/DocumentRegistryProvider.mjs +25 -0
  131. package/src/registry/providers/OpenAPIDocumentRegistryProvider.cjs +122 -0
  132. package/src/registry/providers/OpenAPIDocumentRegistryProvider.mjs +114 -0
  133. package/src/resolver/ArazzoValueResolver.cjs +42 -0
  134. package/src/resolver/ArazzoValueResolver.mjs +37 -0
  135. package/src/resolver/OpenAPIOperationParameterResolver.cjs +117 -0
  136. package/src/resolver/OpenAPIOperationParameterResolver.mjs +110 -0
  137. package/src/resolver/OutputResolver.cjs +71 -0
  138. package/src/resolver/OutputResolver.mjs +64 -0
  139. package/src/resolver/RequestBodyResolver.cjs +227 -0
  140. package/src/resolver/RequestBodyResolver.mjs +220 -0
  141. package/src/resolver/ResolverScope.cjs +5 -0
  142. package/src/resolver/ResolverScope.mjs +1 -0
  143. package/src/resolver/StepParameterResolver.cjs +22 -0
  144. package/src/resolver/StepParameterResolver.mjs +15 -0
  145. package/src/resolver/WorkflowParameterResolver.cjs +73 -0
  146. package/src/resolver/WorkflowParameterResolver.mjs +66 -0
  147. package/src/state/WorkflowExecutionState.cjs +99 -0
  148. package/src/state/WorkflowExecutionState.mjs +93 -0
  149. package/src/vendor/swagger-client.cjs +1 -0
  150. package/src/vendor/swagger-client.mjs +1 -0
  151. package/types/runner.d.ts +2341 -0
@@ -0,0 +1,457 @@
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 _empty = require("@speclynx/apidom-reference/configuration/empty");
11
+ var _apidomNsOpenapi = require("@speclynx/apidom-ns-openapi-2");
12
+ var _ramdaAdjunct = require("ramda-adjunct");
13
+ var _swaggerClient = require("../vendor/swagger-client.cjs");
14
+ var _ParameterDelivery = _interopRequireDefault(require("../client/ParameterDelivery.cjs"));
15
+ var _HTTPClientFetch = _interopRequireDefault(require("../client/HTTPClientFetch.cjs"));
16
+ var _OpenAPIOperationResponseNormalizer = _interopRequireDefault(require("../client/OpenAPIOperationResponseNormalizer.cjs"));
17
+ var _OpenAPIOperationExtractor = _interopRequireDefault(require("../extractor/OpenAPIOperationExtractor.cjs"));
18
+ var _OpenAPIOperationNormalizer = _interopRequireDefault(require("../normalizer/OpenAPIOperationNormalizer.cjs"));
19
+ var _OpenAPIDocumentAssembler = _interopRequireDefault(require("../assembler/OpenAPIDocumentAssembler.cjs"));
20
+ var _ClientError = _interopRequireDefault(require("../errors/ClientError.cjs"));
21
+ // @ts-expect-error vendored swagger-client bundle has no type declarations
22
+
23
+ /**
24
+ * Decorates the built request before it is handed to the {@link HTTPClient}.
25
+ *
26
+ * Receives the finalized {@link OpenAPIOperationRequest} and may mutate it in
27
+ * place or return a replacement; returning nothing keeps the received request.
28
+ * May be synchronous or asynchronous.
29
+ * @public
30
+ */
31
+
32
+ /**
33
+ * Options for executing an OpenAPI operation.
34
+ *
35
+ * All fields are forwarded to the vendored swagger-client `buildRequest`
36
+ * (which owns parameter serialization, security application, and server URL
37
+ * resolution), except `requestInterceptor`, which the executor runs between
38
+ * building the request and sending it.
39
+ *
40
+ * Typed here are the options the runner itself drives and the ones callers
41
+ * routinely reach for. The rest of `buildRequest`'s surface (`securities`,
42
+ * `scheme`, `parameterBuilders`, `attachContentTypeForEmptyPayload`, …) is
43
+ * deliberately left untyped and passes through the bag's open tail unchanged —
44
+ * see {@link OpenAPIOperationExecuteOptionsBag}. Authentication in particular
45
+ * is not modeled: Arazzo is auth-agnostic, so credentials are applied with a
46
+ * {@link RequestInterceptor}.
47
+ * @public
48
+ */
49
+
50
+ /**
51
+ * The execute options forwarded to {@link OpenAPIOperationExecutor.execute}.
52
+ *
53
+ * The {@link OpenAPIOperationExecuteOptions} fields are surfaced for
54
+ * type-checked callers, while the open `Record` tail keeps the bag opaque so
55
+ * the rest of `buildRequest`'s surface (`scheme`, `parameterBuilders`,
56
+ * `attachContentTypeForEmptyPayload`, …) passes through untouched.
57
+ *
58
+ * Nothing routine belongs in the tail. Credentials go through a
59
+ * {@link RequestInterceptor} and `server` covers every case that once needed a
60
+ * `contextUrl`, so reaching for either of those here means an edge case: tests
61
+ * standing in for a document fetched over HTTP, or credentials applied from the
62
+ * document's own security schemes.
63
+ *
64
+ * Two kinds of entry are inert rather than honored, since the executor owns
65
+ * what they used to control. The operation target always comes from the
66
+ * locator, so `operationId`/`operationPath` have no effect; and the options
67
+ * only swagger-client's `execute()` ever read — `userFetch` and
68
+ * `responseInterceptor`, which the runner replaces with `httpClient` and
69
+ * `responseNormalizer` — reach `buildRequest` but nothing acts on them.
70
+ * @public
71
+ */
72
+
73
+ /**
74
+ * Options for the OpenAPIOperationExecutor.
75
+ * @public
76
+ */
77
+
78
+ /**
79
+ * Executes a single OpenAPI operation named by a canonical
80
+ * {@link OpenAPIOperationLocator}.
81
+ *
82
+ * The pipeline extracts the operation from its owning document, normalizes it,
83
+ * assembles a minimal standalone OpenAPI document containing just that
84
+ * operation, builds the HTTP request with the vendored swagger-client
85
+ * `buildRequest` (parameter serialization, securities, server resolution),
86
+ * sends it through the pluggable {@link HTTPClient}, and normalizes the raw
87
+ * `Response` into the runner's response model. A non-2xx status is a valid
88
+ * outcome (judged by a step's `successCriteria`) and is returned, never
89
+ * thrown; a transport failure is wrapped as a {@link ClientError}.
90
+ *
91
+ * The executor is Arazzo-agnostic: it neither locates the operation (that is
92
+ * the operation locator normalizer's concern) nor resolves parameters or
93
+ * request bodies from runtime expressions (the step executor's concern). It
94
+ * receives an already-resolved locator and an opaque bag of execute options,
95
+ * and returns the normalized operation response carrying the request that was
96
+ * actually sent, so `$url` / `$method` / `$request.*` can be evaluated after
97
+ * execution.
98
+ * @public
99
+ */
100
+ class OpenAPIOperationExecutor {
101
+ #httpClient;
102
+ #requestInterceptor;
103
+ #responseNormalizer;
104
+ #operationExtractor;
105
+ #operationNormalizer;
106
+ #documentAssembler;
107
+ constructor(options = {}) {
108
+ this.#httpClient = options.httpClient ?? _HTTPClientFetch.default;
109
+ this.#requestInterceptor = options.requestInterceptor;
110
+ this.#responseNormalizer = options.responseNormalizer ?? new _OpenAPIOperationResponseNormalizer.default();
111
+ this.#operationExtractor = options.operationExtractor ?? new _OpenAPIOperationExtractor.default();
112
+ this.#operationNormalizer = options.operationNormalizer ?? new _OpenAPIOperationNormalizer.default();
113
+ this.#documentAssembler = options.documentAssembler ?? new _OpenAPIDocumentAssembler.default();
114
+ }
115
+
116
+ /**
117
+ * Executes the located operation, returning the normalized operation
118
+ * response.
119
+ *
120
+ * `executeOptions` is an opaque bag of `buildRequest` options (e.g. resolved
121
+ * `parameters`, a `requestBody` and its `requestContentType`, or a `server`).
122
+ * The operation target always takes precedence over it: the
123
+ * locator's JSON Pointer selects the operation in the assembled document, so
124
+ * `operationId`/`operationPath` entries in the bag cannot hijack the
125
+ * operation.
126
+ */
127
+ async execute(locator, executeOptions = {}) {
128
+ // extraction validates the locator first: a pointer naming anything but an
129
+ // operation would otherwise crash inside normalization
130
+ const operation = this.#operationExtractor.extractByPointer(locator.document, locator.jsonPointer);
131
+ // the legacy id (`{method}-{path}`) matches regardless of an explicit
132
+ // `operationId` in the assembled document
133
+ const operationId = (0, _swaggerClient.idFromPathMethodLegacy)((0, _apidomCore.toValue)(operation.meta.get('path')), (0, _apidomCore.toValue)(operation.meta.get('http-method')));
134
+ const normalizedOperation = await this.#operationNormalizer.normalize(operation, locator.document);
135
+ const assembled = this.#documentAssembler.assemble(normalizedOperation, locator.document);
136
+
137
+ // the interceptor is consumed here, and the target always comes from the
138
+ // locator, so both operation keys are dropped rather than rest
139
+ const {
140
+ requestInterceptor,
141
+ operationId: _,
142
+ operationPath: __,
143
+ ...rest
144
+ } = executeOptions;
145
+
146
+ // each step derives the next options rather than editing in place
147
+ const withServer = this.#applyServerOptions(rest, normalizedOperation, locator.document);
148
+ const withBody = this.#adaptRequestBody(withServer, normalizedOperation, locator.document, locator.jsonPointer);
149
+ const buildOptions = this.#adaptRequestContentType(withBody, normalizedOperation, locator.document, locator.jsonPointer);
150
+ let request;
151
+ try {
152
+ const spec = assembled.toJSON();
153
+ request = (0, _swaggerClient.buildRequest)({
154
+ ...buildOptions,
155
+ spec,
156
+ operationId
157
+ });
158
+ } catch (error) {
159
+ throw new _ClientError.default('Failed to build request for OpenAPI operation', {
160
+ operationPath: locator.jsonPointer,
161
+ cause: error
162
+ });
163
+ }
164
+
165
+ // a differing value means #adaptRequestContentType swapped the authored
166
+ // media type for the declared one so the body would attach; the header
167
+ // still goes out as authored, parameters and all
168
+ const authoredContentType = executeOptions.requestContentType;
169
+ if (typeof authoredContentType === 'string' && buildOptions.requestContentType !== authoredContentType) {
170
+ request.headers['Content-Type'] = authoredContentType;
171
+ }
172
+ request = await this.#finalizeRequest(request, requestInterceptor);
173
+
174
+ // capture the request as sent, so `$url` / `$method` / `$request.*` can be
175
+ // evaluated after execution; headers are copied so a transport-side
176
+ // mutation cannot rewrite the record
177
+ const requestInfo = {
178
+ url: request.url,
179
+ method: request.method,
180
+ headers: {
181
+ ...request.headers
182
+ },
183
+ body: request.body
184
+ };
185
+ let rawResponse;
186
+ try {
187
+ rawResponse = await this.#httpClient(request);
188
+ } catch (error) {
189
+ throw new _ClientError.default('OpenAPI operation request failed', {
190
+ operationPath: locator.jsonPointer,
191
+ cause: error
192
+ });
193
+ }
194
+ return this.#responseNormalizer.normalize(rawResponse, requestInfo);
195
+ }
196
+
197
+ /**
198
+ * Derives where the request is sent, returning the options to build with.
199
+ *
200
+ * swagger-client already selects a declared server, substitutes its variables
201
+ * and resolves relative URLs — the one thing it gets wrong is what to do with
202
+ * a `server` matching nothing it declared, which it silently swaps for the
203
+ * first declared server. Here that value becomes an override instead: the URL
204
+ * you name is the URL that is called, whatever the document declares. Passing
205
+ * it as `baseURL` bypasses swagger-client's own server resolution, which also
206
+ * makes `server` work on Swagger 2.0, where it is otherwise ignored.
207
+ *
208
+ * A relative server resolves against the URL the document was loaded from,
209
+ * which is what `contextUrl` means, so it is derived rather than asked for.
210
+ * Only an HTTP(S) document URL qualifies. Swagger 2.0 falls back to the
211
+ * context URL's protocol when the document declares no `schemes`, so a `file:`
212
+ * URL would yield `file://host/basePath` instead of `http://…`. The registry
213
+ * normalizes `file:` URIs to bare filesystem paths, which carry no protocol
214
+ * and are harmless, so this is a guard on the invariant rather than on a
215
+ * reachable state today. A caller-supplied `contextUrl` still wins, for
216
+ * resolving against somewhere the document did not come from.
217
+ */
218
+ #applyServerOptions(buildOptions, operation, document) {
219
+ const resolved = buildOptions.contextUrl === undefined && _empty.url.isHttpUrl(document.uri) ? {
220
+ ...buildOptions,
221
+ contextUrl: document.uri
222
+ } : buildOptions;
223
+ const {
224
+ server,
225
+ ...withoutServer
226
+ } = resolved;
227
+ if (typeof server !== 'string') return resolved;
228
+
229
+ // the operation normalizer has already inherited servers down from the
230
+ // document root, including the spec's default `[{ url: '/' }]`. spread into
231
+ // a real array rather than using ArrayElement's own find(), which returns an
232
+ // empty ArrayElement on a miss — truthy, so every server would look declared.
233
+ // the members are Server elements, but isObjectElement keeps this one code
234
+ // path valid for every version: isServerElement is per-namespace, and the
235
+ // 3.1 one rejects 3.0 servers
236
+ const servers = operation.get('servers');
237
+ const declared = (0, _apidomDatamodel.isArrayElement)(servers) ? [...servers] : [];
238
+ const isDeclared = declared.some(candidate => (0, _apidomDatamodel.isObjectElement)(candidate) && (0, _apidomCore.toValue)(candidate.get('url')) === server);
239
+ if (isDeclared) return resolved;
240
+ const baseURL = _empty.url.hasProtocol(server) ? server : _empty.url.resolve(resolved.contextUrl ?? '', server);
241
+
242
+ // buildRequest concatenates the base and the path verbatim, so a trailing
243
+ // slash would double up. swagger-client trims one in its own resolution too
244
+ return {
245
+ ...withoutServer,
246
+ baseURL: baseURL.replace(/\/$/, '')
247
+ };
248
+ }
249
+
250
+ /**
251
+ * Reconciles the requested body media type with the ones the operation
252
+ * declares, returning the options to build with. A rewritten
253
+ * `requestContentType` is what tells `execute` to restore the authored value
254
+ * onto the header afterwards.
255
+ *
256
+ * swagger-client attaches the body only when `requestContentType` is an exact
257
+ * key of `requestBody.content`, and otherwise drops the body *and* the header
258
+ * without a word. Media types are richer than that: they carry optional
259
+ * parameters and their names are case-insensitive, so the Arazzo
260
+ * `application/json; charset=utf-8` and `Application/JSON` both name a
261
+ * declared `application/json`. Both are matched here, the request is built
262
+ * under the declared spelling, and the authored value is restored onto the
263
+ * header afterwards. A type naming nothing declared is an authoring error and
264
+ * is raised rather than turned into an empty request.
265
+ *
266
+ * Only OpenAPI 3.x declares media types this way. A Swagger 2.0 operation has
267
+ * no `requestBody` to check against, so its content type passes through for
268
+ * `consumes` to govern.
269
+ */
270
+ #adaptRequestContentType(buildOptions, operation, document, jsonPointer) {
271
+ const requested = buildOptions.requestContentType;
272
+ if (typeof requested !== 'string' || buildOptions.requestBody === undefined) {
273
+ return buildOptions;
274
+ }
275
+ if ((0, _apidomNsOpenapi.isSwaggerElement)(document.parseResult.api)) return buildOptions;
276
+ const requestBody = operation.get('requestBody');
277
+ const content = (0, _apidomDatamodel.isObjectElement)(requestBody) ? requestBody.get('content') : undefined;
278
+ if (!(0, _apidomDatamodel.isObjectElement)(content)) {
279
+ throw new _ClientError.default(`Request body media type "${requested}" cannot be sent: the operation declares ` + 'no request body content. Omit the content type to send the payload as-is', {
280
+ operationPath: jsonPointer
281
+ });
282
+ }
283
+ const declared = content.keys();
284
+ if (declared.includes(requested)) return buildOptions;
285
+
286
+ // media type names are case-insensitive and their parameters are not part of
287
+ // the name, so both are normalized away before matching
288
+ const baseType = requested.split(';')[0].trim().toLowerCase();
289
+ const [type] = baseType.split('/');
290
+ const covers = (mediaType, by) => {
291
+ const candidate = mediaType.toLowerCase();
292
+ if (by === 'exact') return candidate === baseType;
293
+ if (by === 'subtype') return candidate === `${type}/*`;
294
+ return candidate === '*/*';
295
+ };
296
+
297
+ // a form media type decides how the body is encoded, and buildRequest applies
298
+ // that encoding only for an exactly declared type. matching one against a
299
+ // range would put a JSON body behind a form Content-Type
300
+ const isFormEncoded = baseType === 'application/x-www-form-urlencoded' || baseType === 'multipart/form-data';
301
+
302
+ // otherwise a declared range covers a concrete type, so `*/*` (what several
303
+ // generators emit by default) accepts anything; the most specific wins
304
+ const exact = declared.find(mediaType => covers(mediaType, 'exact'));
305
+ const match = exact ?? (isFormEncoded ? undefined : declared.find(mediaType => covers(mediaType, 'subtype')) ?? declared.find(mediaType => covers(mediaType, 'any')));
306
+ if (match === undefined) {
307
+ throw new _ClientError.default(isFormEncoded ? `Request body media type "${requested}" must be declared by the operation exactly, ` + `since it decides how the body is encoded (declared: [${declared.join(', ')}])` : `Request body media type "${requested}" is not declared by the operation ` + `(declared: [${declared.join(', ')}])`, {
308
+ operationPath: jsonPointer
309
+ });
310
+ }
311
+ return {
312
+ ...buildOptions,
313
+ requestContentType: match
314
+ };
315
+ }
316
+
317
+ /**
318
+ * Routes a request body through the convention the target OpenAPI version
319
+ * uses, leaving OpenAPI 3.x calls untouched.
320
+ *
321
+ * Swagger 2.0 has no request body concept — the payload is an ordinary
322
+ * parameter declared `in: body`, or a set of `in: formData` ones — so it must
323
+ * travel through `parameters` under the names the operation declares. Arazzo
324
+ * cannot express that itself (its parameter `in` allows only `path`, `query`,
325
+ * `querystring`, `header`, and `cookie`), which is why the translation lives
326
+ * here, where the assembled document has those parameters dereferenced and
327
+ * inherited.
328
+ *
329
+ * The payload travels under {@link ParameterDelivery} keys
330
+ * (`body.{name}`, `formData.{name}`), never bare names: a bare key would
331
+ * capture a same-named parameter in another location — 2.0 legally declares
332
+ * e.g. `petId` in `path` and in `formData` at once — per the lookup order
333
+ * documented on {@link ParameterDelivery}.
334
+ *
335
+ * A *bare* `parameters` entry bearing a payload target's name is rejected
336
+ * with {@link ClientError} rather than resolved either way: before the
337
+ * qualified keys the payload silently overwrote it, after them the bare key
338
+ * would silently outrank the payload at the client's bare-first lookup —
339
+ * both wrong for somebody, so the ambiguity is reported instead. Such an
340
+ * entry can come from a direct caller mixing bare parameters with a request
341
+ * body, or from the runner's own pipeline: the parameter resolver keeps a
342
+ * `querystring` parameter under its bare name.
343
+ */
344
+ #adaptRequestBody(buildOptions, operation, document, jsonPointer) {
345
+ if (!(0, _apidomNsOpenapi.isSwaggerElement)(document.parseResult.api) || buildOptions.requestBody === undefined) {
346
+ return buildOptions;
347
+ }
348
+ const {
349
+ requestBody,
350
+ parameters: given,
351
+ ...rest
352
+ } = buildOptions;
353
+ const callerParameters = given;
354
+ // an operation declaring none leaves `parameters` absent rather than empty,
355
+ // and that case still has to reach the throw below
356
+ const declared = operation.parameters;
357
+ const parameters = (0, _apidomDatamodel.isArrayElement)(declared) ? [...declared.filter(_apidomNsOpenapi.isParameterElement)] : [];
358
+
359
+ // the body parameter's name is arbitrary, so the payload wins over a
360
+ // same-keyed entry the caller supplied
361
+ const body = parameters.find(parameter => (0, _apidomCore.toValue)(parameter.in) === 'body');
362
+ if (body !== undefined) {
363
+ const name = (0, _apidomCore.toValue)(body.name);
364
+ this.#rejectBarePayloadConflicts(callerParameters, [name], jsonPointer);
365
+ return {
366
+ ...rest,
367
+ parameters: {
368
+ ...callerParameters,
369
+ [_ParameterDelivery.default.keyFor('body', name)]: requestBody
370
+ }
371
+ };
372
+ }
373
+
374
+ // formData models each field as its own parameter, so the payload's keys
375
+ // are the parameter names; buildRequest reports any that do not match
376
+ const hasForm = parameters.some(parameter => (0, _apidomCore.toValue)(parameter.in) === 'formData');
377
+ if (hasForm) {
378
+ if (!(0, _ramdaAdjunct.isPlainObject)(requestBody)) {
379
+ throw new _ClientError.default('Request body cannot be sent: the OpenAPI 2.0 operation carries it in "formData" ' + 'parameters, so the payload must be an object keyed by their names', {
380
+ operationPath: jsonPointer
381
+ });
382
+ }
383
+ const payload = requestBody;
384
+ this.#rejectBarePayloadConflicts(callerParameters, Object.keys(payload), jsonPointer);
385
+ const merged = {
386
+ ...callerParameters
387
+ };
388
+ for (const [field, value] of Object.entries(payload)) {
389
+ merged[_ParameterDelivery.default.keyFor('formData', field)] = value;
390
+ }
391
+ return {
392
+ ...rest,
393
+ parameters: merged
394
+ };
395
+ }
396
+ throw new _ClientError.default('Request body cannot be sent: the OpenAPI 2.0 operation declares no "body" or ' + '"formData" parameter to carry it', {
397
+ operationPath: jsonPointer
398
+ });
399
+ }
400
+
401
+ /**
402
+ * Rejects bare `parameters` entries bearing the names the payload is about
403
+ * to be delivered under — the client consults bare names before qualified
404
+ * keys, so such an entry would silently displace the request body (see
405
+ * {@link OpenAPIOperationExecutor.#adaptRequestBody}).
406
+ */
407
+ #rejectBarePayloadConflicts(callerParameters, payloadNames, jsonPointer) {
408
+ if (callerParameters === undefined) return;
409
+ const conflicts = payloadNames.filter(name => Object.hasOwn(callerParameters, name));
410
+ if (conflicts.length === 0) return;
411
+ throw new _ClientError.default(`Request body cannot be sent: bare parameter ${conflicts.length === 1 ? 'entry' : 'entries'} ` + `[${conflicts.join(', ')}] would displace the payload at delivery. Supply the ` + `parameter under its "{in}.{name}" key, or drop the duplicate`, {
412
+ operationPath: jsonPointer
413
+ });
414
+ }
415
+
416
+ /**
417
+ * Applies the wire-level fixups swagger-client performs between building a
418
+ * request and fetching it, and runs the request interceptors: the
419
+ * executor-level one first, the per-call one from the options bag second.
420
+ *
421
+ * Ported rather than imported: upstream keeps them inline in `execute()` and
422
+ * `http()`, which also fetch and throw on a non-2xx. Diff against those two
423
+ * when bumping swagger-client.
424
+ */
425
+ async #finalizeRequest(request, perCallInterceptor) {
426
+ let finalized = request;
427
+
428
+ // JSON-encode plain-object and array bodies, exactly as swagger-client's
429
+ // execute() does before handing the request to its transport
430
+ if (finalized.body && ((0, _ramdaAdjunct.isPlainObject)(finalized.body) || Array.isArray(finalized.body))) {
431
+ finalized.body = JSON.stringify(finalized.body);
432
+ }
433
+
434
+ // an embedded newline makes a header value invalid per the Fetch standard,
435
+ // so fetch throws a TypeError before sending anything. squashing repairs it,
436
+ // and since the request is captured after this, the record shows the value
437
+ // that actually went out
438
+ Object.keys(finalized.headers).forEach(headerName => {
439
+ const value = finalized.headers[headerName];
440
+ if (typeof value === 'string') {
441
+ finalized.headers[headerName] = value.replace(/\n+/g, ' ');
442
+ }
443
+ });
444
+ finalized = (await this.#requestInterceptor?.(finalized)) ?? finalized;
445
+ finalized = (await perCallInterceptor?.(finalized)) ?? finalized;
446
+
447
+ // for multipart/form-data, remove the built content-type so the transport
448
+ // sets one carrying the correct boundary
449
+ const contentType = finalized.headers['content-type'] ?? finalized.headers['Content-Type'];
450
+ if (typeof contentType === 'string' && /multipart\/form-data/i.test(contentType)) {
451
+ delete finalized.headers['content-type'];
452
+ delete finalized.headers['Content-Type'];
453
+ }
454
+ return finalized;
455
+ }
456
+ }
457
+ var _default = exports.default = OpenAPIOperationExecutor;