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