@databehave/openapi 0.0.0-stage → 0.2.0
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 +32 -0
- package/LICENSE +21 -0
- package/README.md +93 -2
- package/dist/catalog.d.ts +51 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +90 -0
- package/dist/catalog.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/request-validation.d.ts +65 -0
- package/dist/middleware/request-validation.d.ts.map +1 -0
- package/dist/middleware/request-validation.js +353 -0
- package/dist/middleware/request-validation.js.map +1 -0
- package/dist/mock-mode-plugin.d.ts +5 -0
- package/dist/mock-mode-plugin.d.ts.map +1 -0
- package/dist/mock-mode-plugin.js +20 -0
- package/dist/mock-mode-plugin.js.map +1 -0
- package/dist/mock-mode.d.ts +76 -0
- package/dist/mock-mode.d.ts.map +1 -0
- package/dist/mock-mode.js +93 -0
- package/dist/mock-mode.js.map +1 -0
- package/dist/openapi/auto-schema.d.ts +3 -0
- package/dist/openapi/auto-schema.d.ts.map +1 -0
- package/dist/openapi/auto-schema.js +10 -0
- package/dist/openapi/auto-schema.js.map +1 -0
- package/dist/openapi/generate.d.ts +8 -0
- package/dist/openapi/generate.d.ts.map +1 -0
- package/dist/openapi/generate.js +121 -0
- package/dist/openapi/generate.js.map +1 -0
- package/dist/openapi/loader.d.ts +18 -0
- package/dist/openapi/loader.d.ts.map +1 -0
- package/dist/openapi/loader.js +32 -0
- package/dist/openapi/loader.js.map +1 -0
- package/dist/openapi/seed.d.ts +17 -0
- package/dist/openapi/seed.d.ts.map +1 -0
- package/dist/openapi/seed.js +58 -0
- package/dist/openapi/seed.js.map +1 -0
- package/dist/openapi/translate.d.ts +14 -0
- package/dist/openapi/translate.d.ts.map +1 -0
- package/dist/openapi/translate.js +312 -0
- package/dist/openapi/translate.js.map +1 -0
- package/dist/openapi/walker.d.ts +37 -0
- package/dist/openapi/walker.d.ts.map +1 -0
- package/dist/openapi/walker.js +2 -0
- package/dist/openapi/walker.js.map +1 -0
- package/dist/placeholder.d.ts +7 -0
- package/dist/placeholder.d.ts.map +1 -0
- package/dist/placeholder.js +17 -0
- package/dist/placeholder.js.map +1 -0
- package/dist/plugin.d.ts +10 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +43 -0
- package/dist/plugin.js.map +1 -0
- package/dist/request-validation-plugin.d.ts +8 -0
- package/dist/request-validation-plugin.d.ts.map +1 -0
- package/dist/request-validation-plugin.js +24 -0
- package/dist/request-validation-plugin.js.map +1 -0
- package/dist/schema.d.ts +18 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +26 -0
- package/dist/schema.js.map +1 -0
- package/dist/validation/validate.d.ts +40 -0
- package/dist/validation/validate.d.ts.map +1 -0
- package/dist/validation/validate.js +378 -0
- package/dist/validation/validate.js.map +1 -0
- package/package.json +55 -3
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
import { matchPattern, parseRoutePattern } from '@databehave/server';
|
|
2
|
+
import { compileValidator } from '../validation/validate.js';
|
|
3
|
+
const PROBLEM_TYPE_BASE = 'https://github.com/ochairo/databehave/blob/main/docs/errors';
|
|
4
|
+
const PROBLEM_TYPE_SLUG = {
|
|
5
|
+
400: 'malformed-body',
|
|
6
|
+
401: 'unauthorized',
|
|
7
|
+
413: 'payload-too-large',
|
|
8
|
+
415: 'unsupported-media-type',
|
|
9
|
+
422: 'request-validation',
|
|
10
|
+
};
|
|
11
|
+
const problemType = (status) => `${PROBLEM_TYPE_BASE}/${PROBLEM_TYPE_SLUG[status] ?? 'request-validation'}.md`;
|
|
12
|
+
// Default cap on request-body size (bytes). Matches the express
|
|
13
|
+
// `body-parser` default; raise via `validation.maxBodyBytes` only if
|
|
14
|
+
// the spec genuinely demands large bodies.
|
|
15
|
+
const DEFAULT_MAX_BODY_BYTES = 102400;
|
|
16
|
+
const STATUS_TITLES = {
|
|
17
|
+
400: 'Malformed request',
|
|
18
|
+
401: 'Unauthorized',
|
|
19
|
+
413: 'Payload too large',
|
|
20
|
+
415: 'Unsupported media type',
|
|
21
|
+
422: 'Request validation failed',
|
|
22
|
+
};
|
|
23
|
+
const isObj = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
24
|
+
const resolveParam = (raw, doc) => {
|
|
25
|
+
if (!isObj(raw))
|
|
26
|
+
return null;
|
|
27
|
+
let node = raw;
|
|
28
|
+
if (typeof node.$ref === 'string') {
|
|
29
|
+
const m = /^#\/components\/parameters\/(.+)$/.exec(node.$ref);
|
|
30
|
+
if (!m)
|
|
31
|
+
return null;
|
|
32
|
+
const docAny = doc;
|
|
33
|
+
const target = docAny.components?.parameters?.[decodeURIComponent(m[1])];
|
|
34
|
+
if (!isObj(target))
|
|
35
|
+
return null;
|
|
36
|
+
node = target;
|
|
37
|
+
}
|
|
38
|
+
const location = node.in;
|
|
39
|
+
if ((location !== 'query' && location !== 'path' && location !== 'header' && location !== 'cookie') || typeof node.name !== 'string')
|
|
40
|
+
return null;
|
|
41
|
+
return {
|
|
42
|
+
in: location, name: node.name,
|
|
43
|
+
...(typeof node.required === 'boolean' ? { required: node.required } : {}),
|
|
44
|
+
...(isObj(node.schema) ? { schema: node.schema } : {}),
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
export const createRequestValidationContext = (catalog, options = {}) => {
|
|
48
|
+
const maxBodyBytes = options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
49
|
+
if (!Number.isSafeInteger(maxBodyBytes) || maxBodyBytes < 0) {
|
|
50
|
+
throw new Error('maxBodyBytes must be a nonnegative safe integer');
|
|
51
|
+
}
|
|
52
|
+
const doc = catalog.document;
|
|
53
|
+
const schemes = new Map();
|
|
54
|
+
for (const [name, scheme] of Object.entries(doc.components?.securitySchemes ?? {})) {
|
|
55
|
+
if (isObj(scheme) && typeof scheme.type === 'string') {
|
|
56
|
+
schemes.set(name, scheme);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const globalSecurity = doc.security ?? [];
|
|
60
|
+
const routes = [];
|
|
61
|
+
for (const operation of catalog.operations) {
|
|
62
|
+
const oasPath = operation.sourcePath;
|
|
63
|
+
const methodName = operation.method;
|
|
64
|
+
const pattern = parseRoutePattern(operation.path);
|
|
65
|
+
const pathLevelParams = operation.pathParameters;
|
|
66
|
+
const op = operation.definition;
|
|
67
|
+
const opNode = op;
|
|
68
|
+
const params = [];
|
|
69
|
+
const rawParams = [...pathLevelParams, ...(opNode.parameters ?? [])];
|
|
70
|
+
for (const raw of rawParams) {
|
|
71
|
+
const p = resolveParam(raw, doc);
|
|
72
|
+
if (!p || p.in === 'cookie')
|
|
73
|
+
continue;
|
|
74
|
+
const schema = (p.schema ?? {});
|
|
75
|
+
const validator = compileValidator(schema, doc, `#/paths/${oasPath}/${methodName}/parameters/${p.name}`);
|
|
76
|
+
params.push({
|
|
77
|
+
name: p.name,
|
|
78
|
+
in: p.in,
|
|
79
|
+
required: p.required === true || p.in === 'path',
|
|
80
|
+
type: typeof schema.type === 'string' ? schema.type : null,
|
|
81
|
+
validator,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
const requestBody = opNode.requestBody;
|
|
85
|
+
const content = requestBody?.content;
|
|
86
|
+
const declaredTypes = content ? Object.keys(content) : [];
|
|
87
|
+
const hasJsonBody = declaredTypes.some((c) => /^application\/json(\b|;)/i.test(c));
|
|
88
|
+
const bodyOnlyJson = hasJsonBody &&
|
|
89
|
+
declaredTypes.every((c) => /^application\/json(\b|;)/i.test(c));
|
|
90
|
+
const jsonSchema = content?.['application/json']?.schema;
|
|
91
|
+
const bodyValidator = jsonSchema
|
|
92
|
+
? compileValidator(jsonSchema, doc, `#/paths/${oasPath}/${methodName}/requestBody`)
|
|
93
|
+
: null;
|
|
94
|
+
routes.push({
|
|
95
|
+
key: operation.key,
|
|
96
|
+
pattern,
|
|
97
|
+
hasBody: requestBody !== undefined,
|
|
98
|
+
hasJsonBody,
|
|
99
|
+
bodyOnlyJson,
|
|
100
|
+
bodyRequired: requestBody?.required === true,
|
|
101
|
+
bodyValidator,
|
|
102
|
+
params,
|
|
103
|
+
security: opNode.security ?? globalSecurity,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
catalog,
|
|
108
|
+
routes,
|
|
109
|
+
schemes,
|
|
110
|
+
maxBodyBytes,
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
const coerce = (raw, type) => {
|
|
114
|
+
if (type === 'integer') {
|
|
115
|
+
if (!/^-?\d+$/.test(raw))
|
|
116
|
+
return raw;
|
|
117
|
+
const n = Number(raw);
|
|
118
|
+
return Number.isFinite(n) ? n : raw;
|
|
119
|
+
}
|
|
120
|
+
if (type === 'number') {
|
|
121
|
+
if (!/^-?\d+(?:\.\d+)?$/.test(raw))
|
|
122
|
+
return raw;
|
|
123
|
+
const n = Number(raw);
|
|
124
|
+
return Number.isFinite(n) ? n : raw;
|
|
125
|
+
}
|
|
126
|
+
if (type === 'boolean') {
|
|
127
|
+
if (raw === 'true')
|
|
128
|
+
return true;
|
|
129
|
+
if (raw === 'false')
|
|
130
|
+
return false;
|
|
131
|
+
return raw;
|
|
132
|
+
}
|
|
133
|
+
return raw;
|
|
134
|
+
};
|
|
135
|
+
const isSecuritySatisfied = (req, ctx, headers, url) => {
|
|
136
|
+
const names = Object.keys(req);
|
|
137
|
+
if (names.length === 0)
|
|
138
|
+
return true;
|
|
139
|
+
return names.every((name) => {
|
|
140
|
+
const scheme = ctx.schemes.get(name);
|
|
141
|
+
if (!scheme)
|
|
142
|
+
return false;
|
|
143
|
+
if (scheme.type === 'http') {
|
|
144
|
+
const auth = headers.get('authorization') ?? '';
|
|
145
|
+
const want = (scheme.scheme ?? 'bearer').toLowerCase();
|
|
146
|
+
return new RegExp(`^${want}\\s+`, 'i').test(auth);
|
|
147
|
+
}
|
|
148
|
+
if (scheme.type === 'apiKey') {
|
|
149
|
+
if (scheme.in === 'header' && scheme.name) {
|
|
150
|
+
return headers.has(scheme.name.toLowerCase());
|
|
151
|
+
}
|
|
152
|
+
if (scheme.in === 'query' && scheme.name) {
|
|
153
|
+
return url.searchParams.has(scheme.name);
|
|
154
|
+
}
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
// oauth2 / openIdConnect: presence-only check; full token validation
|
|
158
|
+
// (introspection, signature verification) is out of scope for a
|
|
159
|
+
// zero-dep walker. Consumers needing it should layer it via
|
|
160
|
+
// a separate HTTP preflight or validation plugin.
|
|
161
|
+
return headers.has('authorization');
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
const buildAuthChallenge = (reqs, ctx) => {
|
|
165
|
+
for (const r of reqs) {
|
|
166
|
+
for (const name of Object.keys(r)) {
|
|
167
|
+
const scheme = ctx.schemes.get(name);
|
|
168
|
+
if (scheme?.type === 'http') {
|
|
169
|
+
const s = (scheme.scheme ?? 'bearer').replace(/^./, (c) => c.toUpperCase());
|
|
170
|
+
return { 'www-authenticate': `${s} realm="api"` };
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return { 'www-authenticate': 'Bearer realm="api"' };
|
|
175
|
+
};
|
|
176
|
+
const problem = (status, detail, violations = [], extraHeaders = {}) => {
|
|
177
|
+
const body = {
|
|
178
|
+
type: problemType(status),
|
|
179
|
+
title: STATUS_TITLES[status] ?? 'Request validation failed',
|
|
180
|
+
status,
|
|
181
|
+
detail,
|
|
182
|
+
};
|
|
183
|
+
if (violations.length > 0)
|
|
184
|
+
body.violations = violations;
|
|
185
|
+
return new Response(JSON.stringify(body), {
|
|
186
|
+
status,
|
|
187
|
+
headers: {
|
|
188
|
+
'content-type': 'application/problem+json',
|
|
189
|
+
...extraHeaders,
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
};
|
|
193
|
+
const readBody = async (req, maxBodyBytes) => {
|
|
194
|
+
let reader;
|
|
195
|
+
// Tee cancellation only reaches the source after both branches cancel. Neither
|
|
196
|
+
// promise can be awaited here: a user source may never settle its cancel hook.
|
|
197
|
+
const cancel = () => {
|
|
198
|
+
void reader?.cancel().catch(() => { });
|
|
199
|
+
void req.body?.cancel().catch(() => { });
|
|
200
|
+
};
|
|
201
|
+
let onAbort = () => { };
|
|
202
|
+
try {
|
|
203
|
+
if (req.signal.aborted)
|
|
204
|
+
throw new Error('request aborted');
|
|
205
|
+
reader = req.clone().body?.getReader();
|
|
206
|
+
if (!reader)
|
|
207
|
+
return { raw: '', bytes: 0 };
|
|
208
|
+
const aborted = new Promise((_, reject) => {
|
|
209
|
+
onAbort = () => reject(new Error('request aborted'));
|
|
210
|
+
req.signal.addEventListener('abort', onAbort, { once: true });
|
|
211
|
+
});
|
|
212
|
+
const decoder = new TextDecoder();
|
|
213
|
+
let bytes = 0;
|
|
214
|
+
let raw = '';
|
|
215
|
+
while (true) {
|
|
216
|
+
const chunk = await Promise.race([reader.read(), aborted]);
|
|
217
|
+
if (req.signal.aborted)
|
|
218
|
+
throw new Error('request aborted');
|
|
219
|
+
if (chunk.done)
|
|
220
|
+
return { raw: raw + decoder.decode(), bytes };
|
|
221
|
+
bytes += chunk.value.byteLength;
|
|
222
|
+
if (bytes > maxBodyBytes) {
|
|
223
|
+
cancel();
|
|
224
|
+
return { response: problem(413, `request body exceeds maxBodyBytes (${maxBodyBytes})`) };
|
|
225
|
+
}
|
|
226
|
+
raw += decoder.decode(chunk.value, { stream: true });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
cancel();
|
|
231
|
+
return { response: problem(400, 'request body could not be read') };
|
|
232
|
+
}
|
|
233
|
+
finally {
|
|
234
|
+
req.signal.removeEventListener('abort', onAbort);
|
|
235
|
+
reader?.releaseLock();
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
export const validateRequest = async (req, ctx, effectiveMethod = req.method) => {
|
|
239
|
+
const url = new URL(req.url);
|
|
240
|
+
const method = effectiveMethod.toUpperCase();
|
|
241
|
+
const operation = ctx.catalog.find(method, url.pathname);
|
|
242
|
+
let matched = null;
|
|
243
|
+
for (const r of ctx.routes) {
|
|
244
|
+
if (r.key !== operation?.key)
|
|
245
|
+
continue;
|
|
246
|
+
const params = matchPattern(r.pattern, url.pathname);
|
|
247
|
+
if (params) {
|
|
248
|
+
matched = { route: r, params };
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
// Unmatched paths fall through — they are either hand-written routes
|
|
253
|
+
// outside the OAS document or genuine 404s. Either way the validator
|
|
254
|
+
// has no contract to enforce.
|
|
255
|
+
if (!matched)
|
|
256
|
+
return null;
|
|
257
|
+
const { route, params } = matched;
|
|
258
|
+
const headers = new Map();
|
|
259
|
+
req.headers.forEach((v, k) => headers.set(k.toLowerCase(), v));
|
|
260
|
+
// 1) Security gate.
|
|
261
|
+
if (route.security.length > 0) {
|
|
262
|
+
const ok = route.security.some((sr) => isSecuritySatisfied(sr, ctx, headers, url));
|
|
263
|
+
if (!ok) {
|
|
264
|
+
return problem(401, 'missing or invalid credentials', [], buildAuthChallenge(route.security, ctx));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const hasBodyMethod = method !== 'GET' && method !== 'HEAD';
|
|
268
|
+
const contentType = (headers.get('content-type') ?? '').split(';')[0]?.trim().toLowerCase() ?? '';
|
|
269
|
+
// 2) Content-Type guard for routes that declare a JSON-only requestBody.
|
|
270
|
+
if (hasBodyMethod && route.bodyOnlyJson && contentType && contentType !== 'application/json') {
|
|
271
|
+
return problem(415, `unsupported media type '${contentType}' (expected application/json)`);
|
|
272
|
+
}
|
|
273
|
+
const violations = [];
|
|
274
|
+
// 3) Body parse + validate.
|
|
275
|
+
if (hasBodyMethod && route.hasBody) {
|
|
276
|
+
const body = await readBody(req, ctx.maxBodyBytes);
|
|
277
|
+
if ('response' in body)
|
|
278
|
+
return body.response;
|
|
279
|
+
const { raw } = body;
|
|
280
|
+
if (body.bytes === 0) {
|
|
281
|
+
if (route.bodyRequired) {
|
|
282
|
+
return problem(422, 'request body is required', [
|
|
283
|
+
{ path: '/body', keyword: 'required', message: 'missing required body' },
|
|
284
|
+
]);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
else if (route.hasJsonBody && (!contentType || contentType === 'application/json')) {
|
|
288
|
+
let parsed;
|
|
289
|
+
try {
|
|
290
|
+
parsed = JSON.parse(raw);
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
return problem(400, 'malformed JSON body');
|
|
294
|
+
}
|
|
295
|
+
if (route.bodyValidator)
|
|
296
|
+
violations.push(...route.bodyValidator(parsed, '/body'));
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
// 4) Param validation (with type coercion for query/path/header).
|
|
300
|
+
for (const p of route.params) {
|
|
301
|
+
if (p.in === 'query') {
|
|
302
|
+
const raw = url.searchParams.get(p.name);
|
|
303
|
+
if (raw === null) {
|
|
304
|
+
if (p.required) {
|
|
305
|
+
violations.push({
|
|
306
|
+
path: `/query/${p.name}`,
|
|
307
|
+
keyword: 'required',
|
|
308
|
+
message: 'missing required query parameter',
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
violations.push(...p.validator(coerce(raw, p.type), `/query/${p.name}`));
|
|
314
|
+
}
|
|
315
|
+
else if (p.in === 'path') {
|
|
316
|
+
const raw = params[p.name];
|
|
317
|
+
// Defensive: `matchPattern` always populates every named path
|
|
318
|
+
// segment when the route matches, so a missing path param is
|
|
319
|
+
// unreachable in practice. Kept as a guard against future
|
|
320
|
+
// refactors that loosen the matcher contract.
|
|
321
|
+
/* c8 ignore start */
|
|
322
|
+
if (raw === undefined) {
|
|
323
|
+
violations.push({
|
|
324
|
+
path: `/path/${p.name}`,
|
|
325
|
+
keyword: 'required',
|
|
326
|
+
message: 'missing required path parameter',
|
|
327
|
+
});
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
/* c8 ignore stop */
|
|
331
|
+
violations.push(...p.validator(coerce(raw, p.type), `/path/${p.name}`));
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
const raw = headers.get(p.name.toLowerCase());
|
|
335
|
+
if (raw === undefined) {
|
|
336
|
+
if (p.required) {
|
|
337
|
+
violations.push({
|
|
338
|
+
path: `/header/${p.name}`,
|
|
339
|
+
keyword: 'required',
|
|
340
|
+
message: 'missing required header',
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
violations.push(...p.validator(coerce(raw, p.type), `/header/${p.name}`));
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if (violations.length > 0) {
|
|
349
|
+
return problem(422, `request validation failed (${violations.length} violation${violations.length === 1 ? '' : 's'})`, violations);
|
|
350
|
+
}
|
|
351
|
+
return null;
|
|
352
|
+
};
|
|
353
|
+
//# sourceMappingURL=request-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-validation.js","sourceRoot":"","sources":["../../src/middleware/request-validation.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAqB,MAAM,oBAAoB,CAAA;AACvF,OAAO,EAAE,gBAAgB,EAAkC,MAAM,2BAA2B,CAAA;AAE5F,MAAM,iBAAiB,GACrB,6DAA6D,CAAA;AAE/D,MAAM,iBAAiB,GAA2B;IAChD,GAAG,EAAE,gBAAgB;IACrB,GAAG,EAAE,cAAc;IACnB,GAAG,EAAE,mBAAmB;IACxB,GAAG,EAAE,wBAAwB;IAC7B,GAAG,EAAE,oBAAoB;CAC1B,CAAA;AAED,MAAM,WAAW,GAAG,CAAC,MAAc,EAAU,EAAE,CAC7C,GAAG,iBAAiB,IAAI,iBAAiB,CAAC,MAAM,CAAC,IAAI,oBAAoB,KAAK,CAAA;AAGhF,gEAAgE;AAChE,qEAAqE;AACrE,2CAA2C;AAC3C,MAAM,sBAAsB,GAAG,MAAM,CAAA;AAErC,MAAM,aAAa,GAA2B;IAC5C,GAAG,EAAE,mBAAmB;IACxB,GAAG,EAAE,cAAc;IACnB,GAAG,EAAE,mBAAmB;IACxB,GAAG,EAAE,wBAAwB;IAC7B,GAAG,EAAE,2BAA2B;CACjC,CAAA;AAyCD,MAAM,KAAK,GAAG,CAAC,CAAU,EAAgC,EAAE,CACzD,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;AAU1D,MAAM,YAAY,GAAG,CAAC,GAAY,EAAE,GAAW,EAA4B,EAAE;IAC3E,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA;IAC5B,IAAI,IAAI,GAA4B,GAAG,CAAA;IACvC,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,CAAC,GAAG,mCAAmC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC7D,IAAI,CAAC,CAAC;YAAE,OAAO,IAAI,CAAA;QACnB,MAAM,MAAM,GAAG,GAAgE,CAAA;QAC/E,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,CAAA;QACzE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;YAAE,OAAO,IAAI,CAAA;QAC/B,IAAI,GAAG,MAAM,CAAA;IACf,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAA;IACxB,IAAI,CAAC,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,QAAQ,CAAC,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAA;IACjJ,OAAO;QACL,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI;QAC7B,GAAG,CAAC,OAAO,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1E,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAClE,CAAA;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAC5C,OAAuB,EACvB,UAA8C,EAAE,EACtB,EAAE;IAC5B,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,sBAAsB,CAAA;IACnE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAA;IACpE,CAAC;IACD,MAAM,GAAG,GAAG,OAAO,CAAC,QAInB,CAAA;IACD,MAAM,OAAO,GAAG,IAAI,GAAG,EAA0B,CAAA;IACjD,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,eAAe,IAAI,EAAE,CAAC,EAAE,CAAC;QACnF,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,MAAwB,CAAC,CAAA;QAC7C,CAAC;IACH,CAAC;IACD,MAAM,cAAc,GAAG,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAA;IACzC,MAAM,MAAM,GAAqB,EAAE,CAAA;IACnC,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QAC3C,MAAM,OAAO,GAAG,SAAS,CAAC,UAAU,CAAA;QACpC,MAAM,UAAU,GAAG,SAAS,CAAC,MAAM,CAAA;QACnC,MAAM,OAAO,GAAG,iBAAiB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;QACjD,MAAM,eAAe,GAAG,SAAS,CAAC,cAAc,CAAA;QAChD,MAAM,EAAE,GAAG,SAAS,CAAC,UAAU,CAAA;QAC/B,MAAM,MAAM,GAAG,EAOd,CAAA;QACD,MAAM,MAAM,GAAgB,EAAE,CAAA;QAC9B,MAAM,SAAS,GAAG,CAAC,GAAG,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,CAAA;QACpE,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;YAC5B,MAAM,CAAC,GAAG,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;YAChC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,QAAQ;gBAAE,SAAQ;YACrC,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAY,CAAA;YAC1C,MAAM,SAAS,GAAG,gBAAgB,CAChC,MAAM,EACN,GAAG,EACH,WAAW,OAAO,IAAI,UAAU,eAAe,CAAC,CAAC,IAAI,EAAE,CACxD,CAAA;YACD,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,QAAQ,EAAE,CAAC,CAAC,QAAQ,KAAK,IAAI,IAAI,CAAC,CAAC,EAAE,KAAK,MAAM;gBAChD,IAAI,EAAE,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;gBAC1D,SAAS;aACV,CAAC,CAAA;QACJ,CAAC;QACD,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAA;QACtC,MAAM,OAAO,GAAG,WAAW,EAAE,OAAO,CAAA;QACpC,MAAM,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QACzD,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,2BAA2B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;QAClF,MAAM,YAAY,GAChB,WAAW;YACX,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,2BAA2B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;QACjE,MAAM,UAAU,GAAG,OAAO,EAAE,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;QACxD,MAAM,aAAa,GAAG,UAAU;YAC9B,CAAC,CAAC,gBAAgB,CAAC,UAAU,EAAE,GAAG,EAAE,WAAW,OAAO,IAAI,UAAU,cAAc,CAAC;YACnF,CAAC,CAAC,IAAI,CAAA;QACR,MAAM,CAAC,IAAI,CAAC;YACV,GAAG,EAAE,SAAS,CAAC,GAAG;YAClB,OAAO;YACP,OAAO,EAAE,WAAW,KAAK,SAAS;YAClC,WAAW;YACX,YAAY;YACZ,YAAY,EAAE,WAAW,EAAE,QAAQ,KAAK,IAAI;YAC5C,aAAa;YACb,MAAM;YACN,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,cAAc;SAC5C,CAAC,CAAA;IACJ,CAAC;IACD,OAAO;QACL,OAAO;QACP,MAAM;QACN,OAAO;QACP,YAAY;KACb,CAAA;AACH,CAAC,CAAA;AAED,MAAM,MAAM,GAAG,CAAC,GAAW,EAAE,IAAmB,EAAW,EAAE;IAC3D,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,GAAG,CAAA;QACpC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAA;QACrB,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;IACrC,CAAC;IACD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,GAAG,CAAA;QAC9C,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAA;QACrB,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;IACrC,CAAC;IACD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,IAAI,GAAG,KAAK,MAAM;YAAE,OAAO,IAAI,CAAA;QAC/B,IAAI,GAAG,KAAK,OAAO;YAAE,OAAO,KAAK,CAAA;QACjC,OAAO,GAAG,CAAA;IACZ,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA;AAED,MAAM,mBAAmB,GAAG,CAC1B,GAAgD,EAChD,GAA6B,EAC7B,OAA4B,EAC5B,GAAQ,EACC,EAAE;IACX,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC9B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACnC,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE;QAC1B,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACpC,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAA;QACzB,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,CAAA;YAC/C,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAA;YACtD,OAAO,IAAI,MAAM,CAAC,IAAI,IAAI,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACnD,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,IAAI,MAAM,CAAC,EAAE,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;gBAC1C,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;YAC/C,CAAC;YACD,IAAI,MAAM,CAAC,EAAE,KAAK,OAAO,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;gBACzC,OAAO,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;YAC1C,CAAC;YACD,OAAO,KAAK,CAAA;QACd,CAAC;QACD,qEAAqE;QACrE,gEAAgE;QAChE,4DAA4D;QAC5D,kDAAkD;QAClD,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAA;IACrC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA;AAED,MAAM,kBAAkB,GAAG,CACzB,IAA4D,EAC5D,GAA6B,EACL,EAAE;IAC1B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAClC,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;YACpC,IAAI,MAAM,EAAE,IAAI,KAAK,MAAM,EAAE,CAAC;gBAC5B,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,QAAQ,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAA;gBAC3E,OAAO,EAAE,kBAAkB,EAAE,GAAG,CAAC,cAAc,EAAE,CAAA;YACnD,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,CAAA;AACrD,CAAC,CAAA;AAED,MAAM,OAAO,GAAG,CACd,MAAc,EACd,MAAc,EACd,aAAmC,EAAE,EACrC,eAAuC,EAAE,EAC/B,EAAE;IACZ,MAAM,IAAI,GAMN;QACF,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC;QACzB,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,IAAI,2BAA2B;QAC3D,MAAM;QACN,MAAM;KACP,CAAA;IACD,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;QAAE,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;IACvD,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE;QACxC,MAAM;QACN,OAAO,EAAE;YACP,cAAc,EAAE,0BAA0B;YAC1C,GAAG,YAAY;SAChB;KACF,CAAC,CAAA;AACJ,CAAC,CAAA;AAKD,MAAM,QAAQ,GAAG,KAAK,EAAE,GAAY,EAAE,YAAoB,EAAqB,EAAE;IAC/E,IAAI,MAA2D,CAAA;IAC/D,+EAA+E;IAC/E,+EAA+E;IAC/E,MAAM,MAAM,GAAG,GAAG,EAAE;QAClB,KAAK,MAAM,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QACrC,KAAK,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;IACzC,CAAC,CAAA;IACD,IAAI,OAAO,GAAe,GAAG,EAAE,GAAE,CAAC,CAAA;IAClC,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAA;QAC1D,MAAM,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,CAAA;QACtC,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAA;QACzC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;YAC/C,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAA;YACpD,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;QAC/D,CAAC,CAAC,CAAA;QACF,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAA;QACjC,IAAI,KAAK,GAAG,CAAC,CAAA;QACb,IAAI,GAAG,GAAG,EAAE,CAAA;QACZ,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC,CAAA;YAC1D,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO;gBAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAA;YAC1D,IAAI,KAAK,CAAC,IAAI;gBAAE,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,CAAA;YAC7D,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,UAAU,CAAA;YAC/B,IAAI,KAAK,GAAG,YAAY,EAAE,CAAC;gBACzB,MAAM,EAAE,CAAA;gBACR,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,GAAG,EAAE,sCAAsC,YAAY,GAAG,CAAC,EAAE,CAAA;YAC1F,CAAC;YACD,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;QACtD,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,EAAE,CAAA;QACR,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,GAAG,EAAE,gCAAgC,CAAC,EAAE,CAAA;IACrE,CAAC;YAAS,CAAC;QACT,GAAG,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QAChD,MAAM,EAAE,WAAW,EAAE,CAAA;IACvB,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAClC,GAAY,EACZ,GAA6B,EAC7B,eAAe,GAAG,GAAG,CAAC,MAAM,EACF,EAAE;IAC5B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC5B,MAAM,MAAM,GAAG,eAAe,CAAC,WAAW,EAAE,CAAA;IAC5C,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAA;IACxD,IAAI,OAAO,GAA+E,IAAI,CAAA;IAC9F,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,CAAC,GAAG,KAAK,SAAS,EAAE,GAAG;YAAE,SAAQ;QACtC,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAA;QACpD,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAA;YAC9B,MAAK;QACP,CAAC;IACH,CAAC;IACD,qEAAqE;IACrE,qEAAqE;IACrE,8BAA8B;IAC9B,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAA;IAEzB,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAA;IACjC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAA;IACzC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA;IAE9D,oBAAoB;IACpB,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,mBAAmB,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,CAAA;QAClF,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,OAAO,OAAO,CACZ,GAAG,EACH,gCAAgC,EAChC,EAAE,EACF,kBAAkB,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,CACxC,CAAA;QACH,CAAC;IACH,CAAC;IAED,MAAM,aAAa,GAAG,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,MAAM,CAAA;IAC3D,MAAM,WAAW,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,CAAA;IAEjG,yEAAyE;IACzE,IAAI,aAAa,IAAI,KAAK,CAAC,YAAY,IAAI,WAAW,IAAI,WAAW,KAAK,kBAAkB,EAAE,CAAC;QAC7F,OAAO,OAAO,CAAC,GAAG,EAAE,2BAA2B,WAAW,+BAA+B,CAAC,CAAA;IAC5F,CAAC;IAED,MAAM,UAAU,GAAgB,EAAE,CAAA;IAElC,4BAA4B;IAC5B,IAAI,aAAa,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QACnC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,YAAY,CAAC,CAAA;QAClD,IAAI,UAAU,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAA;QAC5C,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;QACpB,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;YACrB,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;gBACvB,OAAO,OAAO,CAAC,GAAG,EAAE,0BAA0B,EAAE;oBAC9C,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,uBAAuB,EAAE;iBACzE,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;aAAM,IAAI,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC,WAAW,IAAI,WAAW,KAAK,kBAAkB,CAAC,EAAE,CAAC;YACrF,IAAI,MAAe,CAAA;YACnB,IAAI,CAAC;gBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;YAC1B,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,OAAO,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAA;YAC5C,CAAC;YACD,IAAI,KAAK,CAAC,aAAa;gBAAE,UAAU,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;QACnF,CAAC;IACH,CAAC;IAED,kEAAkE;IAClE,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QAC7B,IAAI,CAAC,CAAC,EAAE,KAAK,OAAO,EAAE,CAAC;YACrB,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;YACxC,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBACjB,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;oBACf,UAAU,CAAC,IAAI,CAAC;wBACd,IAAI,EAAE,UAAU,CAAC,CAAC,IAAI,EAAE;wBACxB,OAAO,EAAE,UAAU;wBACnB,OAAO,EAAE,kCAAkC;qBAC5C,CAAC,CAAA;gBACJ,CAAC;gBACD,SAAQ;YACV,CAAC;YACD,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;QAC1E,CAAC;aAAM,IAAI,CAAC,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;YAC3B,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;YAC1B,8DAA8D;YAC9D,6DAA6D;YAC7D,0DAA0D;YAC1D,8CAA8C;YAC9C,qBAAqB;YACrB,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBACtB,UAAU,CAAC,IAAI,CAAC;oBACd,IAAI,EAAE,SAAS,CAAC,CAAC,IAAI,EAAE;oBACvB,OAAO,EAAE,UAAU;oBACnB,OAAO,EAAE,iCAAiC;iBAC3C,CAAC,CAAA;gBACF,SAAQ;YACV,CAAC;YACD,oBAAoB;YACpB,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;QACzE,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;YAC7C,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBACtB,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;oBACf,UAAU,CAAC,IAAI,CAAC;wBACd,IAAI,EAAE,WAAW,CAAC,CAAC,IAAI,EAAE;wBACzB,OAAO,EAAE,UAAU;wBACnB,OAAO,EAAE,yBAAyB;qBACnC,CAAC,CAAA;gBACJ,CAAC;gBACD,SAAQ;YACV,CAAC;YACD,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;QAC3E,CAAC;IACH,CAAC;IAED,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,OAAO,OAAO,CACZ,GAAG,EACH,8BAA8B,UAAU,CAAC,MAAM,aAAa,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,EACjG,UAAU,CACX,CAAA;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Plugin } from '@databehave/core';
|
|
2
|
+
import type { MockModeOptions } from './mock-mode.js';
|
|
3
|
+
export type { MockModeOptions } from './mock-mode.js';
|
|
4
|
+
export declare const mockModePlugin: (options?: MockModeOptions) => Plugin;
|
|
5
|
+
//# sourceMappingURL=mock-mode-plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-mode-plugin.d.ts","sourceRoot":"","sources":["../src/mock-mode-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAI9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AACrD,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAErD,eAAO,MAAM,cAAc,GAAI,UAAS,eAAoB,KAAG,MAc7D,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { httpCapability } from '@databehave/server';
|
|
2
|
+
import { openapiCapability } from './catalog.js';
|
|
3
|
+
import { buildMockModeHooks } from './mock-mode.js';
|
|
4
|
+
export const mockModePlugin = (options = {}) => ({
|
|
5
|
+
id: 'databehave.openapi.mock-mode', apiVersion: 1,
|
|
6
|
+
requires: [httpCapability, openapiCapability],
|
|
7
|
+
setup(ctx) {
|
|
8
|
+
const catalog = ctx.use(openapiCapability);
|
|
9
|
+
const runtime = ctx.use(httpCapability);
|
|
10
|
+
const hooks = buildMockModeHooks({ ...options, enabled: true }, (request, status) => {
|
|
11
|
+
const operation = catalog.find(request.effectiveMethod, request.path);
|
|
12
|
+
return operation ? catalog.body(operation, status, request) : undefined;
|
|
13
|
+
});
|
|
14
|
+
if (!hooks)
|
|
15
|
+
throw new Error('Mock mode configuration failed');
|
|
16
|
+
runtime.registerMiddleware({ owner: 'databehave.openapi.mock-mode', order: ctx.order, stage: 'interception', handle: hooks.onRequest });
|
|
17
|
+
runtime.registerMiddleware({ owner: 'databehave.openapi.mock-mode', order: ctx.order, stage: 'decoration', handle: hooks.onResponse });
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
//# sourceMappingURL=mock-mode-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-mode-plugin.js","sourceRoot":"","sources":["../src/mock-mode-plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAInD,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,UAA2B,EAAE,EAAU,EAAE,CAAC,CAAC;IACxE,EAAE,EAAE,8BAA8B,EAAE,UAAU,EAAE,CAAC;IACjD,QAAQ,EAAE,CAAC,cAAc,EAAE,iBAAiB,CAAC;IAC7C,KAAK,CAAC,GAAG;QACP,MAAM,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAA;QAC1C,MAAM,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;QACvC,MAAM,KAAK,GAAG,kBAAkB,CAAC,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAClF,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;YACrE,OAAO,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QACzE,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;QAC7D,OAAO,CAAC,kBAAkB,CAAC,EAAE,KAAK,EAAE,8BAA8B,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAA;QACvI,OAAO,CAAC,kBAAkB,CAAC,EAAE,KAAK,EAAE,8BAA8B,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAA;IACxI,CAAC;CACF,CAAC,CAAA"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/** Explicit status selection and response tagging policy. */
|
|
2
|
+
import type { MockRequest, MockResponse } from '@databehave/server';
|
|
3
|
+
/** Optional generated body lookup for a selected route and status. */
|
|
4
|
+
export type BodyResolver = (request: MockRequest, status: number) => unknown | undefined;
|
|
5
|
+
/**
|
|
6
|
+
* Minimal logger interface (compatible with the host server's logger
|
|
7
|
+
* and with `console`). Only `warn` is required by mock-mode today; the
|
|
8
|
+
* shape is kept narrow so callers can pass an existing logger without
|
|
9
|
+
* adapter glue.
|
|
10
|
+
*/
|
|
11
|
+
export interface MockModeLogger {
|
|
12
|
+
warn(message: string): void;
|
|
13
|
+
}
|
|
14
|
+
/** Status policy enabled by including the mock-mode plugin. */
|
|
15
|
+
export interface MockModeOptions {
|
|
16
|
+
/** MockResponse header that tags every response with the resolved status. */
|
|
17
|
+
header?: string;
|
|
18
|
+
/**
|
|
19
|
+
* When `true`, an incoming request may force the mocked status by
|
|
20
|
+
* sending the same header (default `x-mock-status: 500`). Disabled
|
|
21
|
+
* by default so production-style mock servers don't expose status
|
|
22
|
+
* injection to arbitrary clients. Resolution becomes:
|
|
23
|
+
* 1. request `header` value (when `allowHeaderOverride === true`)
|
|
24
|
+
* 2. `pathOverrides["<METHOD> <path>"]`
|
|
25
|
+
* 3. `pathOverrides["<path>"]`
|
|
26
|
+
* 4. `defaultStatus`
|
|
27
|
+
* 5. passthrough
|
|
28
|
+
*/
|
|
29
|
+
allowHeaderOverride?: boolean;
|
|
30
|
+
/** Paths exempt from status injection (typically health probes). */
|
|
31
|
+
healthPaths?: readonly string[];
|
|
32
|
+
/**
|
|
33
|
+
* Status applied when no `pathOverrides` entry matches. Omit (or set
|
|
34
|
+
* `undefined`) for passthrough (real handler runs). Set to an error
|
|
35
|
+
* code (e.g. `500`) to force every route to that status by default.
|
|
36
|
+
*/
|
|
37
|
+
defaultStatus?: number;
|
|
38
|
+
/**
|
|
39
|
+
* Per-route status overrides. Keys use one of:
|
|
40
|
+
* - `"<METHOD> <path>"` (e.g. `"GET /api/v1/x"`) — method-scoped
|
|
41
|
+
* - `"<path>"` (e.g. `"/api/v1/x"`) — any method
|
|
42
|
+
* Paths must be absolute (start with `/`). Values are HTTP status codes.
|
|
43
|
+
*/
|
|
44
|
+
pathOverrides?: Record<string, number>;
|
|
45
|
+
/**
|
|
46
|
+
* Logger used for non-fatal diagnostics (e.g. out-of-range header
|
|
47
|
+
* overrides). Defaults to the global `console`. Pass the host
|
|
48
|
+
* application's logger to keep mock-server output in one place
|
|
49
|
+
* instead of leaking to stdout/stderr.
|
|
50
|
+
*/
|
|
51
|
+
logger?: MockModeLogger;
|
|
52
|
+
}
|
|
53
|
+
/** Interception and decoration callbacks for the HTTP middleware stages. */
|
|
54
|
+
export interface MockModeHooks {
|
|
55
|
+
onRequest: (req: MockRequest) => MockResponse | undefined;
|
|
56
|
+
onResponse: (req: MockRequest, res: MockResponse) => MockResponse;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Resolve the status code for a request using only the supplied config.
|
|
60
|
+
* Returns `undefined` when the request should pass through.
|
|
61
|
+
* Exported for unit-testing; callers normally use `buildMockModeHooks`.
|
|
62
|
+
*/
|
|
63
|
+
export declare const resolveStatus: (method: string, path: string, config: MockModeOptions) => number | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Build the onRequest / onResponse hook pair. Returns `undefined`
|
|
66
|
+
* when the feature is disabled (caller may skip wiring entirely).
|
|
67
|
+
*
|
|
68
|
+
* `bodyResolver` is optional. When provided, @databehave/server asks it for a
|
|
69
|
+
* body for the configured status (typically a generator backed by
|
|
70
|
+
* the OpenAPI `responses[N]` schema). When it returns `undefined`,
|
|
71
|
+
* the minimal envelope `{ error: true, status: N }` is used instead.
|
|
72
|
+
*/
|
|
73
|
+
export declare const buildMockModeHooks: (config: MockModeOptions & {
|
|
74
|
+
readonly enabled?: boolean;
|
|
75
|
+
}, bodyResolver?: BodyResolver) => MockModeHooks | undefined;
|
|
76
|
+
//# sourceMappingURL=mock-mode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-mode.d.ts","sourceRoot":"","sources":["../src/mock-mode.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEnE,sEAAsE;AACtE,MAAM,MAAM,YAAY,GAAG,CACzB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,KACX,OAAO,GAAG,SAAS,CAAA;AAExB;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAED,+DAA+D;AAC/D,MAAM,WAAW,eAAe;IAC9B,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,oEAAoE;IACpE,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC/B;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,cAAc,CAAA;CACxB;AAED,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,YAAY,GAAG,SAAS,CAAA;IACzD,UAAU,EAAE,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,YAAY,KAAK,YAAY,CAAA;CAClE;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,GACxB,QAAQ,MAAM,EACd,MAAM,MAAM,EACZ,QAAQ,eAAe,KACtB,MAAM,GAAG,SAQX,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAC7B,QAAQ,eAAe,GAAG;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,EACxD,eAAe,YAAY,KAC1B,aAAa,GAAG,SAyElB,CAAA"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the status code for a request using only the supplied config.
|
|
3
|
+
* Returns `undefined` when the request should pass through.
|
|
4
|
+
* Exported for unit-testing; callers normally use `buildMockModeHooks`.
|
|
5
|
+
*/
|
|
6
|
+
export const resolveStatus = (method, path, config) => {
|
|
7
|
+
const overrides = config.pathOverrides ?? {};
|
|
8
|
+
const m = method.toUpperCase();
|
|
9
|
+
const byMethodPath = overrides[`${m} ${path}`];
|
|
10
|
+
if (byMethodPath !== undefined)
|
|
11
|
+
return byMethodPath;
|
|
12
|
+
const byPath = overrides[path];
|
|
13
|
+
if (byPath !== undefined)
|
|
14
|
+
return byPath;
|
|
15
|
+
return config.defaultStatus;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Build the onRequest / onResponse hook pair. Returns `undefined`
|
|
19
|
+
* when the feature is disabled (caller may skip wiring entirely).
|
|
20
|
+
*
|
|
21
|
+
* `bodyResolver` is optional. When provided, @databehave/server asks it for a
|
|
22
|
+
* body for the configured status (typically a generator backed by
|
|
23
|
+
* the OpenAPI `responses[N]` schema). When it returns `undefined`,
|
|
24
|
+
* the minimal envelope `{ error: true, status: N }` is used instead.
|
|
25
|
+
*/
|
|
26
|
+
export const buildMockModeHooks = (config, bodyResolver) => {
|
|
27
|
+
if (config.enabled !== true)
|
|
28
|
+
return undefined;
|
|
29
|
+
const header = config.header ?? 'x-mock-status';
|
|
30
|
+
const healthPaths = new Set(config.healthPaths ?? []);
|
|
31
|
+
const isHealthPath = (p) => healthPaths.has(p);
|
|
32
|
+
const logger = config.logger ?? console;
|
|
33
|
+
const synthesize = (request, status) => {
|
|
34
|
+
const headers = { [header]: String(status) };
|
|
35
|
+
if (status === 204 || status === 205 || status === 304) {
|
|
36
|
+
return { status, empty: true, headers };
|
|
37
|
+
}
|
|
38
|
+
const resolved = bodyResolver?.(request, status);
|
|
39
|
+
const body = resolved === undefined ? { error: true, status } : resolved;
|
|
40
|
+
return { status, json: body, headers };
|
|
41
|
+
};
|
|
42
|
+
const onRequest = (req) => {
|
|
43
|
+
if (isHealthPath(req.path))
|
|
44
|
+
return undefined;
|
|
45
|
+
// Header override (opt-in). The header name is the same one used
|
|
46
|
+
// to tag responses so a single curl flag flips both directions.
|
|
47
|
+
// 1xx (informational) responses are rejected: Node's HTTP layer
|
|
48
|
+
// treats them specially and a mock server has no use for them.
|
|
49
|
+
if (config.allowHeaderOverride === true) {
|
|
50
|
+
const raw = req.headers[header.toLowerCase()];
|
|
51
|
+
if (raw !== undefined) {
|
|
52
|
+
const n = Number.parseInt(raw, 10);
|
|
53
|
+
if (Number.isFinite(n) && n >= 200 && n < 600) {
|
|
54
|
+
return synthesize(req, n);
|
|
55
|
+
}
|
|
56
|
+
// Out-of-range or non-numeric values were previously dropped on
|
|
57
|
+
// the floor, which made debugging "why doesn't my override
|
|
58
|
+
// work?" needlessly hard. Emit a single warn line so the typo
|
|
59
|
+
// is visible without escalating to a hard failure (which would
|
|
60
|
+
// break legitimate clients that ship the header for other
|
|
61
|
+
// reasons).
|
|
62
|
+
logger.warn(`@databehave/openapi/mock-mode: ignored ${header}=${JSON.stringify(raw)} ` +
|
|
63
|
+
`(must be an integer in [200, 600))`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const status = resolveStatus(req.method, req.path, config);
|
|
67
|
+
if (status === undefined)
|
|
68
|
+
return undefined;
|
|
69
|
+
return synthesize(req, status);
|
|
70
|
+
};
|
|
71
|
+
const onResponse = (req, res) => {
|
|
72
|
+
if (isHealthPath(req.path))
|
|
73
|
+
return res;
|
|
74
|
+
// Skip when the response (synthesised or handler-supplied) already
|
|
75
|
+
// carries the tag header. Header lookup is case-insensitive so
|
|
76
|
+
// `'X-Mock-Status'` from a handler is recognised against the
|
|
77
|
+
// configured (typically lowercase) `header` name.
|
|
78
|
+
if (res.headers) {
|
|
79
|
+
const wanted = header.toLowerCase();
|
|
80
|
+
for (const k of Object.keys(res.headers)) {
|
|
81
|
+
if (k.toLowerCase() === wanted)
|
|
82
|
+
return res;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const tag = String(res.status ?? 200);
|
|
86
|
+
return {
|
|
87
|
+
...res,
|
|
88
|
+
headers: { ...(res.headers ?? {}), [header]: tag },
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
return { onRequest, onResponse };
|
|
92
|
+
};
|
|
93
|
+
//# sourceMappingURL=mock-mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-mode.js","sourceRoot":"","sources":["../src/mock-mode.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-schema.d.ts","sourceRoot":"","sources":["../../src/openapi/auto-schema.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,eAAO,MAAM,QAAQ,GAAI,OAAO,MAAM,KAAG,MAOxC,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** FNV-1a request seed derivation retained across generation strategies. */
|
|
2
|
+
export const hashSeed = (input) => {
|
|
3
|
+
let h = 0x811c9dc5;
|
|
4
|
+
for (let i = 0; i < input.length; i++) {
|
|
5
|
+
h ^= input.charCodeAt(i);
|
|
6
|
+
h = (h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24))) >>> 0;
|
|
7
|
+
}
|
|
8
|
+
return h >>> 0;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=auto-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-schema.js","sourceRoot":"","sources":["../../src/openapi/auto-schema.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAU,EAAE;IAChD,IAAI,CAAC,GAAG,UAAU,CAAA;IAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;QACxB,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;IACzE,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,CAAA;AAChB,CAAC,CAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Deterministic structural placeholder generation; no schema runtime dependency. */
|
|
2
|
+
import type { OasDoc, OasNode } from './walker.js';
|
|
3
|
+
/** Reserved for a future seeded mode (brief item #11). Currently ignored. */
|
|
4
|
+
export interface GenerateOptions {
|
|
5
|
+
readonly seed?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare const generateFromOasSchema: (node: OasNode, doc?: OasDoc, _opts?: GenerateOptions, seen?: Set<string>) => unknown;
|
|
8
|
+
//# sourceMappingURL=generate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/openapi/generate.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAElD,6EAA6E;AAC7E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CACvB;AAsDD,eAAO,MAAM,qBAAqB,GAChC,MAAM,OAAO,EACb,MAAK,MAAW,EAEhB,QAAO,eAAoB,EAC3B,OAAM,GAAG,CAAC,MAAM,CAAqB,KACpC,OAqEF,CAAA"}
|