@backstage/backend-openapi-utils 0.1.18 → 0.2.0-next.1
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 +21 -0
- package/dist/constants.cjs.js +6 -0
- package/dist/constants.cjs.js.map +1 -0
- package/dist/index.cjs.js +7 -99
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/proxy/setup.cjs.js +74 -0
- package/dist/proxy/setup.cjs.js.map +1 -0
- package/dist/schema/errors.cjs.js +43 -0
- package/dist/schema/errors.cjs.js.map +1 -0
- package/dist/schema/parameter-validation.cjs.js +391 -0
- package/dist/schema/parameter-validation.cjs.js.map +1 -0
- package/dist/schema/request-body-validation.cjs.js +108 -0
- package/dist/schema/request-body-validation.cjs.js.map +1 -0
- package/dist/schema/response-body-validation.cjs.js +125 -0
- package/dist/schema/response-body-validation.cjs.js.map +1 -0
- package/dist/schema/utils.cjs.js +38 -0
- package/dist/schema/utils.cjs.js.map +1 -0
- package/dist/schema/validation.cjs.js +116 -0
- package/dist/schema/validation.cjs.js.map +1 -0
- package/dist/stub.cjs.js +89 -0
- package/dist/stub.cjs.js.map +1 -0
- package/dist/testUtils.cjs.js +43 -0
- package/dist/testUtils.cjs.js.map +1 -0
- package/dist/types/index.cjs.js +3 -0
- package/dist/types/index.cjs.js.map +1 -0
- package/package.json +27 -20
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var Ajv = require('ajv');
|
|
4
|
+
var errors = require('./errors.cjs.js');
|
|
5
|
+
var utils = require('./utils.cjs.js');
|
|
6
|
+
|
|
7
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
8
|
+
|
|
9
|
+
var Ajv__default = /*#__PURE__*/_interopDefaultCompat(Ajv);
|
|
10
|
+
|
|
11
|
+
class BaseParameterParser {
|
|
12
|
+
ajv;
|
|
13
|
+
operation;
|
|
14
|
+
parameters = {};
|
|
15
|
+
constructor(parameterIn, operation, options) {
|
|
16
|
+
this.ajv = options.ajv;
|
|
17
|
+
this.operation = operation;
|
|
18
|
+
const { schema, path, method } = operation;
|
|
19
|
+
const parameters = schema.parameters || [];
|
|
20
|
+
for (const parameter of parameters) {
|
|
21
|
+
if ("$ref" in parameter) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`[(${method}) ${path}] Reference objects are not supported`
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
if (!parameter.schema) {
|
|
27
|
+
throw new errors.OperationError(
|
|
28
|
+
operation,
|
|
29
|
+
"Schema not found for path parameter"
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
if ("$ref" in parameter.schema) {
|
|
33
|
+
throw new errors.OperationError(
|
|
34
|
+
this.operation,
|
|
35
|
+
"Reference objects are not supported for parameters"
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
if (parameter.in === parameterIn) {
|
|
39
|
+
this.parameters[parameter.name] = parameter;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Attempt to transform a string value to its expected type, this allows Ajv to perform validation. As these are parameters,
|
|
45
|
+
* support for edge cases like nested type casting is not currently supported.
|
|
46
|
+
* @param value
|
|
47
|
+
* @param schema
|
|
48
|
+
* @returns
|
|
49
|
+
*/
|
|
50
|
+
optimisticallyParseValue(value, schema) {
|
|
51
|
+
if (schema.type === "integer") {
|
|
52
|
+
return parseInt(value, 10);
|
|
53
|
+
}
|
|
54
|
+
if (schema.type === "number") {
|
|
55
|
+
return parseFloat(value);
|
|
56
|
+
}
|
|
57
|
+
if (schema.type === "boolean") {
|
|
58
|
+
if (["true", "false"].includes(value)) {
|
|
59
|
+
return value === "true";
|
|
60
|
+
}
|
|
61
|
+
throw new Error('Invalid boolean value must be either "true" or "false"');
|
|
62
|
+
}
|
|
63
|
+
return value;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
class QueryParameterParser extends BaseParameterParser {
|
|
67
|
+
constructor(operation, options) {
|
|
68
|
+
super("query", operation, options);
|
|
69
|
+
}
|
|
70
|
+
async parse(request) {
|
|
71
|
+
const { searchParams } = new URL(request.url);
|
|
72
|
+
const remainingQueryParameters = new Set(searchParams.keys());
|
|
73
|
+
const queryParameters = {};
|
|
74
|
+
let parameterIterator = Object.entries(this.parameters);
|
|
75
|
+
const isFormExplode = (parameter) => {
|
|
76
|
+
return parameter.schema?.type === "object" && (parameter.style === "form" || !parameter.style) && parameter.explode;
|
|
77
|
+
};
|
|
78
|
+
const regularParameters = parameterIterator.filter(
|
|
79
|
+
([_, parameter]) => !isFormExplode(parameter)
|
|
80
|
+
);
|
|
81
|
+
const formExplodeParameters = parameterIterator.filter(
|
|
82
|
+
([_, parameter]) => isFormExplode(parameter)
|
|
83
|
+
);
|
|
84
|
+
if (formExplodeParameters.length > 1) {
|
|
85
|
+
throw new errors.OperationError(
|
|
86
|
+
this.operation,
|
|
87
|
+
"Ambiguous query parameters, you cannot have 2 form explode parameters"
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
parameterIterator = [...regularParameters, ...formExplodeParameters];
|
|
91
|
+
for (const [name, parameter] of parameterIterator) {
|
|
92
|
+
if (!parameter.schema) {
|
|
93
|
+
throw new errors.OperationError(
|
|
94
|
+
this.operation,
|
|
95
|
+
"Schema not found for query parameter"
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
if ("$ref" in parameter.schema) {
|
|
99
|
+
throw new errors.OperationError(
|
|
100
|
+
this.operation,
|
|
101
|
+
"Reference objects are not supported for parameters"
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
let [param, indices] = this.#findQueryParameters(
|
|
105
|
+
this.parameters,
|
|
106
|
+
remainingQueryParameters,
|
|
107
|
+
searchParams,
|
|
108
|
+
name
|
|
109
|
+
);
|
|
110
|
+
if (!!param) {
|
|
111
|
+
indices.forEach((index) => remainingQueryParameters.delete(index));
|
|
112
|
+
}
|
|
113
|
+
if (parameter.schema.type !== "array" && Array.isArray(param)) {
|
|
114
|
+
param = param.length > 0 ? param[0] : void 0;
|
|
115
|
+
}
|
|
116
|
+
if (parameter.required && !indices.some((index) => searchParams.has(index))) {
|
|
117
|
+
throw new errors.OperationError(
|
|
118
|
+
this.operation,
|
|
119
|
+
`Required query parameter ${name} not found`
|
|
120
|
+
);
|
|
121
|
+
} else if (!param && !parameter.required) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (param) {
|
|
125
|
+
param = this.optimisticallyParseValue(param, parameter.schema);
|
|
126
|
+
}
|
|
127
|
+
const validate = this.ajv.compile(parameter.schema);
|
|
128
|
+
const valid = validate(param);
|
|
129
|
+
if (!valid) {
|
|
130
|
+
throw new errors.OperationParsingError(
|
|
131
|
+
this.operation,
|
|
132
|
+
"Query parameter",
|
|
133
|
+
validate.errors
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
queryParameters[name] = param;
|
|
137
|
+
}
|
|
138
|
+
if (remainingQueryParameters.size > 0) {
|
|
139
|
+
throw new errors.OperationError(
|
|
140
|
+
this.operation,
|
|
141
|
+
`Unexpected query parameters: ${Array.from(
|
|
142
|
+
remainingQueryParameters
|
|
143
|
+
).join(", ")}`
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
return queryParameters;
|
|
147
|
+
}
|
|
148
|
+
#findQueryParameters(parameters, remainingQueryParameters, searchParams, name) {
|
|
149
|
+
const parameter = parameters[name];
|
|
150
|
+
const schema = parameter.schema;
|
|
151
|
+
const getIfExists = (key) => searchParams.has(key) ? searchParams.getAll(key) : null;
|
|
152
|
+
if (schema.type === "array") {
|
|
153
|
+
if (parameter.style === "form" || typeof parameter.style === "undefined") {
|
|
154
|
+
if (parameter.explode || typeof parameter.explode === "undefined") {
|
|
155
|
+
if (!searchParams.has(name) && searchParams.has(`${name}[0]`)) {
|
|
156
|
+
const values = [];
|
|
157
|
+
const indices = [];
|
|
158
|
+
let index = 0;
|
|
159
|
+
while (searchParams.has(`${name}[${index}]`)) {
|
|
160
|
+
values.push(searchParams.get(`${name}[${index}]`));
|
|
161
|
+
indices.push(`${name}[${index}]`);
|
|
162
|
+
index++;
|
|
163
|
+
}
|
|
164
|
+
return [values, indices];
|
|
165
|
+
}
|
|
166
|
+
return [getIfExists(name), [name]];
|
|
167
|
+
}
|
|
168
|
+
if (!searchParams.has(name) && searchParams.has(`${name}[]`)) {
|
|
169
|
+
return [searchParams.get(`${name}[]`)?.split(","), [`${name}[]`]];
|
|
170
|
+
}
|
|
171
|
+
if (searchParams.has(name) && searchParams.getAll(name).length > 1) {
|
|
172
|
+
throw new errors.OperationError(
|
|
173
|
+
this.operation,
|
|
174
|
+
"Arrays must be comma separated in non-explode mode"
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
return [searchParams.get(name)?.split(","), [name]];
|
|
178
|
+
} else if (parameter.style === "spaceDelimited") {
|
|
179
|
+
return [searchParams.get(name)?.split(" "), [name]];
|
|
180
|
+
} else if (parameter.style === "pipeDelimited") {
|
|
181
|
+
return [searchParams.get(name)?.split("|"), [name]];
|
|
182
|
+
}
|
|
183
|
+
throw new errors.OperationError(
|
|
184
|
+
this.operation,
|
|
185
|
+
"Unsupported style for array parameter"
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
if (schema.type === "object") {
|
|
189
|
+
if (parameter.style === "form" || typeof parameter.style === "undefined") {
|
|
190
|
+
if (parameter.explode) {
|
|
191
|
+
const obj2 = {};
|
|
192
|
+
const indices = [];
|
|
193
|
+
for (const [key, value2] of searchParams.entries()) {
|
|
194
|
+
if (!remainingQueryParameters.has(key)) {
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
indices.push(key);
|
|
198
|
+
obj2[key] = value2;
|
|
199
|
+
}
|
|
200
|
+
return [obj2, indices];
|
|
201
|
+
}
|
|
202
|
+
const obj = {};
|
|
203
|
+
const value = searchParams.get(name);
|
|
204
|
+
if (value) {
|
|
205
|
+
const parts = value.split(",");
|
|
206
|
+
if (parts.length % 2 !== 0) {
|
|
207
|
+
throw new errors.OperationError(
|
|
208
|
+
this.operation,
|
|
209
|
+
"Invalid object query parameter, must have an even number of key-value pairs"
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
for (let i = 0; i < parts.length; i += 2) {
|
|
213
|
+
obj[parts[i]] = parts[i + 1];
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return [obj, [name]];
|
|
217
|
+
} else if (parameter.style === "deepObject") {
|
|
218
|
+
const obj = {};
|
|
219
|
+
const indices = [];
|
|
220
|
+
for (const [key, value] of searchParams.entries()) {
|
|
221
|
+
if (key.startsWith(`${name}[`)) {
|
|
222
|
+
indices.push(key);
|
|
223
|
+
const parts = key.split("[");
|
|
224
|
+
let currentLayer = obj;
|
|
225
|
+
for (let partIndex = 1; partIndex < parts.length - 1; partIndex++) {
|
|
226
|
+
const part = parts[partIndex];
|
|
227
|
+
if (!part.includes("]")) {
|
|
228
|
+
throw new errors.OperationError(
|
|
229
|
+
this.operation,
|
|
230
|
+
`Invalid object parameter, missing closing bracket for key "${key}"`
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
const objKey = part.split("]")[0];
|
|
234
|
+
if (!currentLayer[objKey]) {
|
|
235
|
+
currentLayer[objKey] = {};
|
|
236
|
+
}
|
|
237
|
+
currentLayer = currentLayer[objKey];
|
|
238
|
+
}
|
|
239
|
+
const lastPart = parts[parts.length - 1];
|
|
240
|
+
if (!lastPart.includes("]")) {
|
|
241
|
+
throw new errors.OperationError(
|
|
242
|
+
this.operation,
|
|
243
|
+
`Invalid object parameter, missing closing bracket for key "${key}"`
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
currentLayer[lastPart.split("]")[0]] = value;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return [obj, indices];
|
|
250
|
+
}
|
|
251
|
+
throw new errors.OperationError(
|
|
252
|
+
this.operation,
|
|
253
|
+
`Unsupported style for object parameter, "${parameter.style}"`
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
return [getIfExists(name), [name]];
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
class HeaderParameterParser extends BaseParameterParser {
|
|
260
|
+
constructor(operation, options) {
|
|
261
|
+
super("header", operation, options);
|
|
262
|
+
}
|
|
263
|
+
async parse(request) {
|
|
264
|
+
const headerParameters = {};
|
|
265
|
+
for (const [name, parameter] of Object.entries(this.parameters)) {
|
|
266
|
+
const header = request.headers.get(name);
|
|
267
|
+
if (!header) {
|
|
268
|
+
if (parameter.required) {
|
|
269
|
+
throw new errors.OperationError(
|
|
270
|
+
this.operation,
|
|
271
|
+
`Header parameter ${name} not found`
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
if (!parameter.schema) {
|
|
277
|
+
throw new errors.OperationError(
|
|
278
|
+
this.operation,
|
|
279
|
+
"Schema not found for header parameter"
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
if ("$ref" in parameter.schema) {
|
|
283
|
+
throw new errors.OperationError(
|
|
284
|
+
this.operation,
|
|
285
|
+
"Reference objects are not supported for parameters"
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
const validate = this.ajv.compile(parameter.schema);
|
|
289
|
+
const valid = validate(header);
|
|
290
|
+
if (!valid) {
|
|
291
|
+
throw new errors.OperationParsingError(
|
|
292
|
+
this.operation,
|
|
293
|
+
"Header parameter",
|
|
294
|
+
validate.errors
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
headerParameters[name] = header;
|
|
298
|
+
}
|
|
299
|
+
return headerParameters;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
class PathParameterParser extends BaseParameterParser {
|
|
303
|
+
constructor(operation, options) {
|
|
304
|
+
super("path", operation, options);
|
|
305
|
+
}
|
|
306
|
+
async parse(request) {
|
|
307
|
+
const { pathname } = new URL(request.url);
|
|
308
|
+
const params = PathParameterParser.parsePath({
|
|
309
|
+
operation: this.operation,
|
|
310
|
+
path: pathname,
|
|
311
|
+
schema: this.operation.path
|
|
312
|
+
});
|
|
313
|
+
const pathParameters = {};
|
|
314
|
+
for (const [name, parameter] of Object.entries(this.parameters)) {
|
|
315
|
+
let param = params[name];
|
|
316
|
+
if (!param && parameter.required) {
|
|
317
|
+
throw new errors.OperationError(
|
|
318
|
+
this.operation,
|
|
319
|
+
`Path parameter ${name} not found`
|
|
320
|
+
);
|
|
321
|
+
} else if (!params[name] && !parameter.required) {
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
if (param) {
|
|
325
|
+
param = this.optimisticallyParseValue(param, parameter.schema);
|
|
326
|
+
}
|
|
327
|
+
const validate = this.ajv.compile(parameter.schema);
|
|
328
|
+
const valid = validate(param);
|
|
329
|
+
if (!valid) {
|
|
330
|
+
throw new errors.OperationParsingError(
|
|
331
|
+
this.operation,
|
|
332
|
+
"Path parameter",
|
|
333
|
+
validate.errors
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
pathParameters[name] = param;
|
|
337
|
+
}
|
|
338
|
+
return pathParameters;
|
|
339
|
+
}
|
|
340
|
+
static parsePath({
|
|
341
|
+
operation,
|
|
342
|
+
schema,
|
|
343
|
+
path
|
|
344
|
+
}) {
|
|
345
|
+
const parts = path.split("/");
|
|
346
|
+
const pathParts = schema.split("/");
|
|
347
|
+
if (parts.length !== pathParts.length) {
|
|
348
|
+
throw new errors.OperationError(operation, "Path parts do not match");
|
|
349
|
+
}
|
|
350
|
+
const params = {};
|
|
351
|
+
for (let i = 0; i < parts.length; i++) {
|
|
352
|
+
if (pathParts[i] === parts[i]) {
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
if (pathParts[i].startsWith("{") && pathParts[i].endsWith("}")) {
|
|
356
|
+
params[pathParts[i].slice(1, -1)] = parts[i];
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
break;
|
|
360
|
+
}
|
|
361
|
+
return params;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
class ParameterValidator {
|
|
365
|
+
schema;
|
|
366
|
+
cache = {};
|
|
367
|
+
constructor(schema) {
|
|
368
|
+
this.schema = schema;
|
|
369
|
+
}
|
|
370
|
+
async validate({ pair: { request, response }, operation }) {
|
|
371
|
+
if (response.statusCode === 400) {
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
const ajv = new Ajv__default.default();
|
|
375
|
+
const queryParser = new QueryParameterParser(operation, { ajv });
|
|
376
|
+
const headerParser = new HeaderParameterParser(operation, { ajv });
|
|
377
|
+
const pathParser = new PathParameterParser(operation, { ajv });
|
|
378
|
+
const fetchRequest = utils.mockttpToFetchRequest(request);
|
|
379
|
+
await Promise.all([
|
|
380
|
+
queryParser.parse(fetchRequest),
|
|
381
|
+
headerParser.parse(fetchRequest),
|
|
382
|
+
pathParser.parse(fetchRequest)
|
|
383
|
+
]);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
exports.HeaderParameterParser = HeaderParameterParser;
|
|
388
|
+
exports.ParameterValidator = ParameterValidator;
|
|
389
|
+
exports.PathParameterParser = PathParameterParser;
|
|
390
|
+
exports.QueryParameterParser = QueryParameterParser;
|
|
391
|
+
//# sourceMappingURL=parameter-validation.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parameter-validation.cjs.js","sources":["../../src/schema/parameter-validation.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { OpenAPIObject, ParameterObject, SchemaObject } from 'openapi3-ts';\nimport {\n Operation,\n ParserOptions,\n RequestParser,\n Validator,\n ValidatorParams,\n} from './types';\nimport Ajv from 'ajv';\nimport { OperationError, OperationParsingError } from './errors';\nimport { mockttpToFetchRequest } from './utils';\n\ntype ReferencelessSchemaObject = SchemaObject & { $ref?: never };\n\ntype ReferencelessParameterObject = Omit<ParameterObject, 'schema'> & {\n schema: ReferencelessSchemaObject;\n};\n\nclass BaseParameterParser {\n ajv: Ajv;\n operation: Operation;\n parameters: Record<string, ReferencelessParameterObject> = {};\n constructor(\n parameterIn: string,\n operation: Operation,\n options: ParserOptions,\n ) {\n this.ajv = options.ajv;\n this.operation = operation;\n const { schema, path, method } = operation;\n const parameters = schema.parameters || [];\n for (const parameter of parameters) {\n if ('$ref' in parameter) {\n throw new Error(\n `[(${method}) ${path}] Reference objects are not supported`,\n );\n }\n\n if (!parameter.schema) {\n throw new OperationError(\n operation,\n 'Schema not found for path parameter',\n );\n }\n if ('$ref' in parameter.schema) {\n throw new OperationError(\n this.operation,\n 'Reference objects are not supported for parameters',\n );\n }\n if (parameter.in === parameterIn) {\n this.parameters[parameter.name] =\n parameter as ReferencelessParameterObject;\n }\n }\n }\n\n /**\n * Attempt to transform a string value to its expected type, this allows Ajv to perform validation. As these are parameters,\n * support for edge cases like nested type casting is not currently supported.\n * @param value\n * @param schema\n * @returns\n */\n optimisticallyParseValue(value: string, schema: SchemaObject) {\n if (schema.type === 'integer') {\n return parseInt(value, 10);\n }\n if (schema.type === 'number') {\n return parseFloat(value);\n }\n if (schema.type === 'boolean') {\n if (['true', 'false'].includes(value)) {\n return value === 'true';\n }\n throw new Error('Invalid boolean value must be either \"true\" or \"false\"');\n }\n return value;\n }\n}\n\nexport class QueryParameterParser\n extends BaseParameterParser\n implements RequestParser<Record<string, any>>\n{\n constructor(operation: Operation, options: ParserOptions) {\n super('query', operation, options);\n }\n async parse(request: Request) {\n const { searchParams } = new URL(request.url);\n const remainingQueryParameters = new Set<string>(searchParams.keys());\n const queryParameters: Record<string, any> = {};\n\n let parameterIterator = Object.entries(this.parameters);\n\n const isFormExplode = (parameter: ReferencelessParameterObject) => {\n return (\n parameter.schema?.type === 'object' &&\n (parameter.style === 'form' || !parameter.style) &&\n parameter.explode\n );\n };\n\n const regularParameters = parameterIterator.filter(\n ([_, parameter]) => !isFormExplode(parameter),\n );\n\n const formExplodeParameters = parameterIterator.filter(([_, parameter]) =>\n isFormExplode(parameter),\n );\n\n if (formExplodeParameters.length > 1) {\n throw new OperationError(\n this.operation,\n 'Ambiguous query parameters, you cannot have 2 form explode parameters',\n );\n }\n\n // Sort the parameters so that form explode parameters are processed last.\n parameterIterator = [...regularParameters, ...formExplodeParameters];\n\n for (const [name, parameter] of parameterIterator) {\n if (!parameter.schema) {\n throw new OperationError(\n this.operation,\n 'Schema not found for query parameter',\n );\n }\n if ('$ref' in parameter.schema) {\n throw new OperationError(\n this.operation,\n 'Reference objects are not supported for parameters',\n );\n }\n // eslint-disable-next-line prefer-const\n let [param, indices]: [any | null, string[]] = this.#findQueryParameters(\n this.parameters,\n remainingQueryParameters,\n searchParams,\n name,\n );\n if (!!param) {\n indices.forEach(index => remainingQueryParameters.delete(index));\n }\n\n // The query parameters can be either a single value or an array of values, try to wrangle them into the expected format if they're not explicitly an array.\n if (parameter.schema.type !== 'array' && Array.isArray(param)) {\n param = param.length > 0 ? param[0] : undefined;\n }\n if (\n parameter.required &&\n !indices.some(index => searchParams.has(index))\n ) {\n throw new OperationError(\n this.operation,\n `Required query parameter ${name} not found`,\n );\n } else if (!param && !parameter.required) {\n continue;\n }\n if (param) {\n // We do this here because all query parameters are strings but the schema will expect the real value.\n param = this.optimisticallyParseValue(param, parameter.schema);\n }\n const validate = this.ajv.compile(parameter.schema);\n const valid = validate(param);\n if (!valid) {\n throw new OperationParsingError(\n this.operation,\n 'Query parameter',\n validate.errors!,\n );\n }\n queryParameters[name] = param;\n }\n if (remainingQueryParameters.size > 0) {\n throw new OperationError(\n this.operation,\n `Unexpected query parameters: ${Array.from(\n remainingQueryParameters,\n ).join(', ')}`,\n );\n }\n return queryParameters;\n }\n\n #findQueryParameters(\n parameters: Record<string, ParameterObject>,\n remainingQueryParameters: Set<string>,\n searchParams: URLSearchParams,\n name: string,\n ): [any | null, string[]] {\n const parameter = parameters[name];\n const schema = parameter.schema as SchemaObject;\n\n // Since getAll will return an empty array if the key is not found, we need to check if the key exists first.\n const getIfExists = (key: string) =>\n searchParams.has(key) ? searchParams.getAll(key) : null;\n\n if (schema.type === 'array') {\n // Form is the default array format.\n if (\n parameter.style === 'form' ||\n typeof parameter.style === 'undefined'\n ) {\n // As is explode = true.\n if (parameter.explode || typeof parameter.explode === 'undefined') {\n // Support for qs explode format. Every value is stored as a separate query parameter.\n if (!searchParams.has(name) && searchParams.has(`${name}[0]`)) {\n const values: string[] = [];\n const indices: string[] = [];\n let index = 0;\n while (searchParams.has(`${name}[${index}]`)) {\n values.push(searchParams.get(`${name}[${index}]`)!);\n indices.push(`${name}[${index}]`);\n index++;\n }\n return [values, indices];\n }\n // If not qs format, grab all values with the same name from search params.\n return [getIfExists(name), [name]];\n }\n // Add support for qs non-standard array format. This is helpful for search-backend, since that uses qs still.\n if (!searchParams.has(name) && searchParams.has(`${name}[]`)) {\n return [searchParams.get(`${name}[]`)?.split(','), [`${name}[]`]];\n }\n // Non-explode arrays should be comma separated.\n if (searchParams.has(name) && searchParams.getAll(name).length > 1) {\n throw new OperationError(\n this.operation,\n 'Arrays must be comma separated in non-explode mode',\n );\n }\n return [searchParams.get(name)?.split(','), [name]];\n } else if (parameter.style === 'spaceDelimited') {\n return [searchParams.get(name)?.split(' '), [name]];\n } else if (parameter.style === 'pipeDelimited') {\n return [searchParams.get(name)?.split('|'), [name]];\n }\n throw new OperationError(\n this.operation,\n 'Unsupported style for array parameter',\n );\n }\n if (schema.type === 'object') {\n // Form is the default object format.\n if (\n parameter.style === 'form' ||\n typeof parameter.style === 'undefined'\n ) {\n if (parameter.explode) {\n // Object form/explode is a collection of disjoint keys, there's no mapping for what they are so we collect all of them.\n // This means we need to run this as the last query parameter that is processed.\n const obj: Record<string, string> = {};\n const indices: string[] = [];\n for (const [key, value] of searchParams.entries()) {\n // Have we processed this query parameter as part of another parameter parsing? If not, consider it to be a part of this object.\n if (!remainingQueryParameters.has(key)) {\n continue;\n }\n indices.push(key);\n obj[key] = value;\n }\n return [obj, indices];\n }\n // For non-explode, the schema is comma separated key,value \"pairs\", so filter=key1,value1,key2,value2 would parse to {key1: value1, key2: value2}.\n const obj: Record<string, string> = {};\n const value = searchParams.get(name);\n if (value) {\n const parts = value.split(',');\n if (parts.length % 2 !== 0) {\n throw new OperationError(\n this.operation,\n 'Invalid object query parameter, must have an even number of key-value pairs',\n );\n }\n for (let i = 0; i < parts.length; i += 2) {\n obj[parts[i]] = parts[i + 1];\n }\n }\n return [obj, [name]];\n } else if (parameter.style === 'deepObject') {\n // Deep object is a nested object structure, so we need to parse the keys to build the object.\n // example: ?filter[key1]=value1&filter[key2]=value2 => { key1: value1, key2: value2 }\n const obj: Record<string, any> = {};\n const indices: string[] = [];\n for (const [key, value] of searchParams.entries()) {\n if (key.startsWith(`${name}[`)) {\n indices.push(key);\n const parts = key.split('[');\n let currentLayer = obj;\n for (let partIndex = 1; partIndex < parts.length - 1; partIndex++) {\n const part = parts[partIndex];\n if (!part.includes(']')) {\n throw new OperationError(\n this.operation,\n `Invalid object parameter, missing closing bracket for key \"${key}\"`,\n );\n }\n const objKey = part.split(']')[0];\n if (!currentLayer[objKey]) {\n currentLayer[objKey] = {};\n }\n currentLayer = currentLayer[objKey];\n }\n const lastPart = parts[parts.length - 1];\n if (!lastPart.includes(']')) {\n throw new OperationError(\n this.operation,\n `Invalid object parameter, missing closing bracket for key \"${key}\"`,\n );\n }\n currentLayer[lastPart.split(']')[0]] = value;\n }\n }\n return [obj, indices];\n }\n throw new OperationError(\n this.operation,\n `Unsupported style for object parameter, \"${parameter.style}\"`,\n );\n }\n // For everything else, just return the value.\n return [getIfExists(name), [name]];\n }\n}\n\nexport class HeaderParameterParser\n extends BaseParameterParser\n implements RequestParser<Record<string, any>>\n{\n constructor(operation: Operation, options: ParserOptions) {\n super('header', operation, options);\n }\n async parse(request: Request) {\n const headerParameters: Record<string, any> = {};\n for (const [name, parameter] of Object.entries(this.parameters)) {\n const header = request.headers.get(name);\n if (!header) {\n if (parameter.required) {\n throw new OperationError(\n this.operation,\n `Header parameter ${name} not found`,\n );\n }\n continue;\n }\n if (!parameter.schema) {\n throw new OperationError(\n this.operation,\n 'Schema not found for header parameter',\n );\n }\n if ('$ref' in parameter.schema) {\n throw new OperationError(\n this.operation,\n 'Reference objects are not supported for parameters',\n );\n }\n const validate = this.ajv.compile(parameter.schema);\n const valid = validate(header);\n\n if (!valid) {\n throw new OperationParsingError(\n this.operation,\n 'Header parameter',\n validate.errors!,\n );\n }\n headerParameters[name] = header;\n }\n return headerParameters;\n }\n}\n\nexport class PathParameterParser\n extends BaseParameterParser\n implements RequestParser<Record<string, any>>\n{\n constructor(operation: Operation, options: ParserOptions) {\n super('path', operation, options);\n }\n async parse(request: Request) {\n const { pathname } = new URL(request.url);\n const params = PathParameterParser.parsePath({\n operation: this.operation,\n path: pathname,\n schema: this.operation.path,\n });\n const pathParameters: Record<string, any> = {};\n for (const [name, parameter] of Object.entries(this.parameters)) {\n let param: string | number | boolean = params[name];\n if (!param && parameter.required) {\n throw new OperationError(\n this.operation,\n `Path parameter ${name} not found`,\n );\n } else if (!params[name] && !parameter.required) {\n continue;\n }\n\n if (param) {\n param = this.optimisticallyParseValue(param, parameter.schema);\n }\n\n const validate = this.ajv.compile(parameter.schema);\n const valid = validate(param);\n\n if (!valid) {\n throw new OperationParsingError(\n this.operation,\n 'Path parameter',\n validate.errors!,\n );\n }\n pathParameters[name] = param;\n }\n return pathParameters;\n }\n\n static parsePath({\n operation,\n schema,\n path,\n }: {\n operation: Operation;\n schema: string;\n path: string;\n }) {\n const parts = path.split('/');\n const pathParts = schema.split('/');\n if (parts.length !== pathParts.length) {\n throw new OperationError(operation, 'Path parts do not match');\n }\n const params: Record<string, string> = {};\n for (let i = 0; i < parts.length; i++) {\n if (pathParts[i] === parts[i]) {\n continue;\n }\n if (pathParts[i].startsWith('{') && pathParts[i].endsWith('}')) {\n params[pathParts[i].slice(1, -1)] = parts[i];\n continue;\n }\n break;\n }\n return params;\n }\n}\n\nexport class ParameterValidator implements Validator {\n schema: OpenAPIObject;\n cache: Record<string, any> = {};\n constructor(schema: OpenAPIObject) {\n this.schema = schema;\n }\n\n async validate({ pair: { request, response }, operation }: ValidatorParams) {\n if (response.statusCode === 400) {\n // If the response is a 400, then the request is invalid and we shouldn't validate the parameters\n return;\n }\n\n const ajv = new Ajv();\n const queryParser = new QueryParameterParser(operation, { ajv });\n const headerParser = new HeaderParameterParser(operation, { ajv });\n const pathParser = new PathParameterParser(operation, { ajv });\n\n const fetchRequest = mockttpToFetchRequest(request);\n\n await Promise.all([\n queryParser.parse(fetchRequest),\n headerParser.parse(fetchRequest),\n pathParser.parse(fetchRequest),\n ]);\n }\n}\n"],"names":["OperationError","OperationParsingError","obj","value","Ajv","mockttpToFetchRequest"],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var errors = require('./errors.cjs.js');
|
|
4
|
+
|
|
5
|
+
class DisabledRequestBodyParser {
|
|
6
|
+
operation;
|
|
7
|
+
constructor(operation) {
|
|
8
|
+
this.operation = operation;
|
|
9
|
+
}
|
|
10
|
+
async parse(request) {
|
|
11
|
+
const bodyText = await request.text();
|
|
12
|
+
if (bodyText?.length) {
|
|
13
|
+
throw new errors.OperationError(
|
|
14
|
+
this.operation,
|
|
15
|
+
"Received a body but no schema was found"
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
return void 0;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
class RequestBodyParser {
|
|
22
|
+
operation;
|
|
23
|
+
disabled = false;
|
|
24
|
+
validate;
|
|
25
|
+
schema;
|
|
26
|
+
requestBodySchema;
|
|
27
|
+
static fromOperation(operation, options) {
|
|
28
|
+
return operation.schema.requestBody ? new RequestBodyParser(operation, options) : new DisabledRequestBodyParser(operation);
|
|
29
|
+
}
|
|
30
|
+
constructor(operation, options) {
|
|
31
|
+
this.operation = operation;
|
|
32
|
+
const { schema: operationSchema } = this.operation;
|
|
33
|
+
const requestBody = operationSchema.requestBody;
|
|
34
|
+
if (!requestBody) {
|
|
35
|
+
throw new errors.OperationError(
|
|
36
|
+
this.operation,
|
|
37
|
+
"No request body found in operation"
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
if ("$ref" in requestBody) {
|
|
41
|
+
throw new errors.OperationError(
|
|
42
|
+
this.operation,
|
|
43
|
+
"Reference objects are not supported"
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
if (!requestBody.content) {
|
|
47
|
+
throw new errors.OperationError(
|
|
48
|
+
this.operation,
|
|
49
|
+
"No content found in request body"
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
const contentTypes = requestBody.content;
|
|
53
|
+
const jsonContentType = Object.keys(contentTypes).find(
|
|
54
|
+
(contentType) => contentType.split(";").includes("application/json")
|
|
55
|
+
);
|
|
56
|
+
if (!jsonContentType) {
|
|
57
|
+
throw new errors.OperationError(
|
|
58
|
+
this.operation,
|
|
59
|
+
"No application/json content type found in request body"
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
const schema = requestBody.content[jsonContentType].schema;
|
|
63
|
+
if (!schema) {
|
|
64
|
+
throw new errors.OperationError(
|
|
65
|
+
this.operation,
|
|
66
|
+
"No JSON schema found in request body"
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
if ("$ref" in schema) {
|
|
70
|
+
throw new errors.OperationError(
|
|
71
|
+
this.operation,
|
|
72
|
+
"Reference objects are not supported"
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
this.validate = options.ajv.compile(schema);
|
|
76
|
+
this.schema = schema;
|
|
77
|
+
this.requestBodySchema = requestBody;
|
|
78
|
+
}
|
|
79
|
+
async parse(request) {
|
|
80
|
+
const bodyText = await request.text();
|
|
81
|
+
if (this.requestBodySchema.required && !bodyText?.length) {
|
|
82
|
+
throw new errors.OperationError(
|
|
83
|
+
this.operation,
|
|
84
|
+
`No request body found for ${request.url}`
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
const contentType = request.headers.get("content-type") || "application/json";
|
|
88
|
+
if (!contentType.split(";").includes("application/json")) {
|
|
89
|
+
throw new errors.OperationError(
|
|
90
|
+
this.operation,
|
|
91
|
+
"Content type is not application/json"
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
const body = await request.json();
|
|
95
|
+
const valid = this.validate(body);
|
|
96
|
+
if (!valid) {
|
|
97
|
+
throw new errors.OperationParsingError(
|
|
98
|
+
this.operation,
|
|
99
|
+
`Request body`,
|
|
100
|
+
this.validate.errors
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
return body;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
exports.RequestBodyParser = RequestBodyParser;
|
|
108
|
+
//# sourceMappingURL=request-body-validation.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-body-validation.cjs.js","sources":["../../src/schema/request-body-validation.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { JsonObject } from '@backstage/types';\nimport { Operation, ParserOptions, RequestParser } from './types';\nimport { ValidateFunction } from 'ajv';\nimport { OperationError, OperationParsingError } from './errors';\nimport { RequestBodyObject, SchemaObject } from 'openapi3-ts';\n\nclass DisabledRequestBodyParser\n implements RequestParser<JsonObject | undefined>\n{\n operation: Operation;\n constructor(operation: Operation) {\n this.operation = operation;\n }\n async parse(request: Request): Promise<JsonObject | undefined> {\n const bodyText = await request.text();\n if (bodyText?.length) {\n throw new OperationError(\n this.operation,\n 'Received a body but no schema was found',\n );\n }\n return undefined;\n }\n}\nexport class RequestBodyParser\n implements RequestParser<JsonObject | undefined>\n{\n operation: Operation;\n disabled: boolean = false;\n validate!: ValidateFunction;\n schema!: SchemaObject;\n requestBodySchema!: RequestBodyObject;\n\n static fromOperation(operation: Operation, options: ParserOptions) {\n return operation.schema.requestBody\n ? new RequestBodyParser(operation, options)\n : new DisabledRequestBodyParser(operation);\n }\n\n constructor(operation: Operation, options: ParserOptions) {\n this.operation = operation;\n const { schema: operationSchema } = this.operation;\n const requestBody = operationSchema.requestBody;\n\n if (!requestBody) {\n throw new OperationError(\n this.operation,\n 'No request body found in operation',\n );\n }\n\n if ('$ref' in requestBody!) {\n throw new OperationError(\n this.operation,\n 'Reference objects are not supported',\n );\n }\n if (!requestBody!.content) {\n throw new OperationError(\n this.operation,\n 'No content found in request body',\n );\n }\n const contentTypes = requestBody!.content;\n const jsonContentType = Object.keys(contentTypes).find(contentType =>\n contentType.split(';').includes('application/json'),\n );\n if (!jsonContentType) {\n throw new OperationError(\n this.operation,\n 'No application/json content type found in request body',\n );\n }\n const schema = requestBody!.content[jsonContentType].schema;\n if (!schema) {\n throw new OperationError(\n this.operation,\n 'No JSON schema found in request body',\n );\n }\n if ('$ref' in schema) {\n throw new OperationError(\n this.operation,\n 'Reference objects are not supported',\n );\n }\n this.validate = options.ajv.compile(schema);\n this.schema = schema;\n this.requestBodySchema = requestBody;\n }\n async parse(request: Request): Promise<JsonObject | undefined> {\n const bodyText = await request.text();\n if (this.requestBodySchema.required && !bodyText?.length) {\n throw new OperationError(\n this.operation,\n `No request body found for ${request.url}`,\n );\n }\n\n const contentType =\n request.headers.get('content-type') || 'application/json';\n if (!contentType.split(';').includes('application/json')) {\n throw new OperationError(\n this.operation,\n 'Content type is not application/json',\n );\n }\n const body = (await request.json()) as JsonObject;\n const valid = this.validate(body);\n if (!valid) {\n throw new OperationParsingError(\n this.operation,\n `Request body`,\n this.validate.errors!,\n );\n }\n return body;\n }\n}\n"],"names":["OperationError","OperationParsingError"],"mappings":";;;;AAsBA,MAAM,yBAEN,CAAA;AAAA,EACE,SAAA,CAAA;AAAA,EACA,YAAY,SAAsB,EAAA;AAChC,IAAA,IAAA,CAAK,SAAY,GAAA,SAAA,CAAA;AAAA,GACnB;AAAA,EACA,MAAM,MAAM,OAAmD,EAAA;AAC7D,IAAM,MAAA,QAAA,GAAW,MAAM,OAAA,CAAQ,IAAK,EAAA,CAAA;AACpC,IAAA,IAAI,UAAU,MAAQ,EAAA;AACpB,MAAA,MAAM,IAAIA,qBAAA;AAAA,QACR,IAAK,CAAA,SAAA;AAAA,QACL,yCAAA;AAAA,OACF,CAAA;AAAA,KACF;AACA,IAAO,OAAA,KAAA,CAAA,CAAA;AAAA,GACT;AACF,CAAA;AACO,MAAM,iBAEb,CAAA;AAAA,EACE,SAAA,CAAA;AAAA,EACA,QAAoB,GAAA,KAAA,CAAA;AAAA,EACpB,QAAA,CAAA;AAAA,EACA,MAAA,CAAA;AAAA,EACA,iBAAA,CAAA;AAAA,EAEA,OAAO,aAAc,CAAA,SAAA,EAAsB,OAAwB,EAAA;AACjE,IAAO,OAAA,SAAA,CAAU,MAAO,CAAA,WAAA,GACpB,IAAI,iBAAA,CAAkB,WAAW,OAAO,CAAA,GACxC,IAAI,yBAAA,CAA0B,SAAS,CAAA,CAAA;AAAA,GAC7C;AAAA,EAEA,WAAA,CAAY,WAAsB,OAAwB,EAAA;AACxD,IAAA,IAAA,CAAK,SAAY,GAAA,SAAA,CAAA;AACjB,IAAA,MAAM,EAAE,MAAA,EAAQ,eAAgB,EAAA,GAAI,IAAK,CAAA,SAAA,CAAA;AACzC,IAAA,MAAM,cAAc,eAAgB,CAAA,WAAA,CAAA;AAEpC,IAAA,IAAI,CAAC,WAAa,EAAA;AAChB,MAAA,MAAM,IAAIA,qBAAA;AAAA,QACR,IAAK,CAAA,SAAA;AAAA,QACL,oCAAA;AAAA,OACF,CAAA;AAAA,KACF;AAEA,IAAA,IAAI,UAAU,WAAc,EAAA;AAC1B,MAAA,MAAM,IAAIA,qBAAA;AAAA,QACR,IAAK,CAAA,SAAA;AAAA,QACL,qCAAA;AAAA,OACF,CAAA;AAAA,KACF;AACA,IAAI,IAAA,CAAC,YAAa,OAAS,EAAA;AACzB,MAAA,MAAM,IAAIA,qBAAA;AAAA,QACR,IAAK,CAAA,SAAA;AAAA,QACL,kCAAA;AAAA,OACF,CAAA;AAAA,KACF;AACA,IAAA,MAAM,eAAe,WAAa,CAAA,OAAA,CAAA;AAClC,IAAA,MAAM,eAAkB,GAAA,MAAA,CAAO,IAAK,CAAA,YAAY,CAAE,CAAA,IAAA;AAAA,MAAK,iBACrD,WAAY,CAAA,KAAA,CAAM,GAAG,CAAA,CAAE,SAAS,kBAAkB,CAAA;AAAA,KACpD,CAAA;AACA,IAAA,IAAI,CAAC,eAAiB,EAAA;AACpB,MAAA,MAAM,IAAIA,qBAAA;AAAA,QACR,IAAK,CAAA,SAAA;AAAA,QACL,wDAAA;AAAA,OACF,CAAA;AAAA,KACF;AACA,IAAA,MAAM,MAAS,GAAA,WAAA,CAAa,OAAQ,CAAA,eAAe,CAAE,CAAA,MAAA,CAAA;AACrD,IAAA,IAAI,CAAC,MAAQ,EAAA;AACX,MAAA,MAAM,IAAIA,qBAAA;AAAA,QACR,IAAK,CAAA,SAAA;AAAA,QACL,sCAAA;AAAA,OACF,CAAA;AAAA,KACF;AACA,IAAA,IAAI,UAAU,MAAQ,EAAA;AACpB,MAAA,MAAM,IAAIA,qBAAA;AAAA,QACR,IAAK,CAAA,SAAA;AAAA,QACL,qCAAA;AAAA,OACF,CAAA;AAAA,KACF;AACA,IAAA,IAAA,CAAK,QAAW,GAAA,OAAA,CAAQ,GAAI,CAAA,OAAA,CAAQ,MAAM,CAAA,CAAA;AAC1C,IAAA,IAAA,CAAK,MAAS,GAAA,MAAA,CAAA;AACd,IAAA,IAAA,CAAK,iBAAoB,GAAA,WAAA,CAAA;AAAA,GAC3B;AAAA,EACA,MAAM,MAAM,OAAmD,EAAA;AAC7D,IAAM,MAAA,QAAA,GAAW,MAAM,OAAA,CAAQ,IAAK,EAAA,CAAA;AACpC,IAAA,IAAI,IAAK,CAAA,iBAAA,CAAkB,QAAY,IAAA,CAAC,UAAU,MAAQ,EAAA;AACxD,MAAA,MAAM,IAAIA,qBAAA;AAAA,QACR,IAAK,CAAA,SAAA;AAAA,QACL,CAAA,0BAAA,EAA6B,QAAQ,GAAG,CAAA,CAAA;AAAA,OAC1C,CAAA;AAAA,KACF;AAEA,IAAA,MAAM,WACJ,GAAA,OAAA,CAAQ,OAAQ,CAAA,GAAA,CAAI,cAAc,CAAK,IAAA,kBAAA,CAAA;AACzC,IAAA,IAAI,CAAC,WAAY,CAAA,KAAA,CAAM,GAAG,CAAE,CAAA,QAAA,CAAS,kBAAkB,CAAG,EAAA;AACxD,MAAA,MAAM,IAAIA,qBAAA;AAAA,QACR,IAAK,CAAA,SAAA;AAAA,QACL,sCAAA;AAAA,OACF,CAAA;AAAA,KACF;AACA,IAAM,MAAA,IAAA,GAAQ,MAAM,OAAA,CAAQ,IAAK,EAAA,CAAA;AACjC,IAAM,MAAA,KAAA,GAAQ,IAAK,CAAA,QAAA,CAAS,IAAI,CAAA,CAAA;AAChC,IAAA,IAAI,CAAC,KAAO,EAAA;AACV,MAAA,MAAM,IAAIC,4BAAA;AAAA,QACR,IAAK,CAAA,SAAA;AAAA,QACL,CAAA,YAAA,CAAA;AAAA,QACA,KAAK,QAAS,CAAA,MAAA;AAAA,OAChB,CAAA;AAAA,KACF;AACA,IAAO,OAAA,IAAA,CAAA;AAAA,GACT;AACF;;;;"}
|