@sackville-mcp/api 0.0.1-alpha.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["parseYaml","parseYaml","parse","MAX_HAR_INFLATED_BYTES","HTTP_METHODS","parseYaml"],"sources":["../src/artifacts.ts","../src/schema.ts","../src/assert.ts","../src/collection.ts","../src/contract.ts","../src/graphql.ts","../src/request-contract.ts","../src/har-capture.ts","../src/har-synth.ts","../src/vars.ts","../src/prepare.ts","../src/safety.ts","../src/script.ts","../src/secrets.ts","../src/runner.ts","../src/sequence.ts","../src/har-produce.ts","../src/import.ts"],"sourcesContent":["export interface Artifact {\n contentType: string\n body: string\n}\n\n/**\n * In-memory store for response bodies, addressed by a `sackville://run/<id>/body`\n * handle. Agents/CLIs fetch bodies by handle so large payloads are never inlined\n * into tool results. (A persistent backend can replace this later.)\n */\nexport class ArtifactStore {\n private artifacts = new Map<string, Artifact>()\n\n put(runId: string, body: string, contentType: string): string {\n const handle = `sackville://run/${runId}/body`\n this.artifacts.set(handle, { body, contentType })\n return handle\n }\n\n get(handle: string): Artifact | undefined {\n return this.artifacts.get(handle)\n }\n}\n","/**\n * JSON Schema validation (draft 2020-12) via ajv. Shared by the `schema`\n * assertion source and the OpenAPI 3.1 contract validator — OpenAPI 3.1's\n * Schema Object *is* JSON Schema 2020-12, so one validator serves both.\n */\nimport { Ajv2020, type ErrorObject } from 'ajv/dist/2020.js'\nimport addFormatsModule from 'ajv-formats'\n\n// ajv-formats ships CJS with `module.exports = fn` *and* `exports.default = fn`;\n// under NodeNext the default import surfaces as the namespace, whose `.default`\n// is the callable plugin.\nconst addFormats = addFormatsModule.default\n\n/** A single schema violation, located by JSON Pointer into the instance. */\nexport interface SchemaError {\n /** JSON Pointer to the offending value ('' = document root). */\n instancePath: string\n message: string\n}\n\nexport interface SchemaValidation {\n valid: boolean\n errors: SchemaError[]\n}\n\n// One shared instance. `strict: false` tolerates the vendor extensions (x-*)\n// and assorted keywords that show up in real-world specs; `allErrors` reports\n// every violation rather than bailing on the first.\nconst ajv = new Ajv2020({ allErrors: true, strict: false })\naddFormats(ajv)\n\nfunction toError(e: ErrorObject): SchemaError {\n const where = e.instancePath || '(root)'\n const detail = e.message ?? 'is invalid'\n // Surface the failing property name for `required` errors (ajv puts it in params).\n const extra =\n e.keyword === 'required' && typeof e.params?.missingProperty === 'string'\n ? `: '${e.params.missingProperty}'`\n : ''\n return { instancePath: e.instancePath, message: `${where} ${detail}${extra}` }\n}\n\n/** Validate `data` against a JSON Schema. Never throws on data; an invalid\n * *schema* surfaces as a single error rather than propagating. */\nexport function validateSchema(schema: unknown, data: unknown): SchemaValidation {\n let validate: ReturnType<typeof ajv.compile>\n try {\n validate = ajv.compile(schema as object)\n } catch (err) {\n return {\n valid: false,\n errors: [{ instancePath: '', message: `invalid schema: ${(err as Error).message}` }],\n }\n }\n const valid = validate(data) as boolean\n return { valid, errors: valid ? [] : (validate.errors ?? []).map(toError) }\n}\n","import { applyOp } from '@sackville-mcp/assert'\nimport { JSONPath } from 'jsonpath-plus'\nimport type { AssertionResult, AssertionSpec, CaptureSpec } from './model.js'\nimport { validateSchema } from './schema.js'\n\nexport interface ResponseContext {\n status: number\n statusText: string\n headers: Record<string, string>\n bodyText: string\n json: unknown\n latencyMs: number\n}\n\n/** Resolve a value from a response by source kind (shared by assertions + captures). */\nfunction valueFrom(\n source: string,\n ctx: ResponseContext,\n opts: { path?: string; name?: string },\n): unknown {\n switch (source) {\n case 'status':\n return ctx.status\n case 'statusText':\n return ctx.statusText\n case 'responseTime':\n return ctx.latencyMs\n case 'body':\n return ctx.bodyText\n case 'header':\n return opts.name ? ctx.headers[opts.name.toLowerCase()] : undefined\n case 'jsonpath':\n // eval disabled: no script (`()`/`?()`) expressions — jsonpath-plus has a\n // history of eval CVEs; only plain path navigation is allowed.\n return JSONPath({\n path: opts.path ?? '$',\n json: ctx.json as object,\n wrap: false,\n eval: false,\n })\n default:\n return undefined\n }\n}\n\n/** Evaluate declarative assertions against a response. */\nexport function evaluateAssertions(\n specs: AssertionSpec[],\n ctx: ResponseContext,\n): AssertionResult[] {\n return specs.map((spec) => {\n // 'schema' is pass/fail against a JSON Schema, not an op comparison: the\n // schema lives in `value`, the subject is the body (or a jsonpath subtree).\n if (spec.source === 'schema') {\n const subject = spec.path ? valueFrom('jsonpath', ctx, spec) : ctx.json\n const { valid, errors } = validateSchema(spec.value, subject)\n return {\n source: spec.source,\n op: spec.op,\n path: spec.path,\n expected: spec.value,\n actual: valid ? null : errors,\n pass: valid,\n }\n }\n const actual = valueFrom(spec.source, ctx, spec)\n return {\n source: spec.source,\n op: spec.op,\n path: spec.path,\n name: spec.name,\n expected: spec.value,\n actual,\n pass: applyOp(spec.op, actual, spec.value),\n }\n })\n}\n\n/** Extract captured variables from a response into a name→value map. */\nexport function extractCaptures(\n specs: CaptureSpec[],\n ctx: ResponseContext,\n): Record<string, unknown> {\n const captured: Record<string, unknown> = {}\n for (const spec of specs) {\n captured[spec.var] = valueFrom(spec.source, ctx, spec)\n }\n return captured\n}\n","import { existsSync, readdirSync, readFileSync } from 'node:fs'\nimport { basename, join } from 'node:path'\nimport { bruToEnvJsonV2, bruToJsonV2 } from '@usebruno/lang'\nimport { parse as parseYaml } from 'yaml'\nimport type {\n ApiRequest,\n AssertionSpec,\n CaptureSpec,\n Collection,\n MultipartPart,\n RequestBody,\n RequestEntry,\n} from './model.js'\n\n// Collection/folder-level .bru files are settings, not requests.\nconst NON_REQUEST = new Set(['collection.bru', 'folder.bru'])\n// Body types stored as a raw string under body.<key>.\nconst RAW_BODY_TYPES = new Set(['json', 'text', 'xml', 'sparql'])\n// `@usebruno/lang` discriminators (camelCase) → our canonical body-type names.\nconst BODY_TYPE_ALIASES: Record<string, string> = {\n formUrlEncoded: 'form-urlencoded',\n multipartForm: 'multipart-form',\n}\n\ninterface BruMultipartPart {\n name: string\n value: string | string[]\n enabled?: boolean\n type?: 'text' | 'file'\n contentType?: string\n}\n\ninterface BruFilePart {\n filePath: string\n contentType?: string\n selected?: boolean\n}\n\ninterface BruBody {\n json?: string\n text?: string\n xml?: string\n sparql?: string\n graphql?: { query?: string; variables?: string }\n formUrlEncoded?: { name: string; value: string; enabled?: boolean }[]\n multipartForm?: BruMultipartPart[]\n file?: BruFilePart[]\n}\n\ninterface BruJson {\n meta?: { name?: string }\n http?: { method?: string; url?: string; body?: string }\n headers?: { name: string; value: string; enabled?: boolean }[]\n body?: BruBody\n}\n\ninterface Sidecar {\n assertions?: AssertionSpec[]\n captures?: CaptureSpec[]\n preScript?: string\n postScript?: string\n}\n\ninterface EnvJson {\n variables?: { name: string; value: string; enabled?: boolean; secret?: boolean }[]\n}\n\n/**\n * Load a Bruno collection directory: each `<name>.bru` request (+ optional\n * `<name>.sackville.yml` sidecar), plus any `environments/<Env>.bru` files.\n */\nexport function loadCollection(dir: string): Collection {\n const requests = new Map<string, RequestEntry>()\n for (const file of readdirSync(dir)) {\n if (!file.endsWith('.bru') || NON_REQUEST.has(file)) continue\n const stem = basename(file, '.bru')\n const parsed = bruToJsonV2(readFileSync(join(dir, file), 'utf8')) as BruJson\n const request = toRequest(stem, parsed)\n\n const entry: RequestEntry = { request, assertions: [], captures: [] }\n const sidecar = join(dir, `${stem}.sackville.yml`)\n if (existsSync(sidecar)) {\n const yaml = (parseYaml(readFileSync(sidecar, 'utf8')) ?? {}) as Sidecar\n entry.assertions = yaml.assertions ?? []\n entry.captures = yaml.captures ?? []\n entry.preScript = yaml.preScript\n entry.postScript = yaml.postScript\n }\n requests.set(stem, entry)\n }\n return { dir, requests, environments: loadEnvironments(dir) }\n}\n\nfunction loadEnvironments(dir: string): Map<string, Record<string, string>> {\n const environments = new Map<string, Record<string, string>>()\n const envDir = join(dir, 'environments')\n if (!existsSync(envDir)) return environments\n for (const file of readdirSync(envDir)) {\n if (!file.endsWith('.bru')) continue\n const parsed = bruToEnvJsonV2(readFileSync(join(envDir, file), 'utf8')) as EnvJson\n const vars: Record<string, string> = {}\n for (const v of parsed.variables ?? []) {\n // Skip disabled and secret-marked vars (real secrets come from the SecretStore).\n if (v.enabled !== false && !v.secret) vars[v.name] = v.value\n }\n environments.set(basename(file, '.bru'), vars)\n }\n return environments\n}\n\nfunction toRequest(stem: string, parsed: BruJson): ApiRequest {\n const http = parsed.http ?? {}\n const headers = (parsed.headers ?? [])\n .filter((h) => h.enabled !== false)\n .map((h) => ({ name: h.name, value: h.value }))\n return {\n name: parsed.meta?.name ?? stem,\n method: String(http.method ?? 'get').toUpperCase(),\n url: http.url ?? '',\n headers,\n body: toBody(http.body, parsed.body),\n }\n}\n\nfunction toBody(rawType: string | undefined, body: BruBody | undefined): RequestBody | undefined {\n if (!rawType || rawType === 'none') return undefined\n // Normalize the parser's camelCase discriminator to our canonical name.\n const type = BODY_TYPE_ALIASES[rawType] ?? rawType\n\n if (type === 'form-urlencoded') {\n const params = (body?.formUrlEncoded ?? [])\n .filter((p) => p.enabled !== false)\n .map((p) => ({ name: p.name, value: p.value }))\n return { type, params }\n }\n if (type === 'graphql') {\n const gql = body?.graphql\n return { type, graphql: { query: gql?.query ?? '', variables: gql?.variables } }\n }\n if (type === 'multipart-form') {\n return { type, parts: toParts(body?.multipartForm ?? []) }\n }\n if (type === 'file') {\n const selected = (body?.file ?? []).find((f) => f.selected !== false) ?? body?.file?.[0]\n if (selected) {\n return { type, file: { filePath: selected.filePath, contentType: selected.contentType } }\n }\n return { type }\n }\n if (RAW_BODY_TYPES.has(type)) {\n const content = body?.[type as keyof BruBody]\n if (typeof content === 'string') return { type, content }\n }\n // Recognized but with no payload to materialize.\n return { type }\n}\n\nfunction toParts(parts: BruMultipartPart[]): MultipartPart[] {\n return parts\n .filter((p) => p.enabled !== false)\n .map((p) => {\n if (p.type === 'file') {\n const filePaths = Array.isArray(p.value) ? p.value : [p.value]\n return {\n name: p.name,\n kind: 'file' as const,\n filePaths,\n contentType: p.contentType || undefined,\n }\n }\n const value = Array.isArray(p.value) ? (p.value[0] ?? '') : p.value\n return { name: p.name, kind: 'text' as const, value }\n })\n}\n","/**\n * OpenAPI 3.1 response-contract validation. OpenAPI 3.1's Schema Object *is*\n * JSON Schema 2020-12, so response bodies are validated with the same ajv\n * validator as the `schema` assertion (see ADR 0005 for why we validate\n * directly rather than via openapi-backend). Surfaces drift: requests to\n * undocumented operations, undocumented status codes, and bodies that violate\n * the declared response schema.\n *\n * Scope: local `#/components/schemas/...` `$ref`s are resolved (rewritten into\n * `$defs` so ajv handles recursion natively); **external local-file** `$ref`s\n * are inlined when a `baseDir` is supplied (JSON + YAML, incl. the file's own\n * internal refs, cycle-guarded). OpenAPI 3.0 `nullable` is shimmed to a 3.1 type\n * union. Still out of scope: **remote (http) `$ref`s** (SSRF) and non-schema\n * `$ref`s (parameters, shared `responses`).\n */\nimport { readFileSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport { parse as parseYaml } from 'yaml'\nimport type { ContractFinding, ContractResult } from './model.js'\nimport { validateSchema } from './schema.js'\n\n// Open interfaces: a parsed OpenAPI document carries far more than we read, so\n// each shape allows arbitrary extra keys rather than fighting the type checker.\ninterface OpenApiResponse {\n content?: Record<string, { schema?: unknown }>\n [key: string]: unknown\n}\ninterface OpenApiOperation {\n responses?: Record<string, OpenApiResponse>\n [key: string]: unknown\n}\nexport interface OpenApiDoc {\n paths?: Record<string, Record<string, OpenApiOperation> | undefined>\n // `requestBodies`/`parameters`/etc. are navigated by the request validator's local\n // `$ref` deref, so allow any component bucket — not just `schemas`.\n components?: { schemas?: Record<string, unknown>; [key: string]: unknown }\n [key: string]: unknown\n}\n\nexport interface ResponseFacts {\n status: number\n headers?: Record<string, string>\n body: unknown\n}\n\nconst COMPONENT_PREFIX = '#/components/schemas/'\n\n/** Build a regex matching a path template (`/users/{id}`) against a concrete path. */\nfunction pathToRegex(template: string): RegExp {\n const literals = template.split(/\\{[^}]+\\}/)\n const escaped = literals.map((part) => part.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')).join('[^/]+')\n return new RegExp(`^${escaped}/?$`)\n}\n\nfunction matchPath(\n paths: NonNullable<OpenApiDoc['paths']>,\n reqPath: string,\n): { template: string; item: Record<string, OpenApiOperation> } | undefined {\n const clean = reqPath.split('?')[0] ?? reqPath\n const exact = paths[clean]\n if (exact) return { template: clean, item: exact }\n for (const [template, item] of Object.entries(paths)) {\n if (item && pathToRegex(template).test(clean)) return { template, item }\n }\n return undefined\n}\n\n/** Find the response object for a status, honoring `2XX` ranges and `default`. */\nfunction findResponse(\n responses: Record<string, OpenApiResponse>,\n status: number,\n): OpenApiResponse | undefined {\n const exact = responses[String(status)]\n if (exact) return exact\n // Range keys appear as both `2XX` (spec) and `2xx` (common in the wild).\n const digit = Math.floor(status / 100)\n const range = responses[`${digit}XX`] ?? responses[`${digit}xx`]\n if (range) return range\n return responses.default\n}\n\n/** Pick the JSON response schema (prefers application/json, then *​/*, then first). */\nfunction pickJsonSchema(response: OpenApiResponse): unknown {\n const content = response.content\n if (!content) return undefined\n const entry = content['application/json'] ?? content['*/*'] ?? Object.values(content)[0]\n return entry?.schema\n}\n\n/** Navigate a JSON Pointer (`#/A/B`) within a document. */\nfunction navigatePointer(doc: unknown, pointer: string): unknown {\n const path = pointer.replace(/^#/, '').split('/').filter(Boolean)\n let node: unknown = doc\n for (const raw of path) {\n const key = raw.replace(/~1/g, '/').replace(/~0/g, '~')\n if (!node || typeof node !== 'object') return undefined\n node = (node as Record<string, unknown>)[key]\n }\n return node\n}\n\n/** Load + parse a referenced file (JSON or YAML by extension), cached by path. */\nfunction loadRefDoc(absPath: string, cache: Map<string, unknown>): unknown {\n const cached = cache.get(absPath)\n if (cached !== undefined) return cached\n const text = readFileSync(absPath, 'utf8')\n const doc = /\\.ya?ml$/i.test(absPath) ? parseYaml(text) : JSON.parse(text)\n cache.set(absPath, doc)\n return doc\n}\n\n/**\n * Inline external local-file `$ref`s into a self-contained schema. A `$ref`\n * pointing at `file#/pointer` is loaded from disk (relative to `baseDir`),\n * navigated, and FULLY dereferenced — the external file's own internal (`#/…`)\n * and nested external refs are inlined too, relative to that file. Internal\n * refs of the MAIN document (`#/components/schemas/…`) are left intact (handled\n * by the `$defs` rewrite). Remote (http) refs remain out of scope (SSRF). A\n * cycle guard caps recursion on self-referential external schemas.\n */\nfunction inlineExternalRefs(\n node: unknown,\n baseDir: string,\n cache: Map<string, unknown>,\n // When set, `#/…` refs resolve within `doc` (an external file) and are inlined;\n // when undefined, the node is the MAIN doc and internal refs are left as-is.\n doc: unknown,\n stack: Set<string>,\n): unknown {\n if (Array.isArray(node)) {\n return node.map((n) => inlineExternalRefs(n, baseDir, cache, doc, stack))\n }\n if (!node || typeof node !== 'object') return node\n\n const ref = (node as Record<string, unknown>).$ref\n if (typeof ref === 'string') {\n const external = !ref.startsWith('#')\n if (external) {\n const [filePart, pointer = ''] = ref.split('#')\n const absPath = resolve(baseDir, filePart as string)\n const key = `${absPath}#${pointer}`\n if (stack.has(key)) return {} // cycle: stop inlining (permissive)\n const refDoc = loadRefDoc(absPath, cache)\n const subtree = navigatePointer(refDoc, `#${pointer}`)\n return inlineExternalRefs(subtree, dirname(absPath), cache, refDoc, new Set([...stack, key]))\n }\n if (doc !== undefined) {\n // Internal ref WITHIN an external file → resolve against that file + inline.\n if (stack.has(ref)) return {} // cycle guard\n const subtree = navigatePointer(doc, ref)\n return inlineExternalRefs(subtree, baseDir, cache, doc, new Set([...stack, ref]))\n }\n // Internal ref of the MAIN doc — leave for the $defs rewrite.\n return node\n }\n\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(node as Record<string, unknown>)) {\n out[k] = inlineExternalRefs(v, baseDir, cache, doc, stack)\n }\n return out\n}\n\n/**\n * OpenAPI 3.0 used `nullable: true` instead of 3.1's `type: ['string', 'null']`.\n * ajv (JSON Schema 2020-12) ignores `nullable`, so without this shim a 3.0 doc\n * gives a false failure on an explicit null. Rewrite `{type:'X', nullable:true}`\n * → `{type:['X','null']}` and drop the (non-2020) `nullable` keyword everywhere.\n */\nfunction shimNullable(node: unknown): unknown {\n if (Array.isArray(node)) return node.map(shimNullable)\n if (!node || typeof node !== 'object') return node\n const out: Record<string, unknown> = {}\n const src = node as Record<string, unknown>\n for (const [key, value] of Object.entries(src)) {\n if (key === 'nullable') continue // dropped (handled below)\n out[key] = shimNullable(value)\n }\n if (src.nullable === true) {\n if (typeof src.type === 'string') out.type = [src.type, 'null']\n else if (Array.isArray(src.type) && !src.type.includes('null')) out.type = [...src.type, 'null']\n }\n return out\n}\n\n/** Recursively rewrite `#/components/schemas/X` $refs to `#/$defs/X`. */\nfunction rewriteRefs(node: unknown): unknown {\n if (Array.isArray(node)) return node.map(rewriteRefs)\n if (node && typeof node === 'object') {\n const out: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(node as Record<string, unknown>)) {\n if (key === '$ref' && typeof value === 'string' && value.startsWith(COMPONENT_PREFIX)) {\n out.$ref = `#/$defs/${value.slice(COMPONENT_PREFIX.length)}`\n } else {\n out[key] = rewriteRefs(value)\n }\n }\n return out\n }\n return node\n}\n\n/**\n * Validate a response against an OpenAPI 3.1 document. Returns structured\n * findings; `valid` is true only when no `error`-severity finding is present.\n */\nexport interface OpenApiValidateOptions {\n /** Directory the spec was loaded from — enables external local-file `$ref`\n * resolution (relative refs resolve against it). Omit to disable. */\n baseDir?: string\n}\n\n/** A resolved OpenAPI operation: the operation object, its path template, and the\n * raw path-item (its method keys plus any path-level `parameters`). */\nexport interface ResolvedOperation {\n operation: OpenApiOperation\n template: string\n pathItem: Record<string, unknown>\n}\n\n/**\n * Resolve `METHOD path` to its OpenAPI operation via path-template matching (shared\n * by the response AND request validators — extracted so both resolve operations the\n * same way). Returns `undefined` when no path template / method matches.\n */\nexport function resolveOpenApiOperation(\n spec: OpenApiDoc,\n method: string,\n path: string,\n): ResolvedOperation | undefined {\n const matched = spec.paths ? matchPath(spec.paths, path) : undefined\n const operation = matched?.item[method.toLowerCase()]\n if (!matched || !operation) return undefined\n return {\n operation,\n template: matched.template,\n pathItem: matched.item as Record<string, unknown>,\n }\n}\n\n/**\n * Normalize an OpenAPI schema for ajv (2020-12) and return a self-contained schema\n * with component schemas merged into `$defs`. Shared by the response AND request\n * (body + parameter) validators so every schema gets the same treatment: external\n * local-file `$ref` inlining (when `baseDir` is set), the OpenAPI 3.0 `nullable`→\n * type-union shim, and the `#/components/schemas/X`→`#/$defs/X` rewrite. A schema's\n * own local `$defs` win over component defs on a name clash.\n */\nexport function normalizeOpenApiSchema(\n schema: unknown,\n spec: OpenApiDoc,\n opts: OpenApiValidateOptions = {},\n): Record<string, unknown> {\n const is30 = String(spec.openapi ?? '').startsWith('3.0')\n const cache = new Map<string, unknown>()\n const normalize = (sub: unknown) => {\n const inlined = opts.baseDir\n ? inlineExternalRefs(sub, opts.baseDir, cache, undefined, new Set())\n : sub\n return rewriteRefs(is30 ? shimNullable(inlined) : inlined)\n }\n const componentDefs = Object.fromEntries(\n Object.entries(spec.components?.schemas ?? {}).map(([name, sub]) => [name, normalize(sub)]),\n )\n const rewritten = normalize(schema) as Record<string, unknown>\n const localDefs = (rewritten.$defs as Record<string, unknown> | undefined) ?? {}\n return { ...rewritten, $defs: { ...componentDefs, ...localDefs } }\n}\n\nexport function validateOpenApiResponse(\n spec: OpenApiDoc,\n req: { method: string; path: string },\n res: ResponseFacts,\n opts: OpenApiValidateOptions = {},\n): ContractResult {\n const findings: ContractFinding[] = []\n const method = req.method.toLowerCase()\n\n const resolved = resolveOpenApiOperation(spec, method, req.path)\n if (!resolved) {\n findings.push({\n kind: 'missing-operation',\n severity: 'error',\n message: `no operation ${req.method.toUpperCase()} ${req.path} in the OpenAPI document`,\n })\n return { valid: false, findings }\n }\n\n const op = { method, path: resolved.template }\n const responses = resolved.operation.responses ?? {}\n const response = findResponse(responses, res.status)\n if (!response) {\n findings.push({\n kind: 'undocumented-status',\n severity: 'error',\n message: `status ${res.status} is not documented for ${method.toUpperCase()} ${resolved.template}`,\n })\n return { valid: false, findings, operation: op }\n }\n\n const schema = pickJsonSchema(response)\n if (schema !== undefined) {\n const compiled = normalizeOpenApiSchema(schema, spec, opts)\n const { valid, errors } = validateSchema(compiled, res.body)\n if (!valid) {\n for (const err of errors) {\n findings.push({\n kind: 'response-schema',\n severity: 'error',\n path: err.instancePath,\n message: err.message,\n })\n }\n }\n }\n\n return {\n valid: findings.every((f) => f.severity !== 'error'),\n findings,\n operation: op,\n }\n}\n","/**\n * GraphQL operation + response validation via graphql-js. The high-value check\n * is **drift**: validate a saved query against the server's *current* schema\n * (SDL), so a field removed or renamed upstream surfaces as a finding rather\n * than a silent `null`. Also inspects the response payload for a non-empty\n * top-level `errors` array, and — when `variables` are supplied (ADR 0015) —\n * validates the runtime variable VALUES against the operation's declared types.\n */\nimport {\n buildSchema,\n type DocumentNode,\n GraphQLError,\n type GraphQLSchema,\n type GraphQLType,\n getNamedType,\n getVariableValues,\n isInputObjectType,\n isNonNullType,\n isScalarType,\n Kind,\n type OperationDefinitionNode,\n parse,\n print,\n TypeInfo,\n typeFromAST,\n validate,\n visit,\n visitWithTypeInfo,\n} from 'graphql'\nimport type { ContractFinding, ContractResult } from './model.js'\n\ninterface GraphqlPayload {\n data?: unknown\n errors?: { message?: string }[]\n}\n\nexport interface GraphqlValidateOptions {\n /** Response payload to inspect for a top-level `errors` array. */\n json?: unknown\n /** For a multi-operation document, scope the root-type drift check to this\n * operation (and require it to exist). Without it, every operation is checked. */\n operationName?: string\n /** The runtime variable values to validate against the operation's declared variable\n * types (ADR 0015). Variable validation runs ONLY when this is provided (so existing\n * query-vs-SDL-only callers are behavior-preserved). */\n variables?: unknown\n /** Caller KNOWS the variable set is complete (direct surfaces hold the real request).\n * Default false: an absent required variable is `unverified`, not a finding. */\n variablesAuthoritative?: boolean\n /** Operator-supplied custom-scalar coercers, keyed by scalar name (ADR 0018). A registered\n * scalar's VARIABLE values become checkable (the coercer throws on definite invalidity);\n * document literals are NEVER routed through coercers (the `parseLiteral` leak guard, §3).\n * Built-in scalar names are silently ignored (§8.5). Operator-set — never an agent input;\n * the MCP surface selects coercers by NAME against an operator-bound registry. */\n scalarCoercers?: Record<string, ScalarCoercer>\n}\n\n/**\n * A custom-scalar coercer (ADR 0018). Throws (any error) to reject a value as definitely\n * invalid; the return value is IGNORED — only throw/no-throw is the signal. MUST throw ONLY on\n * definite invalidity (indeterminate ⇒ do not throw, so an uncertain value never false-fires).\n * Applies to VARIABLE values only — document literals are never routed through a coercer.\n */\nexport type ScalarCoercer = (value: unknown) => unknown\n\nexport interface GraphqlValidationResult extends ContractResult {\n /** A variable set the validator could not check (custom-scalar-typed variables, a\n * non-object `variables`, an ambiguous multi-operation target, or an absent required\n * variable the caller is not authoritative about) — OR a custom-scalar directive-arg\n * literal (ADR 0018 D2). Additive/optional — the verdict shape is UNCHANGED; the capture\n * bridge folds this into `noSignal` so it can never become a pass (absence-is-never-a-pass).\n * Omitted when everything relevant was verifiable. */\n unverified?: boolean\n /** The `unverified` flag was (at least partly) caused by a custom-scalar directive-arg\n * LITERAL (ADR 0018 D2), as distinct from an unverifiable variable. Additive/optional; lets\n * the capture bridge bump the distinct `graphql-directive-unverified` summary key (ADR 0018\n * §8.4) instead of mislabeling it `graphql-variable-unverified`. Omitted otherwise. */\n directiveUnverified?: boolean\n}\n\n/** The five built-in scalars graphql-js can actually coerce. A custom scalar declared in\n * SDL via `buildSchema` uses an identity `parseValue` (validates nothing), so a variable\n * typed over one carries no signal and must be `unverified`-skipped — UNLESS the operator\n * registered a coercer for it (ADR 0018), making its `parseValue` actually validate. */\nconst BUILTIN_SCALARS = new Set(['Int', 'Float', 'String', 'Boolean', 'ID'])\n\n/**\n * Does this resolved type (unwrapping NonNull/List, and transitively through input-object\n * fields) bottom out in a scalar that carries NO validation signal — i.e. a custom\n * (non-built-in) scalar WITHOUT a registered coercer? Cycle-guarded by `seen` keyed on the\n * input-object type name. Uses the schema-RESOLVED `GraphQLType` (via `typeFromAST`), never\n * the AST node. `registered` is the set of custom scalars with an operator coercer (ADR 0018);\n * pass an empty set for a coercer-INDEPENDENT check (e.g. the D2 directive-literal pass).\n */\nfunction typeInvolvesCustomScalar(\n type: GraphQLType,\n seen: Set<string>,\n registered: Set<string>,\n): boolean {\n const named = getNamedType(type)\n if (isScalarType(named)) return !BUILTIN_SCALARS.has(named.name) && !registered.has(named.name)\n if (isInputObjectType(named)) {\n if (seen.has(named.name)) return false\n seen.add(named.name)\n return Object.values(named.getFields()).some((f) =>\n typeInvolvesCustomScalar(f.type, seen, registered),\n )\n }\n return false // enums (and anything else) carry signal / are handled by validate()\n}\n\n/**\n * Patch the operator-registered custom-scalar coercers onto the freshly-built schema (ADR\n * 0018). Overwrites `parseValue` ONLY — NEVER `parseLiteral` (the redaction-leak guard, §3:\n * `validate()` invokes `parseLiteral` on every custom-scalar LITERAL, and a coercer throw\n * there would land the raw value + message into a finding). Variables traverse `parseValue`\n * via `getVariableValues`, so that is all Feature B needs. Built-in scalar names are silently\n * ignored (§8.5 — a built-in shadow could false-fire on a valid `@skip` Boolean variable).\n * Returns the set of scalar names actually patched (the `registered` set). Safe to mutate the\n * schema in place: `validateGraphqlOperation` builds a fresh, never-shared schema per call.\n */\nfunction patchRegisteredScalars(\n schema: GraphQLSchema,\n coercers: Record<string, ScalarCoercer> | undefined,\n): Set<string> {\n const registered = new Set<string>()\n if (!coercers) return registered\n for (const [name, coercer] of Object.entries(coercers)) {\n if (BUILTIN_SCALARS.has(name)) continue // built-in shadow ignored (safety-critical)\n const t = schema.getType(name)\n if (t && isScalarType(t)) {\n t.parseValue = coercer // parseValue ONLY — parseLiteral deliberately untouched (§3)\n registered.add(name)\n }\n }\n return registered\n}\n\n/**\n * Validate the runtime `variables` of a SINGLE resolved operation against its declared\n * variable types. Appends findings (reconstructed from variable NAME + declared TYPE +\n * category — NEVER from graphql-js messages, which echo raw values) and returns whether\n * anything was `unverified`.\n */\nfunction validateVariables(\n schema: GraphQLSchema,\n operation: OperationDefinitionNode,\n variables: unknown,\n authoritative: boolean,\n registered: Set<string>,\n findings: ContractFinding[],\n): boolean {\n // A `variables` that is not a plain JSON object (array/null/scalar) can't be interpreted\n // (an array makes every var look absent; null throws) → unverified, never a false finding.\n if (typeof variables !== 'object' || variables === null || Array.isArray(variables)) {\n return true\n }\n const vars = variables as Record<string, unknown>\n const varDefs = operation.variableDefinitions ?? []\n const declared = new Set<string>()\n let unverified = false\n\n for (const vd of varDefs) {\n const name = vd.variable.name.value\n declared.add(name)\n const resolved = typeFromAST(schema, vd.type)\n if (!resolved) continue // unknown type — already flagged by validate()\n const typeStr = print(vd.type)\n\n // A variable bottoming out in a custom scalar WITHOUT a registered coercer can't be\n // validated → no signal. A registered coercer (patched onto `parseValue`) makes\n // `getVariableValues` below actually validate it (ADR 0018).\n if (typeInvolvesCustomScalar(resolved, new Set(), registered)) {\n unverified = true\n continue\n }\n\n // Validate JUST this variable, so any error is structurally attributable to it\n // (no parsing graphql-js messages, which echo the raw value).\n const result = getVariableValues(schema, [vd], vars)\n if (!('errors' in result) || !result.errors || result.errors.length === 0) continue\n\n const present = name in vars\n if (!present) {\n // Absent. graphql-js only errors here for a required (non-null, no-default) variable;\n // a non-null WITH a default coerces cleanly (no error), so this IS missing-required.\n if (authoritative) {\n findings.push({\n kind: 'graphql-variable-missing',\n severity: 'error',\n message: `required variable \"$${name}\" of type \"${typeStr}\" was not provided`,\n })\n } else {\n unverified = true\n }\n } else if (vars[name] === null && isNonNullType(resolved)) {\n findings.push({\n kind: 'graphql-variable-invalid',\n severity: 'error',\n message: `variable \"$${name}\" of non-null type \"${typeStr}\" must not be null`,\n })\n } else {\n findings.push({\n kind: 'graphql-variable-invalid',\n severity: 'error',\n message: `variable \"$${name}\" got an invalid value for type \"${typeStr}\"`,\n })\n }\n }\n\n // Variables the operation never declares (graphql-js silently ignores them).\n for (const key of Object.keys(vars)) {\n if (!declared.has(key)) {\n findings.push({\n kind: 'graphql-undocumented-variable',\n severity: 'warning',\n message: `undocumented variable \"$${key}\" not declared by the operation`,\n })\n }\n }\n\n return unverified\n}\n\n/**\n * D2 (ADR 0018): does the document attach a directive-arg LITERAL whose type bottoms out in a\n * custom (non-built-in) scalar? Such a literal is validated by NOTHING — a `buildSchema` custom\n * scalar has an identity `parseLiteral` which we DELIBERATELY never patch (the redaction-leak\n * guard, ADR 0018 §3) — so it carries no signal and must fold to `unverified`, never a finding\n * (the literal may carry an inline secret) and never a silent pass.\n *\n * COERCER-INDEPENDENT (ADR 0018 BLOCKER-2): a registered variable coercer validates VARIABLE\n * values via `parseValue`, never document literals, so this check passes NO `registered` set —\n * a registered scalar's literal stays `unverified` all the same.\n *\n * Confined to DIRECTIVE-arg position (field-arg literals are out of scope, ADR 0018 S1); a\n * variable-valued directive arg is handled by the variable loop, so it is skipped here. Reuses\n * the transitive `typeInvolvesCustomScalar` so a list/input-object directive-arg literal with a\n * nested custom scalar folds correctly. Caller must gate on a structurally-clean query.\n */\nfunction hasCustomScalarDirectiveLiteral(schema: GraphQLSchema, document: DocumentNode): boolean {\n const typeInfo = new TypeInfo(schema)\n let directiveDepth = 0\n let found = false\n visit(\n document,\n visitWithTypeInfo(typeInfo, {\n Directive: {\n enter: () => {\n directiveDepth++\n },\n leave: () => {\n directiveDepth--\n },\n },\n Argument: (node) => {\n if (directiveDepth === 0) return // a FIELD arg — out of scope (S1)\n if (node.value.kind === Kind.VARIABLE) return // handled by the variable loop (D3)\n const t = typeInfo.getInputType()\n // Empty `registered` set: D2 is COERCER-INDEPENDENT (coercers validate variables via\n // `parseValue`, never document literals — so a registered scalar's literal stays\n // unverified all the same, ADR 0018 BLOCKER-2).\n if (t && typeInvolvesCustomScalar(t, new Set(), new Set())) found = true\n },\n }),\n )\n return found\n}\n\n/**\n * Validate a GraphQL `query` against a schema `sdl`; if `opts.json` is supplied,\n * also check the response payload for returned `errors`. With `opts.operationName`\n * the root-type drift check is scoped to that operation (which must exist). When\n * `opts.variables` is supplied, the runtime variable values are validated against the\n * operation's declared types (ADR 0015). `valid` is true only when no `error`-severity\n * finding is present.\n */\nexport function validateGraphqlOperation(\n sdl: string,\n query: string,\n opts: GraphqlValidateOptions = {},\n): GraphqlValidationResult {\n const findings: ContractFinding[] = []\n\n // The schema is the contract; a malformed SDL means we can't validate at all.\n let schema: ReturnType<typeof buildSchema>\n try {\n schema = buildSchema(sdl)\n } catch (err) {\n findings.push({\n kind: 'graphql-validation',\n severity: 'error',\n message: `invalid schema SDL: ${(err as Error).message}`,\n })\n return { valid: false, findings }\n }\n\n // Patch operator-registered custom-scalar coercers (parseValue only) onto the fresh schema;\n // `registered` then drives whether a custom-scalar variable is checkable (ADR 0018).\n const registered = patchRegisteredScalars(schema, opts.scalarCoercers)\n\n // Parse (syntax) then validate (semantics: unknown fields/args = drift).\n let document: ReturnType<typeof parse>\n try {\n document = parse(query)\n } catch (err) {\n const message = err instanceof GraphQLError ? err.message : (err as Error).message\n findings.push({ kind: 'graphql-syntax', severity: 'error', message })\n return { valid: false, findings }\n }\n\n for (const err of validate(schema, document)) {\n findings.push({ kind: 'graphql-validation', severity: 'error', message: err.message })\n }\n\n // Collect operation definitions; optionally scope to a named one.\n const operations = document.definitions.filter(\n (d): d is OperationDefinitionNode => d.kind === 'OperationDefinition',\n )\n let targets = operations\n if (opts.operationName !== undefined) {\n targets = operations.filter((d) => d.name?.value === opts.operationName)\n if (targets.length === 0) {\n findings.push({\n kind: 'graphql-validation',\n severity: 'error',\n message: `no operation named \"${opts.operationName}\" in the document`,\n })\n }\n }\n\n // graphql-js `validate()` does not flag a mutation/subscription whose root\n // type is absent from the schema (it's an execution-time error). For drift\n // detection that's exactly the case we care about, so check it explicitly.\n for (const def of targets) {\n const op = def.operation\n const rootType =\n op === 'mutation'\n ? schema.getMutationType()\n : op === 'subscription'\n ? schema.getSubscriptionType()\n : schema.getQueryType()\n if (!rootType) {\n findings.push({\n kind: 'graphql-validation',\n severity: 'error',\n message: `schema declares no root type for ${op} operations`,\n })\n }\n }\n\n // D2 + variable validation both run only on a structurally-clean query (validate() found\n // nothing) — otherwise the TypeInfo walk / variable payload can't be trusted/attributed.\n const queryClean = findings.every((f) => f.severity !== 'error')\n\n // --- D2: custom-scalar directive-arg LITERALS (ADR 0018) ---\n // Independent of `opts.variables` — it inspects the query's directive literals.\n const directiveUnverified = queryClean && hasCustomScalarDirectiveLiteral(schema, document)\n\n // --- Request-variable validation (ADR 0015) ---\n let variableUnverified = false\n if (opts.variables !== undefined && queryClean) {\n // Require a SINGLE resolved target operation — otherwise a variable payload can't be attributed.\n const targetOp = targets.length === 1 ? targets[0] : undefined\n if (!targetOp) {\n variableUnverified = true // ambiguous (multi-op, no operationName) or unresolved\n } else {\n variableUnverified = validateVariables(\n schema,\n targetOp,\n opts.variables,\n opts.variablesAuthoritative === true,\n registered,\n findings,\n )\n }\n }\n\n const unverified = directiveUnverified || variableUnverified\n\n const payload = opts.json as GraphqlPayload | undefined\n if (payload?.errors && payload.errors.length > 0) {\n const messages = payload.errors.map((e) => e.message ?? '(no message)').join('; ')\n findings.push({\n kind: 'graphql-errors',\n severity: 'error',\n message: `response returned ${payload.errors.length} GraphQL error(s): ${messages}`,\n })\n }\n\n return {\n valid: findings.every((f) => f.severity !== 'error'),\n findings,\n ...(unverified ? { unverified: true } : {}),\n ...(directiveUnverified ? { directiveUnverified: true } : {}),\n }\n}\n","/**\n * OpenAPI 3.1 (and 3.0-compat) REQUEST-side contract validation — the sibling of\n * `validateOpenApiResponse` (see ADR 0005; this milestone's design = the\n * request-contract-validation-design fan-out). It validates the request half of an\n * exchange against the declared operation: the request body against `requestBody`,\n * and parameters against `parameters` (path/query/header). It reuses the response\n * validator's extracted seams (`resolveOpenApiOperation`, `normalizeOpenApiSchema`)\n * so operation resolution and schema treatment (3.0 `nullable` shim, local +\n * external-local-file `$ref` deref) are identical across both halves.\n *\n * **Authority + the `unverified` channel (load-bearing, ADR 0013 absence-is-never-\n * a-pass):** some request facts cannot be verified from every source. A captured HAR\n * cannot distinguish \"no body\" from \"a non-JSON body the bridge dropped\", and cannot\n * always supply query/header params. So callers declare what they KNOW:\n * `bodyPresenceAuthoritative` / `paramsAuthoritative` (true for direct MCP/CLI\n * surfaces that hold the real request; false/omitted for the capture path). When a\n * required-but-absent body/param CANNOT be asserted as a breach (caller not\n * authoritative), or a present body could not be schema-checked, the result carries\n * `unverified: true` — NOT a finding — which the capture bridge folds into `noSignal`\n * so it can never be laundered into a pass.\n */\nimport {\n normalizeOpenApiSchema,\n type OpenApiDoc,\n type OpenApiValidateOptions,\n resolveOpenApiOperation,\n} from './contract.js'\nimport type { ContractFinding, ContractResult } from './model.js'\nimport { validateSchema } from './schema.js'\n\n/** The request facts a validator reads. `path` is the pathname only (matches\n * `CaptureEntry.req.path`); `body` is the already-parsed JSON body. */\nexport interface RequestFacts {\n method: string\n path: string\n body?: unknown\n query?: Record<string, string | string[]>\n /** Lower-cased header names → value. */\n headers?: Record<string, string>\n /** Decoded fields of a `form`-style body (`application/x-www-form-urlencoded` or the\n * text parts of `multipart/form-data`); repeated keys → array. The AUTHORITATIVE\n * structured channel for non-JSON body validation (ADR 0016 addendum 4) — populated at\n * prepare time from the structured parts, NEVER by re-parsing the serialized string.\n * File-part bytes never enter this map. */\n form?: Record<string, string | string[]>\n /** Field NAMES of `multipart/form-data` FILE parts (bytes never inlined — redaction).\n * A declared schema property satisfied by a file part is `unverified`-skipped. */\n formFileFields?: string[]\n}\n\nexport interface OpenApiRequestValidateOptions extends OpenApiValidateOptions {\n /** Caller KNOWS body presence/absence is authoritative (direct surfaces). Default\n * false: an absent required body is `unverified`, not `missing-required-body`. */\n bodyPresenceAuthoritative?: boolean\n /** Caller KNOWS query/header facts are complete (direct surfaces). Default false:\n * an absent required query/header param is `unverified`, not a finding. */\n paramsAuthoritative?: boolean\n}\n\nexport interface RequestValidationResult extends ContractResult {\n /** A body/param the validator could not verify and the caller is not authoritative\n * about. The capture bridge folds this into `noSignal` (never a finding, never a\n * pass). Omitted when everything relevant was verifiable. */\n unverified?: boolean\n}\n\n/** True when a parsed body looks like a GraphQL-over-HTTP envelope (`{query: string,\n * …}`). A direct surface uses this to refuse running OpenAPI body validation on a\n * GraphQL request (which has no REST requestBody shape) — H4. */\nexport function isGraphqlEnvelope(body: unknown): boolean {\n return (\n !!body && typeof body === 'object' && typeof (body as { query?: unknown }).query === 'string'\n )\n}\n\n/** Lower-cased media-type base (sans parameters), e.g. `application/json`. */\nfunction mediaBase(ct: string): string {\n return (ct.split(';')[0] ?? '').trim().toLowerCase()\n}\n\n/** JSON-family media type: `application/json` or any `*+json` (e.g. `application/ld+json`). */\nfunction isJsonMediaType(ct: string): boolean {\n const base = mediaBase(ct)\n return base === 'application/json' || base.endsWith('+json')\n}\n\ninterface RequestBodyObject {\n required?: boolean\n content?: Record<string, { schema?: unknown }>\n}\n\ninterface ParamObject {\n name?: string\n in?: string\n required?: boolean\n schema?: unknown\n style?: string\n explode?: boolean\n content?: unknown\n $ref?: string\n [key: string]: unknown\n}\n\n/** Merge path-item-level + operation-level `parameters`, operation winning on\n * `(name, in)`. Returns raw params (a `$ref` param is handled by the caller). */\nfunction mergeParameters(pathItem: Record<string, unknown>, operation: object): ParamObject[] {\n const collect = (x: unknown): ParamObject[] => {\n const ps = (x as { parameters?: unknown })?.parameters\n return Array.isArray(ps) ? (ps as ParamObject[]) : []\n }\n const map = new Map<string, ParamObject>()\n let i = 0\n for (const p of [...collect(pathItem), ...collect(operation)]) {\n if (!p || typeof p !== 'object') continue\n // $ref params (slice 1/2: not deref'd) get a unique key so they survive the merge.\n const key =\n typeof p.name === 'string' && typeof p.in === 'string' ? `${p.in}:${p.name}` : `#ref${i++}`\n map.set(key, p)\n }\n return [...map.values()]\n}\n\nconst SCALAR_TYPES = new Set(['string', 'number', 'integer', 'boolean'])\n\n/** The scalar JSON types of a (normalized) schema, or `undefined` when the schema\n * is non-scalar / typeless (array/object params are STAGED → inconclusive-skip). */\nfunction scalarTypes(schema: Record<string, unknown>): string[] | undefined {\n const t = schema.type\n if (typeof t === 'string') return SCALAR_TYPES.has(t) ? [t] : undefined\n if (Array.isArray(t)) {\n const nonNull = t.filter((x) => x !== 'null')\n return nonNull.length > 0 && nonNull.every((x) => SCALAR_TYPES.has(x as string))\n ? (t as string[])\n : undefined\n }\n return undefined\n}\n\n/** `'array'`/`'object'` for a (normalized) non-scalar schema, else `undefined`. A\n * `'null'`-augmented union (3.0 nullable shim) is tolerated; a union mixing\n * array/object with a scalar (or with each other) is ambiguous → `undefined`\n * (handled as a typeless skip, never a false validation). */\nfunction nonScalarType(schema: Record<string, unknown>): 'array' | 'object' | undefined {\n const t = schema.type\n if (typeof t === 'string') return t === 'array' || t === 'object' ? t : undefined\n if (Array.isArray(t)) {\n const nonNull = t.filter((x) => x !== 'null')\n if (nonNull.length > 0 && nonNull.every((x) => x === 'array')) return 'array'\n if (nonNull.length > 0 && nonNull.every((x) => x === 'object')) return 'object'\n }\n return undefined\n}\n\n/** A serialized array param cannot soundly prove its element COUNT from a single\n * wire occurrence (it might be an explode-disagreement). When the array schema\n * constrains cardinality, a single-occurrence value is `unverified`-skipped. */\nfunction hasCardinalityConstraint(schema: Record<string, unknown>): boolean {\n return (\n schema.minItems !== undefined || schema.maxItems !== undefined || schema.uniqueItems === true\n )\n}\n\n/** The delimiter joining elements of a non-exploded QUERY array for this style, or\n * `undefined` when the query style isn't a supported array serialization. */\nfunction queryArrayDelimiter(param: ParamObject): string | undefined {\n if (param.style === undefined || param.style === 'form') return ','\n if (param.style === 'spaceDelimited') return ' '\n if (param.style === 'pipeDelimited') return '|'\n return undefined\n}\n\n/** Whether this param's (location, style, type) is a supported ARRAY serialization\n * (query form/space/pipe-delimited, path simple/label/matrix, header simple). Explode +\n * item-type soundness are resolved in the handler. */\nfunction arraySerializationSupported(param: ParamObject): boolean {\n switch (param.in) {\n case 'query':\n return queryArrayDelimiter(param) !== undefined\n case 'header':\n return param.style === undefined || param.style === 'simple'\n case 'path':\n return (\n param.style === undefined ||\n param.style === 'simple' ||\n param.style === 'label' ||\n param.style === 'matrix'\n )\n default:\n return false // cookie + anything unknown\n }\n}\n\n/** A PATH array's split delimiter is `.` only for `label` + `explode` (RFC 6570\n * `{.list*}` → `.a.b.c`). `.` is the one delimiter that occurs inside a JSON `number`\n * (decimal point), so a `number`-typed label-explode array would over-split. */\nfunction arraySplitUsesDot(param: ParamObject): boolean {\n return param.in === 'path' && param.style === 'label' && (param.explode ?? false) === true\n}\n\n/** Decompose a serialized array value into its raw string elements, or `undefined`\n * when the serialization can't be soundly reversed (malformed prefix / unsupported\n * style) — the caller then `unverified`-skips. Query splits on the style delimiter;\n * header `simple` splits on `,` and trims; PATH handles simple/label/matrix × explode\n * (stripping the RFC 6570 `.`/`;name=` prefixes). */\nfunction splitArrayValue(param: ParamObject, value: string): string[] | undefined {\n if (param.in === 'query') {\n const d = queryArrayDelimiter(param)\n return d === undefined ? undefined : value.split(d)\n }\n if (param.in === 'header') return value.split(',').map((s) => s.trim())\n if (param.in === 'path') {\n const style = param.style ?? 'simple'\n if (style === 'simple') return value.split(',') // explode irrelevant for arrays\n if (style === 'label') {\n if (!value.startsWith('.')) return undefined\n const body = value.slice(1)\n return (param.explode ?? false) ? body.split('.') : body.split(',')\n }\n if (style === 'matrix') {\n const name = param.name as string\n if (param.explode ?? false) {\n if (!value.startsWith(';')) return undefined\n const out: string[] = []\n for (const part of value.slice(1).split(';')) {\n const pre = `${name}=`\n if (!part.startsWith(pre)) return undefined\n out.push(part.slice(pre.length))\n }\n return out\n }\n const pre = `;${name}=`\n return value.startsWith(pre) ? value.slice(pre.length).split(',') : undefined\n }\n }\n return undefined\n}\n\n/** Whether every non-null item type is a scalar whose value space cannot contain the\n * split delimiter — making a delimited split EXACT (element coercion AND cardinality\n * sound). `integer`/`boolean` never contain any of our delimiters; `number` contains\n * `.`, so it is excluded only when the dot delimiter is used (label-explode). String/\n * typeless items always over-split, so they stay `unverified`. */\nfunction itemTypesSplittable(itemTypes: string[], usesDotDelimiter: boolean): boolean {\n const nonNull = itemTypes.filter((t) => t !== 'null')\n if (nonNull.length === 0) return false\n return nonNull.every(\n (t) => t === 'integer' || t === 'boolean' || (t === 'number' && !usesDotDelimiter),\n )\n}\n\n/** A FRACTIONAL `multipleOf` is the IEEE-754 false-positive trap: coercing a wire\n * string to a JS float then ajv-checking e.g. `multipleOf: 0.1` reports a\n * spec-conformant value like `0.3` as invalid (0.3/0.1 ≠ an integer in binary). We\n * can't soundly assert conformance, so a scalar schema carrying one is `unverified`-\n * skipped (an INTEGER `multipleOf` divides exactly and stays validated). */\nfunction hasFractionalMultipleOf(schema: Record<string, unknown>): boolean {\n const m = schema.multipleOf\n return typeof m === 'number' && !Number.isInteger(m)\n}\n\n/** Which query OBJECT serializations the validator reconstructs. deepObject\n * (`name[prop]` discrete keys) and form/`explode=false` (`name=k,v,k,v` single string)\n * are checkable; form/`explode=true` objects merge into the shared top-level namespace\n * (irreducibly ambiguous — only their undoc-param SUPPRESSION is supported), and\n * path/header/cookie objects are STAGED. */\nfunction objectSerializationSupported(param: ParamObject): boolean {\n if (param.in !== 'query') return false\n if (param.style === 'deepObject') return true\n return (param.style === undefined || param.style === 'form') && param.explode === false\n}\n\n/**\n * Which (location, style, type) serializations the validator can soundly check.\n * SCALARS: the default per location (path/header `simple`, query `form`). ARRAYS: any\n * `arraySerializationSupported` location/style (query form/space/pipe-delimited, path\n * simple/label/matrix, header simple); explode + item-type soundness are resolved in the\n * handler. OBJECTS and every other style/location (deepObject/cookie/content-typed) are\n * OBJECTS: query deepObject + form/`explode=false` (`objectSerializationSupported`).\n * Everything else (path/header/cookie objects, form/`explode=true` objects, content-\n * typed) is STAGED → inconclusive-skip. `schema` is the NORMALIZED param schema (so the\n * array/scalar decision sees the 3.0 nullable shim). */\nfunction styleSupported(param: ParamObject, schema: Record<string, unknown> | undefined): boolean {\n if (param.content) return false\n const nonScalar = schema ? nonScalarType(schema) : undefined\n if (nonScalar === 'array') return arraySerializationSupported(param)\n if (nonScalar === 'object') return objectSerializationSupported(param)\n switch (param.in) {\n case 'query':\n return param.style === undefined || param.style === 'form'\n case 'header':\n case 'path':\n return param.style === undefined || param.style === 'simple'\n default:\n return false // cookie + anything unknown\n }\n}\n\n/** Strict scalar coercion of a captured string value to a declared scalar type.\n * Numeric/boolean must match the WHOLE string (no residue); an empty value coerces\n * to `null` only when the type union allows it. Never touches the shared ajv. */\nfunction coerceScalar(raw: string, types: string[]): { ok: true; value: unknown } | { ok: false } {\n if (raw === '' && types.includes('null')) return { ok: true, value: null }\n for (const t of types) {\n if (t === 'string') return { ok: true, value: raw }\n if (t === 'integer' && /^[+-]?\\d+$/.test(raw)) return { ok: true, value: Number(raw) }\n if (t === 'number' && /^[+-]?(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][+-]?\\d+)?$/.test(raw)) {\n return { ok: true, value: Number(raw) }\n }\n if (t === 'boolean') {\n if (raw === 'true') return { ok: true, value: true }\n if (raw === 'false') return { ok: true, value: false }\n }\n }\n return { ok: false }\n}\n\n/** Positionally extract path-template params from the concrete path. A segment that\n * embeds a param but is not EXACTLY `{name}` (e.g. `{name}.{ext}`) cannot be split\n * positionally → its params are `skipped` (inconclusive, never a false-fail). */\nfunction extractPathParams(\n template: string,\n concrete: string,\n): { values: Map<string, string>; skipped: Set<string> } {\n const tSegs = template.split('/')\n const cSegs = (concrete.split('?')[0] ?? '').split('/')\n const values = new Map<string, string>()\n const skipped = new Set<string>()\n for (let i = 0; i < tSegs.length; i++) {\n const t = tSegs[i] ?? ''\n const exact = t.match(/^\\{([^}]+)\\}$/)\n if (exact?.[1]) {\n const raw = cSegs[i]\n if (raw !== undefined) {\n let decoded = raw\n try {\n decoded = decodeURIComponent(raw)\n } catch {\n /* keep raw on malformed encoding */\n }\n values.set(exact[1], decoded)\n }\n } else if (t.includes('{')) {\n for (const m of t.matchAll(/\\{([^}]+)\\}/g)) if (m[1]) skipped.add(m[1])\n }\n }\n return { values, skipped }\n}\n\ntype ParamLookup =\n | { state: 'present'; value: string }\n | { state: 'absent' }\n | { state: 'array-values'; values: string[] } // ≥2 query occurrences (an exploded array)\n | { state: 'multi' } // composite path segment / unsupported repetition → STAGED skip\n\nfunction lookupParamValue(\n param: ParamObject,\n req: RequestFacts,\n pathVals: { values: Map<string, string>; skipped: Set<string> },\n): ParamLookup {\n const name = param.name as string\n if (param.in === 'path') {\n if (pathVals.skipped.has(name)) return { state: 'multi' }\n const v = pathVals.values.get(name)\n return v === undefined ? { state: 'absent' } : { state: 'present', value: v }\n }\n if (param.in === 'query') {\n const q = req.query?.[name]\n if (q === undefined) return { state: 'absent' }\n if (Array.isArray(q))\n return q.length === 1 && q[0] !== undefined\n ? { state: 'present', value: q[0] }\n : { state: 'array-values', values: q } // ≥2 occurrences (queryRecord only arrays >1)\n return { state: 'present', value: q }\n }\n if (param.in === 'header') {\n const h = req.headers?.[name.toLowerCase()]\n return h === undefined ? { state: 'absent' } : { state: 'present', value: h }\n }\n return { state: 'absent' }\n}\n\n/**\n * Validate an ARRAY param (query form/space/pipe-delimited, path/header `simple`)\n * against its declared schema. Resolves the wire elements per (state, style, explode):\n *\n * - `array-values` (≥2 query occurrences, explode=true) — the discrete elements, NO\n * split, so any scalar item type is sound.\n * - query `form` + explode=true, single occurrence — wrapped `[v]` ONLY when it carries\n * no comma (no explode-disagreement) and the schema has no cardinality constraint\n * (else `unverified`).\n * - DELIMITED single string (query explode=false form/space/pipe, path simple/label/\n * matrix, header simple) — decomposed by `splitArrayValue`, but ONLY for scalar items\n * whose value space can't contain the delimiter (`integer`/`boolean` always; `number`\n * unless the dot delimiter is used); string/typeless items, empty segments, and a\n * malformed prefix are `unverified` (embedded-delimiter / serialization ambiguity).\n *\n * Appends `param-schema` findings; returns whether the param was `unverified`-skipped.\n */\nfunction validateArrayParam(\n param: ParamObject,\n normSchema: Record<string, unknown>,\n lk: ParamLookup,\n findings: ContractFinding[],\n): boolean {\n // Tuple/heterogeneous or non-scalar items carry no element splitter we can coerce.\n const itemSchema = normSchema.items\n const itemTypes =\n itemSchema && typeof itemSchema === 'object' && !Array.isArray(itemSchema)\n ? scalarTypes(itemSchema as Record<string, unknown>)\n : undefined\n if (normSchema.prefixItems !== undefined || !itemTypes) return true\n // A fractional `multipleOf` on the items is the IEEE-754 false-positive trap — skip.\n if (hasFractionalMultipleOf(itemSchema as Record<string, unknown>)) return true\n\n const explodeTrue =\n param.in === 'query' &&\n (param.style === undefined || param.style === 'form') &&\n (param.explode ?? true) === true\n\n let elements: string[]\n if (lk.state === 'array-values') {\n elements = lk.values // discrete elements — no split, string items fine\n } else if (lk.state === 'present' && explodeTrue) {\n // Single occurrence: ambiguous unless it carries no delimiter AND no cardinality.\n if (lk.value.includes(',') || hasCardinalityConstraint(normSchema)) return true\n elements = [lk.value]\n } else if (lk.state === 'present') {\n // DELIMITED single string. Sound to split ONLY when the delimiter can't occur\n // inside an element and the serialization parses cleanly.\n if (!itemTypesSplittable(itemTypes, arraySplitUsesDot(param))) return true\n const parts = splitArrayValue(param, lk.value)\n if (parts === undefined || parts.some((s) => s === '')) return true\n elements = parts\n } else {\n return true // 'multi'/'absent' — handled upstream; skip defensively\n }\n\n const want = itemTypes.filter((t) => t !== 'null').join('|')\n const coerced: unknown[] = []\n let anyBad = false\n for (const el of elements) {\n const c = coerceScalar(el, itemTypes)\n if (!c.ok) {\n anyBad = true\n findings.push({\n kind: 'param-schema',\n severity: 'error',\n path: param.name as string,\n // Echo the RAW captured element, never the coerced value (redaction).\n message: `${param.in} parameter '${param.name}' value '${el}' is not a valid ${want}`,\n })\n } else {\n coerced.push(c.value)\n }\n }\n if (anyBad) return false // a finding was raised; the array can't be assembled for ajv\n const { valid, errors } = validateSchema(normSchema, coerced)\n if (!valid) {\n for (const err of errors) {\n findings.push({\n kind: 'param-schema',\n severity: 'error',\n path: param.name as string,\n message: `${param.in} parameter '${param.name}' ${err.message}`,\n })\n }\n }\n return false\n}\n\n/** Escape a string for literal use inside a RegExp. */\nfunction escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\n/**\n * Validate a query OBJECT param against its declared schema. deepObject reconstructs\n * from discrete `name[prop]` keys (so STRING props are sound — no split); form/\n * `explode=false` splits the single `name=k,v,k,v` string (integer/boolean props ONLY —\n * a string value's comma cascades, a number's float mis-coerces). Declared scalar props\n * are coerced; undeclared keys pass through (ajv handles them per additionalProperties);\n * the assembled object is ajv-validated. Returns whether the param was `unverified`.\n *\n * REFUSE (→ unverified, never a false finding) when reconstruction can't be sound: no\n * flat scalar `properties`; an object-form `additionalProperties` (an undeclared key we\n * leave uncoerced could false-fail a typed schema); any prop with a fractional\n * `multipleOf` (float trap); a deepObject nested (`a[b]`) or repeated key; a form/\n * explode=false object with any non-(integer|boolean) prop, `additionalProperties !==\n * false`, or an odd/empty split.\n */\nfunction validateObjectParam(\n param: ParamObject,\n normSchema: Record<string, unknown>,\n req: RequestFacts,\n opts: OpenApiRequestValidateOptions,\n method: string,\n template: string,\n findings: ContractFinding[],\n): boolean {\n const props = normSchema.properties\n if (!props || typeof props !== 'object' || Array.isArray(props)) return true\n const propEntries = Object.entries(props as Record<string, unknown>)\n if (propEntries.length === 0) return true\n const propTypes = new Map<string, string[]>()\n for (const [propName, sub] of propEntries) {\n if (!sub || typeof sub !== 'object' || Array.isArray(sub)) return true\n const s = sub as Record<string, unknown>\n const t = scalarTypes(s)\n if (!t || hasFractionalMultipleOf(s)) return true // non-scalar prop / float trap\n propTypes.set(propName, t)\n }\n // Only literal true/false/absent additionalProperties can be reasoned about; an\n // object-form (typed/empty) schema means an undeclared key we'd leave uncoerced could\n // false-fail — refuse.\n const ap = normSchema.additionalProperties\n if (ap !== undefined && typeof ap !== 'boolean') return true\n\n const name = param.name as string\n const collected: Array<[string, string]> = []\n let present = false\n\n if (param.style === 'deepObject') {\n const prefix = `${name}[`\n const flat = new RegExp(`^${escapeRegExp(name)}\\\\[([^\\\\]]+)\\\\]$`)\n for (const [key, val] of Object.entries(req.query ?? {})) {\n if (!key.startsWith(prefix)) continue\n present = true\n const m = flat.exec(key)\n if (!m || m[1] === undefined) return true // nested / malformed bracket key\n if (Array.isArray(val)) return true // repeated deepObject key\n collected.push([m[1], val])\n }\n } else {\n // form/explode=false: under the single key `name`; sound only for integer/boolean\n // props (string → comma cascade, number → float) with additionalProperties:false.\n if (ap !== false) return true\n for (const t of propTypes.values()) {\n if (!t.filter((x) => x !== 'null').every((x) => x === 'integer' || x === 'boolean')) {\n return true\n }\n }\n const raw = req.query?.[name]\n if (raw === undefined) {\n present = false\n } else if (Array.isArray(raw) || raw === '') {\n return true // repeated / empty → ambiguous\n } else {\n present = true\n const segs = raw.split(',')\n if (segs.length % 2 !== 0 || segs.some((s) => s === '')) return true\n for (let i = 0; i < segs.length; i += 2) {\n collected.push([segs[i] as string, segs[i + 1] as string])\n }\n }\n }\n\n if (!present) {\n if (param.required === true) {\n if (opts.paramsAuthoritative) {\n findings.push({\n kind: 'missing-required-param',\n severity: 'error',\n path: name,\n message: `required ${param.in} parameter '${name}' missing for ${method.toUpperCase()} ${template}`,\n })\n } else {\n return true\n }\n }\n return false\n }\n\n const obj: Record<string, unknown> = {}\n let anyBad = false\n for (const [prop, value] of collected) {\n const types = propTypes.get(prop)\n if (types) {\n const c = coerceScalar(value, types)\n if (!c.ok) {\n anyBad = true\n findings.push({\n kind: 'param-schema',\n severity: 'error',\n path: `${name}[${prop}]`,\n // Echo only the RAW captured value (redaction).\n message: `${param.in} parameter '${name}[${prop}]' value '${value}' is not a valid ${types.filter((t) => t !== 'null').join('|')}`,\n })\n } else {\n obj[prop] = c.value\n }\n } else {\n obj[prop] = value // undeclared — ajv decides per additionalProperties\n }\n }\n if (anyBad) return false\n const { valid, errors } = validateSchema(normSchema, obj)\n if (!valid) {\n for (const err of errors) {\n findings.push({\n kind: 'param-schema',\n severity: 'error',\n path: name,\n message: `${param.in} parameter '${name}' ${err.message}`,\n })\n }\n }\n return false\n}\n\n/**\n * Resolve a LOCAL in-document `$ref` (`#/components/{requestBodies,parameters,…}/*`)\n * one level. A non-`#/`-local `$ref` (external file / remote) returns `undefined` →\n * the caller treats it as inconclusive-skip (never fabricates a finding). A node\n * without a `$ref` is returned as-is.\n */\nfunction derefLocalComponent<T>(spec: OpenApiDoc, node: unknown): T | undefined {\n if (!node || typeof node !== 'object') return node as T\n const ref = (node as { $ref?: unknown }).$ref\n if (typeof ref !== 'string') return node as T\n if (!ref.startsWith('#/')) return undefined // external/remote — out of v1 scope\n let cur: unknown = spec\n for (const raw of ref.slice(2).split('/')) {\n const key = raw.replace(/~1/g, '/').replace(/~0/g, '~')\n if (!cur || typeof cur !== 'object') return undefined\n cur = (cur as Record<string, unknown>)[key]\n }\n return cur as T\n}\n\ntype ContentMap = Record<string, { schema?: unknown; encoding?: unknown }>\n\n/** `'urlencoded'`/`'multipart'` for the two form media bases, else `undefined`. Form\n * bodies are validated by reconstructing the field map (ADR 0016 addendum 4). */\nfunction formBase(mb: string): 'urlencoded' | 'multipart' | undefined {\n if (mb === 'application/x-www-form-urlencoded') return 'urlencoded'\n if (mb === 'multipart/form-data') return 'multipart'\n return undefined\n}\n\ntype SelectedContent =\n | { matched: true; schema: unknown; json: boolean; mediaBase: string; encoding: unknown }\n | { matched: false }\n\n/**\n * Select the declared request-body schema for a concrete Content-Type. When a CT is\n * present, match the spec's `content` keys by specificity: exact `type/subtype`, then\n * the subtype range, then the catch-all range. When the CT is ABSENT (the capture\n * path), fall back to a JSON-family key (the bridge only resolves JSON bodies) — and\n * `matched:false` there must NEVER become `unsupported-media-type` (C1). Also surfaces\n * the matched media base + its `encoding` object (form-body validation refuses any\n * per-property encoding — addendum 4).\n */\nfunction selectContentSchema(\n content: ContentMap | undefined,\n ct: string | undefined,\n): SelectedContent {\n if (!content) return { matched: false }\n const keys = Object.keys(content)\n if (ct) {\n const type = ct.split('/')[0] ?? ''\n const key =\n keys.find((k) => mediaBase(k) === ct) ??\n keys.find((k) => mediaBase(k) === `${type}/*`) ??\n keys.find((k) => mediaBase(k) === '*/*')\n if (!key) return { matched: false }\n return {\n matched: true,\n schema: content[key]?.schema,\n json: isJsonMediaType(key),\n mediaBase: mediaBase(key),\n encoding: content[key]?.encoding,\n }\n }\n const jsonKey = keys.find(isJsonMediaType)\n if (!jsonKey) return { matched: false }\n return {\n matched: true,\n schema: content[jsonKey]?.schema,\n json: true,\n mediaBase: 'application/json',\n encoding: content[jsonKey]?.encoding,\n }\n}\n\n/** A declared scalar/array form-body property after classification. */\ntype FormPropPlan =\n | { kind: 'scalar'; types: string[] }\n | { kind: 'array'; itemTypes: string[]; hasCard: boolean }\n\n/** UTF-8 / ASCII charsets we can soundly assume the bytes→string decode preserved. */\nconst SOUND_CHARSETS = new Set(['utf-8', 'utf8', 'us-ascii', 'ascii'])\n\n/**\n * Validate a `form`-style request body (`application/x-www-form-urlencoded` or the text\n * parts of `multipart/form-data`) against its declared object schema, reconstructing\n * typed values from the DISCRETE field map (`req.form`; repeated keys → array). Discrete\n * keys make even STRING array items sound (no delimiter to over-split) — form bodies are\n * more tractable than form *params*. Mirrors `validateObjectParam`'s coerce-then-ajv\n * logic. Declared scalar props are coerced to the declared type; sound scalar-item array\n * props are assembled from repeated keys; undeclared keys pass through as raw strings\n * (ajv then enforces `additionalProperties`); the assembled object is ajv-validated.\n *\n * Returns whether the body was `unverified`-skipped. REFUSE → unverified (never a false\n * finding) when reconstruction can't be sound: ANY per-property `encoding`; a non-UTF-8\n * charset; the schema isn't a flat object with `properties`; an object-form (typed)\n * `additionalProperties`; a non-scalar / typeless property, or an array property with\n * non-scalar items; a fractional `multipleOf` (float trap); a declared property satisfied\n * by a multipart FILE part; a scalar property arriving with repeated keys; a single-\n * occurrence array property carrying a cardinality constraint; an ambiguous empty value\n * for a non-string, non-null scalar property; or — when the caller is NOT authoritative —\n * any required field absent from the captured map.\n */\nfunction validateFormBody(\n normSchema: Record<string, unknown>,\n encoding: unknown,\n req: RequestFacts,\n opts: OpenApiRequestValidateOptions,\n findings: ContractFinding[],\n): boolean {\n // Per-property `encoding` re-introduces the full style/explode ambiguity matrix inside\n // the body (delimited / JSON-encoded properties) — v1 permanently-out.\n if (encoding !== undefined && encoding !== null) return true\n // A non-UTF-8 declared charset means the bytes→string decode may already be wrong.\n const rawCt = req.headers?.['content-type']\n if (rawCt) {\n const m = /;\\s*charset=([^;]+)/i.exec(rawCt)\n if (m?.[1] && !SOUND_CHARSETS.has(m[1].trim().toLowerCase())) return true\n }\n\n const props = normSchema.properties\n if (!props || typeof props !== 'object' || Array.isArray(props)) return true\n const propEntries = Object.entries(props as Record<string, unknown>)\n if (propEntries.length === 0) return true\n // Only a literal true/false/absent `additionalProperties` is reasoned about; a typed\n // one would false-fail an undeclared key we leave uncoerced.\n const ap = normSchema.additionalProperties\n if (ap !== undefined && typeof ap !== 'boolean') return true\n\n const plan = new Map<string, FormPropPlan>()\n for (const [name, sub] of propEntries) {\n if (!sub || typeof sub !== 'object' || Array.isArray(sub)) return true\n const s = sub as Record<string, unknown>\n const st = scalarTypes(s)\n if (st) {\n if (hasFractionalMultipleOf(s)) return true\n plan.set(name, { kind: 'scalar', types: st })\n continue\n }\n const nst = nonScalarType(s)\n if (nst === 'array') {\n const items = s.items\n if (!items || typeof items !== 'object' || Array.isArray(items)) return true\n const it = scalarTypes(items as Record<string, unknown>)\n if (!it || hasFractionalMultipleOf(items as Record<string, unknown>)) return true\n plan.set(name, { kind: 'array', itemTypes: it, hasCard: hasCardinalityConstraint(s) })\n continue\n }\n return true // nested object / array-of-object / typeless property\n }\n\n const form = (req.form ?? {}) as Record<string, string | string[]>\n const fileFields = new Set(req.formFileFields ?? [])\n // A declared property satisfied by a multipart file part can't be schema-checked.\n for (const name of plan.keys()) if (fileFields.has(name)) return true\n\n const required = Array.isArray(normSchema.required) ? (normSchema.required as string[]) : []\n // Non-authoritative source: a required field absent from the captured map can't be\n // distinguished from a dropped field → unverified (absence is never a finding here).\n if (!opts.bodyPresenceAuthoritative) {\n for (const rq of required) if (form[rq] === undefined) return true\n }\n\n const obj: Record<string, unknown> = {}\n let anyBad = false\n for (const [name, p] of plan) {\n const raw = form[name]\n if (raw === undefined) continue // absent: ajv enforces `required` (authoritative path)\n if (p.kind === 'scalar') {\n if (Array.isArray(raw)) return true // scalar prop arriving as repeated keys (array)\n // `field=` can't be told apart from null / valueless-key; only string/null absorb it.\n if (raw === '' && !p.types.includes('string') && !p.types.includes('null')) return true\n const c = coerceScalar(raw, p.types)\n if (!c.ok) {\n anyBad = true\n findings.push({\n kind: 'request-body-schema',\n severity: 'error',\n path: name,\n // Echo only the RAW field value (redaction); never the coerced value.\n message: `request body field '${name}' value '${raw}' is not a valid ${p.types.filter((t) => t !== 'null').join('|')}`,\n })\n } else obj[name] = c.value\n } else {\n const occ = Array.isArray(raw) ? raw : [raw]\n // A single occurrence can't prove a count bound (it might be an explode-disagreement).\n if (occ.length === 1 && p.hasCard) return true\n const arr: unknown[] = []\n for (const el of occ) {\n if (el === '' && !p.itemTypes.includes('string') && !p.itemTypes.includes('null')) {\n return true // ambiguous empty element\n }\n const c = coerceScalar(el, p.itemTypes)\n if (!c.ok) {\n anyBad = true\n findings.push({\n kind: 'request-body-schema',\n severity: 'error',\n path: name,\n message: `request body field '${name}' value '${el}' is not a valid ${p.itemTypes.filter((t) => t !== 'null').join('|')}`,\n })\n } else arr.push(c.value)\n }\n if (!anyBad) obj[name] = arr\n }\n }\n // Undeclared fields pass through raw (ajv enforces `additionalProperties`); file parts\n // are never schema-checked, so they don't enter the assembled object.\n for (const [key, val] of Object.entries(form)) {\n if (plan.has(key) || fileFields.has(key)) continue\n obj[key] = val\n }\n if (anyBad) return false // a value-level finding was raised; don't double-report via ajv\n\n const { valid, errors } = validateSchema(normSchema, obj)\n if (!valid) {\n for (const err of errors) {\n findings.push({\n kind: 'request-body-schema',\n severity: 'error',\n ...(err.instancePath ? { path: err.instancePath } : {}),\n message: err.message,\n })\n }\n }\n return false\n}\n\nexport function validateOpenApiRequest(\n spec: OpenApiDoc,\n req: RequestFacts,\n opts: OpenApiRequestValidateOptions = {},\n): RequestValidationResult {\n const findings: ContractFinding[] = []\n let unverified = false\n const method = req.method.toLowerCase()\n\n const resolved = resolveOpenApiOperation(spec, method, req.path)\n if (!resolved) {\n findings.push({\n kind: 'missing-operation',\n severity: 'error',\n message: `no operation ${req.method.toUpperCase()} ${req.path} in the OpenAPI document`,\n })\n return { valid: false, findings }\n }\n const { operation, template } = resolved\n const op = { method, path: template }\n\n // --- requestBody ---\n const requestBodyRaw = operation.requestBody\n const requestBodyDeclared = requestBodyRaw !== undefined\n const requestBody = derefLocalComponent<RequestBodyObject>(spec, requestBodyRaw)\n const hasBody = req.body !== undefined || req.form !== undefined\n const reqCt = req.headers?.['content-type'] ? mediaBase(req.headers['content-type']) : undefined\n\n if (requestBodyDeclared && (!requestBody || typeof requestBody !== 'object')) {\n // requestBody is a non-local `$ref` we cannot resolve — never fabricate\n // `undocumented-body` (the body IS expected); just mark it unverifiable (C5).\n unverified = true\n } else if (requestBody && typeof requestBody === 'object') {\n if (!hasBody) {\n // A required body that is absent: a breach ONLY if the caller is authoritative\n // about presence; otherwise unverifiable (capture can't tell \"no body\" from\n // \"dropped a non-JSON body\"). A non-required absent body is simply fine.\n if (requestBody.required === true) {\n if (opts.bodyPresenceAuthoritative) {\n findings.push({\n kind: 'missing-required-body',\n severity: 'error',\n message: `required request body missing for ${method.toUpperCase()} ${template}`,\n })\n } else {\n unverified = true\n }\n }\n } else {\n const sel = selectContentSchema(requestBody.content as ContentMap | undefined, reqCt)\n if (!sel.matched) {\n if (reqCt) {\n // A Content-Type IS present but no declared media type matches it.\n findings.push({\n kind: 'unsupported-media-type',\n severity: 'warning',\n message: `content-type '${reqCt}' is not declared for ${method.toUpperCase()} ${template}`,\n })\n }\n // CT-absent + no JSON content key ⇒ unverified only, NEVER unsupported-media-type (C1).\n unverified = true\n } else if (formBase(sel.mediaBase) && req.form !== undefined && sel.schema !== undefined) {\n // A `form`-style body with a structured field map (addendum 4): reconstruct +\n // validate the fields; any unsound case folds to `unverified`.\n const normSchema = normalizeOpenApiSchema(sel.schema, spec, opts)\n if (validateFormBody(normSchema, sel.encoding, req, opts, findings)) unverified = true\n } else if (!sel.json || sel.schema === undefined) {\n // Matched a non-JSON media type (or a media type with no schema) — presence-only\n // for non-form, non-JSON bodies (e.g. a form body with no structured field map).\n unverified = true\n } else {\n const compiled = normalizeOpenApiSchema(sel.schema, spec, opts)\n const { valid, errors } = validateSchema(compiled, req.body)\n if (!valid) {\n for (const err of errors) {\n findings.push({\n kind: 'request-body-schema',\n severity: 'error',\n path: err.instancePath,\n message: err.message,\n })\n }\n }\n }\n }\n } else if (hasBody) {\n // Body sent to an operation that declares no requestBody: a warning (often\n // client-side noise the server ignored), and the body was never schema-checked.\n findings.push({\n kind: 'undocumented-body',\n severity: 'warning',\n message: `request body sent to ${method.toUpperCase()} ${template} which declares no request body`,\n })\n unverified = true\n }\n\n // --- parameters (path / query / header; scalars + query form arrays in v1) ---\n const pathVals = extractPathParams(template, req.path)\n // Metadata for the undocumented-param pass, collected during the param loop:\n const declaredQuery = new Set<string>() // scalar + array query param names\n const deepObjectPrefixes: string[] = [] // `name[` keys belonging to a deepObject param\n // When set, the whole undoc pass is unsound (an object's properties share the\n // top-level query namespace) and is suppressed.\n let suppressUndoc = false\n // Deref `$ref` params first; a non-local ref we can't resolve ⇒ inconclusive-skip.\n const params: ParamObject[] = []\n for (const rp of mergeParameters(resolved.pathItem, operation)) {\n if (typeof rp.$ref === 'string') {\n const d = derefLocalComponent<ParamObject>(spec, rp)\n if (!d || typeof d.name !== 'string' || typeof d.in !== 'string') {\n unverified = true\n // The dropped param could be a query OBJECT whose properties land as\n // top-level keys; suppress the undoc pass rather than risk a false positive.\n suppressUndoc = true\n continue\n }\n params.push(d)\n } else if (typeof rp.name === 'string' && typeof rp.in === 'string') {\n params.push(rp)\n }\n // else malformed param object: ignore\n }\n\n for (const param of params) {\n if (typeof param.name !== 'string' || typeof param.in !== 'string') continue\n const normSchema =\n param.schema !== undefined ? normalizeOpenApiSchema(param.schema, spec, opts) : undefined\n const types = normSchema ? scalarTypes(normSchema) : undefined\n const nonScalar = normSchema ? nonScalarType(normSchema) : undefined\n\n // Record query-param presence for the undoc pass BEFORE any validation skip, so a\n // STAGED object param still suppresses/excludes its keys (its properties are on the\n // wire regardless of whether we validate the object).\n if (param.in === 'query') {\n if (nonScalar === 'object') {\n // EXPLICIT explode test: query object explode DEFAULTS to true (shared namespace).\n if (param.style === 'deepObject') deepObjectPrefixes.push(`${param.name}[`)\n else if ((param.style === undefined || param.style === 'form') && param.explode === false)\n declaredQuery.add(param.name) // form/explode=false: serialized under one key\n else suppressUndoc = true // form/explode=true → shared top-level namespace\n } else {\n declaredQuery.add(param.name) // scalar + array params (the array key == its name)\n }\n }\n\n // Unsupported location / serialization / content-typed param → STAGED skip.\n if (!styleSupported(param, normSchema)) {\n unverified = true\n continue\n }\n if (!normSchema || (!types && nonScalar === undefined)) {\n // No schema, or a truly typeless param → STAGED skip. (Arrays/objects have no\n // scalar `types` but are handled below.)\n unverified = true\n continue\n }\n\n // Object param (query deepObject or form/explode=false) — its own presence logic\n // (deepObject has no `name` key; form/explode=false is under the single `name`).\n if (nonScalar === 'object' && normSchema) {\n if (validateObjectParam(param, normSchema, req, opts, method, template, findings)) {\n unverified = true\n }\n continue\n }\n\n const lk = lookupParamValue(param, req, pathVals)\n if (lk.state === 'absent') {\n const required = param.in === 'path' || param.required === true\n if (required) {\n if (opts.paramsAuthoritative) {\n findings.push({\n kind: 'missing-required-param',\n severity: 'error',\n path: param.name,\n message: `required ${param.in} parameter '${param.name}' missing for ${method.toUpperCase()} ${template}`,\n })\n } else {\n unverified = true\n }\n }\n continue\n }\n\n // Array param (query form/space/pipe-delimited, path/header simple).\n if (nonScalar === 'array' && normSchema) {\n if (validateArrayParam(param, normSchema, lk, findings)) unverified = true\n continue\n }\n\n // Scalar path. A repeated/composite value for a SCALAR param can't be coerced —\n // fold to unverified (never fall through to coerce an absent `.value`).\n if (lk.state === 'multi' || lk.state === 'array-values' || !types) {\n unverified = true\n continue\n }\n // A fractional `multipleOf` is the IEEE-754 false-positive trap — can't soundly\n // coerce-and-ajv this number; skip rather than risk flagging a conformant value.\n if (hasFractionalMultipleOf(normSchema)) {\n unverified = true\n continue\n }\n\n // Present: coerce the raw string to the declared scalar type, then schema-check.\n const coerced = coerceScalar(lk.value, types)\n if (!coerced.ok) {\n const want = types.filter((t) => t !== 'null').join('|')\n findings.push({\n kind: 'param-schema',\n severity: 'error',\n path: param.name,\n // Echo the RAW captured substring, never the coerced value (redaction).\n message: `${param.in} parameter '${param.name}' value '${lk.value}' is not a valid ${want}`,\n })\n continue\n }\n const { valid, errors } = validateSchema(normSchema, coerced.value)\n if (!valid) {\n for (const err of errors) {\n findings.push({\n kind: 'param-schema',\n severity: 'error',\n path: param.name,\n message: `${param.in} parameter '${param.name}' ${err.message}`,\n })\n }\n }\n }\n\n // Undocumented QUERY params (headers excluded — infra/trace headers saturate\n // captures). Suppressed entirely when an object query param shares the top-level\n // namespace (or an unresolved $ref param might). A deepObject's `name[prop]` keys\n // are excluded (bracket namespace), and a declared-but-skipped param is still\n // DECLARED (its name is in `declaredQuery`), so neither is flagged.\n if (req.query && !suppressUndoc) {\n for (const key of Object.keys(req.query)) {\n if (declaredQuery.has(key)) continue\n if (deepObjectPrefixes.some((p) => key.startsWith(p))) continue\n findings.push({\n kind: 'undocumented-param',\n severity: 'warning',\n path: key,\n message: `undocumented query parameter '${key}' for ${method.toUpperCase()} ${template}`,\n })\n }\n }\n\n return {\n valid: findings.every((f) => f.severity !== 'error'),\n findings,\n operation: op,\n ...(unverified ? { unverified: true } : {}),\n }\n}\n","/**\n * The capture→contract bridge (ADR 0013, Phase-5 milestone 5a). Turns a stored\n * browser/API HAR into the records the *already-shipped* OpenAPI response\n * validator consumes — **no request is re-run**; this is a read over an existing\n * artifact. The high-leverage cross-pillar win: a captured run's traffic is\n * checked against the operator-supplied contract for the installed API version.\n *\n * Security posture (ADR 0013 §3): a HAR is operator-gated bytes whose redaction\n * is known-incomplete, so the *surface* gates resolving one (`validate_capture`,\n * slice 6). Here, the pure bridge MUST NOT copy raw headers/cookies into its\n * output (only status + the parsed body needed for schema validation) and every\n * finding message is routed through the operator `Redactor` before it leaves.\n */\nimport { strFromU8, unzipSync } from 'fflate'\nimport { type ResponseFacts, validateOpenApiResponse } from './contract.js'\nimport { validateGraphqlOperation } from './graphql.js'\nimport type { ContractFinding, ContractResult } from './model.js'\nimport { validateOpenApiRequest } from './request-contract.js'\n\n/** fflate is unbounded by default; cap the inflated HAR archive (ADR 0013 §3e). */\nconst MAX_HAR_INFLATED_BYTES = 64 * 1024 * 1024\n\n/** A captured HTTP exchange reduced to the facts the validator needs. */\nexport interface CaptureEntry {\n req: {\n method: string\n path: string\n origin: string\n /**\n * The parsed JSON request body, when the request carried a JSON `postData`\n * (attach `_file` first, inline `text` fallback). Needed for GraphQL drift:\n * the operation `query` lives in the request, not the response (ADR 0013 §5).\n */\n body?: unknown\n /** Decoded request query params (repeated keys → array). Captured for\n * request-side contract validation (slice 4a); only set when non-empty. */\n query?: Record<string, string | string[]>\n /** Lower-cased request header names → value (last wins). Only set when present. */\n headers?: Record<string, string>\n /** Decoded TEXT fields of a `form`-style request body (form-urlencoded /\n * multipart text parts) from HAR `postData.params[]` (repeated keys → array;\n * urlencoded `text` fallback). The authoritative-source rule still holds: the\n * capture path drives the validator NON-authoritatively (ADR 0016 addendum 4). */\n form?: Record<string, string | string[]>\n /** NAMES of multipart FILE parts (a `postData.params` entry with `fileName`);\n * bytes never enter the facts. */\n formFileFields?: string[]\n }\n res: ResponseFacts\n /** Lower-cased response content-type (sans parameters), e.g. `application/json`. */\n mimeType: string\n /**\n * Set when an attached body referenced by `_file` could not be resolved or\n * JSON-parsed — surfaced as a HARD finding by the driver, never an empty-body\n * pass (ADR 0013 slice 2).\n */\n unresolvedBody?: string\n}\n\ninterface HarContent {\n mimeType?: string\n text?: string\n _file?: string\n encoding?: string\n /** Structured form fields (HAR `postData.params`): `{name, value?, fileName?}`. A\n * `fileName` marks a FILE part (bytes never inlined). */\n params?: { name?: string; value?: string; fileName?: string }[]\n}\n\ninterface HarEntry {\n request?: {\n method?: string\n url?: string\n postData?: HarContent\n headers?: { name?: string; value?: string }[]\n }\n response?: {\n status?: number\n content?: HarContent\n }\n}\n\n/** Build a decoded query record from a URL's search params (repeated keys → array). */\nfunction collectQuery(sp: URLSearchParams): Record<string, string | string[]> {\n const out: Record<string, string | string[]> = {}\n for (const key of new Set(sp.keys())) {\n const all = sp.getAll(key)\n out[key] = all.length > 1 ? all : (all[0] ?? '')\n }\n return out\n}\n\n/** Lower-cased request header map (last value wins) from the HAR header array. */\nfunction collectHeaders(\n hdrs: { name?: string; value?: string }[] | undefined,\n): Record<string, string> {\n const out: Record<string, string> = {}\n for (const h of hdrs ?? []) {\n if (typeof h?.name === 'string') out[h.name.toLowerCase()] = String(h.value ?? '')\n }\n return out\n}\n\nfunction findHarJson(zip: Record<string, Uint8Array>): string | undefined {\n const key = Object.keys(zip).find((k) => k.endsWith('.har'))\n return key ? strFromU8(zip[key] as Uint8Array) : undefined\n}\n\nfunction mimeOf(content: { mimeType?: string } | undefined): string {\n return (content?.mimeType ?? '').split(';')[0]?.trim().toLowerCase() ?? ''\n}\n\n/** `'urlencoded'`/`'multipart'` for the two form media bases, else `undefined`. */\nfunction formBaseOf(mime: string): 'urlencoded' | 'multipart' | undefined {\n if (mime === 'application/x-www-form-urlencoded') return 'urlencoded'\n if (mime === 'multipart/form-data') return 'multipart'\n return undefined\n}\n\n/** Append a field into a repeated-keys-→-array map (the form-field channel shape). */\nfunction appendFormField(\n map: Record<string, string | string[]>,\n name: string,\n value: string,\n): void {\n const cur = map[name]\n if (cur === undefined) map[name] = value\n else if (Array.isArray(cur)) cur.push(value)\n else map[name] = [cur, value]\n}\n\n/**\n * Resolve a `form`-style request `postData` into the structured field channel\n * `validateFormBody` consumes (ADR 0016 addendum 4 capture path). PREFER the\n * structured `params[]` (each `{name, value?, fileName?}`, already URL-decoded by\n * the capturer; a `fileName` marks a FILE part → names-only). For `urlencoded`\n * ONLY, fall back to parsing `postData.text` (well-defined percent-decoding). A\n * `multipart` body with no `params[]` (only raw `_file`/`text`) is NOT parsed —\n * boundary parsing reintroduces the embedded-delimiter trap — so `undefined` is\n * returned and the validator `unverified`-skips. Returns `undefined` when nothing\n * sound is extractable.\n */\nfunction formFieldsFromPostData(\n pd: HarContent,\n base: 'urlencoded' | 'multipart',\n): { form: Record<string, string | string[]>; fileFields: string[] } | undefined {\n const form: Record<string, string | string[]> = {}\n const fileFields: string[] = []\n if (Array.isArray(pd.params) && pd.params.length > 0) {\n for (const p of pd.params) {\n if (typeof p?.name !== 'string') continue\n if (typeof p.fileName === 'string')\n fileFields.push(p.name) // FILE part — name only\n else appendFormField(form, p.name, String(p.value ?? ''))\n }\n return { form, fileFields }\n }\n if (base === 'urlencoded' && typeof pd.text === 'string') {\n const sp = new URLSearchParams(pd.text)\n for (const key of new Set(sp.keys())) {\n const all = sp.getAll(key)\n form[key] = all.length > 1 ? all : (all[0] ?? '')\n }\n return { form, fileFields }\n }\n return undefined\n}\n\n/**\n * Slice 2 — parse a HAR `.zip` and resolve each entry's body. The PRIMARY path\n * is `content:'attach'` (the only mode the browser pillar emits): a body lives\n * in a separate archive entry referenced by `response.content._file`. Inline\n * `response.content.text` (`content:'embed'`) is the fallback. JSON bodies are\n * parsed; the URL is reduced to its `pathname` (+ origin kept separately).\n */\nexport function harEntriesToFacts(harZip: Buffer): CaptureEntry[] {\n const zip = unzipSync(new Uint8Array(harZip), {\n filter: (file) => file.originalSize <= MAX_HAR_INFLATED_BYTES,\n })\n const harText = findHarJson(zip)\n if (harText === undefined) throw new Error('har-capture: no .har entry in the archive')\n const log = (JSON.parse(harText) as { log?: { entries?: HarEntry[] } }).log\n const entries = log?.entries ?? []\n\n const out: CaptureEntry[] = []\n for (const e of entries) {\n const method = (e.request?.method ?? 'GET').toUpperCase()\n const rawUrl = e.request?.url ?? ''\n let path = rawUrl\n let origin = ''\n let query: Record<string, string | string[]> | undefined\n try {\n const u = new URL(rawUrl)\n path = u.pathname\n origin = u.origin\n const q = collectQuery(u.searchParams)\n if (Object.keys(q).length > 0) query = q\n } catch {\n // a relative/opaque url: keep it verbatim as the path\n }\n const headersMap = collectHeaders(e.request?.headers)\n const headers = Object.keys(headersMap).length > 0 ? headersMap : undefined\n const status = e.response?.status ?? 0\n const content = e.response?.content\n const mimeType = mimeOf(content)\n\n // Resolve the JSON request body (GraphQL's operation lives here). Attach\n // (`_file`) first, inline `text` fallback; parse only a JSON content-type.\n // A non-resolving/non-JSON request body just leaves `req.body` undefined —\n // the GraphQL router treats a missing query as a hard finding itself.\n const reqContent = e.request?.postData\n // Resolve a `form`-style request body into the structured field channel (ADR 0016\n // addendum 4 capture path); the validator drives it non-authoritatively.\n let reqForm: Record<string, string | string[]> | undefined\n let reqFormFiles: string[] | undefined\n const reqFormBase = reqContent ? formBaseOf(mimeOf(reqContent)) : undefined\n if (reqContent && reqFormBase) {\n const extracted = formFieldsFromPostData(reqContent, reqFormBase)\n if (extracted) {\n reqForm = extracted.form\n if (extracted.fileFields.length > 0) reqFormFiles = extracted.fileFields\n }\n }\n let reqBody: unknown\n if (reqContent && mimeOf(reqContent).includes('json')) {\n let rawReq: string | undefined\n if (reqContent._file) {\n const bytes = zip[reqContent._file]\n if (bytes) rawReq = strFromU8(bytes)\n } else if (typeof reqContent.text === 'string') {\n rawReq = reqContent.text\n }\n if (rawReq !== undefined && rawReq.length > 0) {\n try {\n reqBody = JSON.parse(rawReq)\n } catch {\n // unparseable request body: leave undefined (no GraphQL query extractable)\n }\n }\n }\n\n let body: unknown\n let unresolvedBody: string | undefined\n const isJson = mimeType.includes('json')\n\n // Resolve the body bytes: attach (_file) first, then inline text.\n let rawBody: string | undefined\n if (content?._file) {\n const bytes = zip[content._file]\n if (bytes) rawBody = strFromU8(bytes)\n else unresolvedBody = `attached body ${content._file} not found in the archive`\n } else if (typeof content?.text === 'string') {\n rawBody = content.text\n }\n\n if (unresolvedBody === undefined && isJson) {\n if (rawBody === undefined || rawBody.length === 0) {\n unresolvedBody = 'json response with no resolvable body'\n } else {\n try {\n body = JSON.parse(rawBody)\n } catch {\n unresolvedBody = 'json response body did not parse'\n }\n }\n } else if (!isJson) {\n body = rawBody\n }\n\n out.push({\n req: {\n method,\n path,\n origin,\n ...(reqBody !== undefined ? { body: reqBody } : {}),\n ...(query ? { query } : {}),\n ...(headers ? { headers } : {}),\n ...(reqForm ? { form: reqForm } : {}),\n ...(reqFormFiles ? { formFileFields: reqFormFiles } : {}),\n },\n res: { status, body },\n mimeType,\n ...(unresolvedBody ? { unresolvedBody } : {}),\n })\n }\n return out\n}\n\n/** Slice 3 — only JSON responses from allowed origins are routed to the validator. */\nexport interface CaptureFilterOptions {\n /** When set, only entries whose request origin is in this list are considered. */\n allowedOrigins?: string[]\n}\n\nfunction isApiEntry(entry: CaptureEntry, opts: CaptureFilterOptions): boolean {\n if (opts.allowedOrigins && entry.req.origin && !opts.allowedOrigins.includes(entry.req.origin)) {\n return false\n }\n // REST contract validation is JSON-only in v1; an unresolved JSON body is still\n // an API entry (so it surfaces as a hard finding rather than being filtered away).\n return entry.mimeType.includes('json')\n}\n\n/**\n * Slice 4 — strip the OpenAPI `servers[].url` base path so a captured\n * `/api/v1/widgets` matches the documented path `/widgets`. Returns the longest\n * matching server base path's remainder, or the original path when none match.\n */\nfunction serverBasePaths(spec: OpenApiSpec): string[] {\n const servers = Array.isArray(spec.servers) ? spec.servers : []\n const bases: string[] = []\n for (const s of servers) {\n const url = typeof s?.url === 'string' ? s.url : ''\n if (!url) continue\n let base = url\n try {\n base = new URL(url).pathname\n } catch {\n // a path-only server url (e.g. \"/api/v1\"): use as-is\n }\n base = base.replace(/\\/+$/, '')\n if (base && base !== '/') bases.push(base)\n }\n // longest first, so the most specific base path wins\n return bases.sort((a, b) => b.length - a.length)\n}\n\nfunction reconcileBasePath(path: string, bases: string[]): string {\n for (const base of bases) {\n if (path === base) return '/'\n if (path.startsWith(`${base}/`)) return path.slice(base.length)\n }\n return path\n}\n\ninterface OpenApiSpec {\n servers?: Array<{ url?: string }>\n paths?: Record<string, Record<string, unknown> | undefined>\n [key: string]: unknown\n}\n\n/** The GraphQL half of a capture contract (ADR 0013 §5 discriminated input). */\nexport interface GraphqlContract {\n /** The full request pathname that serves GraphQL, e.g. `/graphql`. */\n endpointPath: string\n /** The schema SDL captured operations are validated against (drift detection). */\n sdl: string\n}\n\n/**\n * The discriminated contract a captured run is validated against. Supply\n * `openapi` (REST), `graphql` (GraphQL), or both. A captured entry is routed to\n * exactly one validator; a GraphQL entry never falls through to the OpenAPI\n * validator (which would flood `missing-operation`), and an entry with no\n * matching contract half is **no-signal**, never a pass (ADR 0013 §1/§5).\n */\nexport interface CaptureContract {\n openapi?: OpenApiSpec\n graphql?: GraphqlContract\n}\n\n/**\n * Extract the GraphQL operation from a captured request body. The GraphQL-over-\n * HTTP shape is a JSON object with a string `query` (and optional `operationName`\n * and `variables`). Returns `undefined` for a non-GraphQL body.\n */\nfunction graphqlOperationOf(\n entry: CaptureEntry,\n): { query: string; operationName?: string; variables?: unknown } | undefined {\n const b = entry.req.body\n if (b && typeof b === 'object' && typeof (b as { query?: unknown }).query === 'string') {\n const opName = (b as { operationName?: unknown }).operationName\n const variables = (b as { variables?: unknown }).variables\n return {\n query: (b as { query: string }).query,\n ...(typeof opName === 'string' ? { operationName: opName } : {}),\n ...(variables !== undefined ? { variables } : {}),\n }\n }\n return undefined\n}\n\nconst HTTP_METHODS = ['get', 'put', 'post', 'delete', 'patch', 'options', 'head', 'trace']\n\n/** Every documented operation as `METHOD /template` — the universe for the drift walk. */\nfunction documentedOperations(spec: OpenApiSpec): string[] {\n const ops: string[] = []\n for (const [template, item] of Object.entries(spec.paths ?? {})) {\n if (!item) continue\n for (const method of HTTP_METHODS) {\n if (method in item) ops.push(`${method.toUpperCase()} ${template}`)\n }\n }\n return ops\n}\n\n/** The rolled-up contract sub-verdict over a captured run (ADR 0013 §1/§5). */\nexport interface CaptureContractVerdict {\n /** Entries actually routed to the validator (JSON, allowed origin). */\n entriesValidated: number\n /** Per-`ContractFindingKind` finding counts across all entries (+ `unresolved-body`). */\n findingsByKind: Record<string, number>\n /** The first entry that failed validation, for a fast headline. */\n firstFailing?: { method: string; path: string; kind: string; message: string }\n /** `METHOD /template` for every documented op an entry exercised — the inverse-of-drift signal. */\n exercisedOperations: string[]\n /** Documented ops NO captured entry hit. */\n unexercisedOperations: string[]\n /** Per-entry validator results (finding messages already redacted). */\n results: ContractResult[]\n /** Entries whose attached body could not be resolved/parsed (never a pass). */\n unresolvedBodies: number\n /**\n * Entries we could NOT verify because no matching contract half was supplied —\n * a GraphQL call with no SDL (`graphql-sdl-not-supplied`), or a REST call with\n * no OpenAPI spec (`no-contract-for-entry`). Counted, never a pass (ADR 0013 §1).\n */\n noSignal: number\n /**\n * `true` only when at least one entry was validated, every result is valid, no\n * body was unresolved, AND no entry was no-signal. Absence is never a pass\n * (ADR 0013 §1) — an unverifiable GraphQL/REST call can't make a run clean.\n */\n clean: boolean\n}\n\nexport interface ValidateCaptureOptions extends CaptureFilterOptions {\n /** Redacts finding messages before they leave the bridge (ADR 0013 §3b). */\n redact?: (value: string) => string\n /** Spec dir for external local-file `$ref` resolution (passed to the validator). */\n baseDir?: string\n}\n\n/**\n * Slice 5 (+ ADR 0013 §5 GraphQL) — drive each captured JSON entry through the\n * matching shipped validator. A GraphQL entry (matched by the contract's\n * `endpointPath` or the JSON `{query}` shape) goes to `validateGraphqlOperation`\n * and NEVER to the OpenAPI validator; a REST entry goes to\n * `validateOpenApiResponse` and feeds the exercised/unexercised drift walk. An\n * entry with no matching contract half is no-signal (never a pass). Every finding\n * message is routed through the operator `Redactor`; our own summary paths use the\n * matched operation template / operator-supplied endpoint, never a raw captured path.\n */\nexport function validateCapturedTraffic(\n harZip: Buffer,\n contract: CaptureContract,\n opts: ValidateCaptureOptions = {},\n): CaptureContractVerdict {\n const redact = opts.redact ?? ((v: string) => v)\n const { openapi: spec, graphql } = contract\n const bases = spec ? serverBasePaths(spec) : []\n const entries = harEntriesToFacts(harZip).filter((e) => isApiEntry(e, opts))\n\n const results: ContractResult[] = []\n const findingsByKind: Record<string, number> = {}\n const exercised = new Set<string>()\n let firstFailing: CaptureContractVerdict['firstFailing']\n let unresolvedBodies = 0\n let noSignal = 0\n\n const bump = (kind: string) => {\n findingsByKind[kind] = (findingsByKind[kind] ?? 0) + 1\n }\n const pushResult = (entry: CaptureEntry, raw: ContractResult, displayPath: string) => {\n // Redact every finding message AND path before it enters the verdict (ADR 0013\n // §3b; the path-redaction widening was human-ratified — request bodies/params are\n // secret-bearing, so `path` can carry a captured key name; cheap, one chokepoint).\n const redactedFindings: ContractFinding[] = raw.findings.map((f) => ({\n ...f,\n message: redact(f.message),\n ...(f.path !== undefined ? { path: redact(f.path) } : {}),\n }))\n const result: ContractResult = { ...raw, findings: redactedFindings }\n results.push(result)\n for (const f of redactedFindings) bump(f.kind)\n if (!result.valid && !firstFailing) {\n const f = redactedFindings.find((x) => x.severity === 'error') ?? redactedFindings[0]\n firstFailing = {\n method: entry.req.method,\n path: displayPath,\n kind: f?.kind ?? 'unknown',\n message: f?.message ?? '',\n }\n }\n return result\n }\n\n for (const entry of entries) {\n if (entry.unresolvedBody) {\n unresolvedBodies++\n bump('unresolved-body')\n firstFailing ??= {\n method: entry.req.method,\n path: redact(reconcileBasePath(entry.req.path, bases)),\n kind: 'unresolved-body',\n message: redact(entry.unresolvedBody),\n }\n continue\n }\n\n // GraphQL detection: the operator-supplied endpoint path, or the JSON\n // `{query}` request shape. Either way it is a GraphQL call, not a REST one.\n const op = graphqlOperationOf(entry)\n const isGraphql = (graphql !== undefined && entry.req.path === graphql.endpointPath) || !!op\n if (isGraphql) {\n if (!graphql) {\n // Detected GraphQL but no SDL supplied: no-signal, NEVER an OpenAPI\n // fall-through (which would flood `missing-operation`). ADR 0013 §5.\n noSignal++\n bump('graphql-sdl-not-supplied')\n continue\n }\n if (!op) {\n // Matched the GraphQL endpoint but no `query` could be extracted from the\n // request — a hard finding, never an empty pass.\n pushResult(\n entry,\n {\n valid: false,\n findings: [\n {\n kind: 'graphql-no-query',\n severity: 'error',\n message: 'no GraphQL query found in the captured request body',\n },\n ],\n },\n redact(graphql.endpointPath),\n )\n continue\n }\n // The capture path is NOT authoritative about variable completeness (a HAR may\n // have dropped `variables`), so `variablesAuthoritative` is omitted — an absent\n // required variable surfaces as `unverified`, never a false finding (ADR 0015).\n const raw = validateGraphqlOperation(graphql.sdl, op.query, {\n json: entry.res.body,\n operationName: op.operationName,\n ...(op.variables !== undefined ? { variables: op.variables } : {}),\n })\n pushResult(entry, raw, redact(graphql.endpointPath))\n // A present-but-uncheckable variable set is `unverified` — fold into `noSignal`\n // (out-of-band, NOT a finding) so it can never be laundered into a clean pass\n // (absence-is-never-a-pass; mirrors the REST `request-unverified` fold).\n if (raw.unverified) {\n noSignal++\n // A custom-scalar directive-arg literal (ADR 0018 D2) gets the distinct summary key\n // so it is not mislabeled as an unverifiable variable (ADR 0018 §8.4).\n bump(\n raw.directiveUnverified ? 'graphql-directive-unverified' : 'graphql-variable-unverified',\n )\n }\n continue\n }\n\n // REST: requires an OpenAPI contract. Without one, the call is unverifiable.\n if (!spec) {\n noSignal++\n bump('no-contract-for-entry')\n continue\n }\n const reqPath = reconcileBasePath(entry.req.path, bases)\n const typedSpec = spec as Parameters<typeof validateOpenApiResponse>[0]\n const resRaw = validateOpenApiResponse(\n typedSpec,\n { method: entry.req.method, path: reqPath },\n entry.res,\n { baseDir: opts.baseDir },\n )\n // Drive REQUEST-side validation over the same entry. The capture path is NOT\n // authoritative about body presence or param completeness (it cannot tell \"no\n // body\" from a dropped non-JSON body, and may not have captured every param), so\n // both authority flags are OMITTED — a required-but-absent body/param surfaces as\n // `unverified`, never a false `missing-*` finding.\n const reqRaw = validateOpenApiRequest(\n typedSpec,\n {\n method: entry.req.method,\n path: reqPath,\n body: entry.req.body,\n query: entry.req.query,\n headers: entry.req.headers,\n form: entry.req.form,\n formFileFields: entry.req.formFileFields,\n },\n { baseDir: opts.baseDir },\n )\n // Merge into one ContractResult before the single redaction chokepoint. Drop the\n // request side's `missing-operation` (the response side reports it once).\n const merged: ContractResult = {\n valid: resRaw.valid && reqRaw.valid,\n findings: [\n ...resRaw.findings,\n ...reqRaw.findings.filter((f) => f.kind !== 'missing-operation'),\n ],\n ...((resRaw.operation ?? reqRaw.operation)\n ? { operation: resRaw.operation ?? reqRaw.operation }\n : {}),\n }\n // A matched operation template is operator-authored (safe); a raw captured\n // path is not — redact it (§3b: never echo an unredacted captured path).\n const result = pushResult(entry, merged, merged.operation?.path ?? redact(reqPath))\n if (result.operation)\n exercised.add(`${result.operation.method.toUpperCase()} ${result.operation.path}`)\n // A present-but-uncheckable body / uncapturable required param is `unverified` —\n // fold it into `noSignal` (out-of-band, NOT a finding in `results[]`, so it never\n // double-counts as a warning) so it can never be laundered into a clean pass\n // (absence-is-never-a-pass; closes the leak the design's critic proved).\n if (reqRaw.unverified) {\n noSignal++\n bump('request-unverified')\n }\n }\n\n const documented = spec ? documentedOperations(spec) : []\n const exercisedOperations = [...exercised].sort()\n const unexercisedOperations = documented.filter((op) => !exercised.has(op)).sort()\n\n const clean =\n entries.length > 0 && unresolvedBodies === 0 && noSignal === 0 && results.every((r) => r.valid)\n\n return {\n entriesValidated: entries.length,\n findingsByKind,\n firstFailing,\n exercisedOperations,\n unexercisedOperations,\n results,\n unresolvedBodies,\n noSignal,\n clean,\n }\n}\n","/**\n * HAR synthesis + redaction for the API pillar (ADR 0013 Addendum 4, milestone 5f).\n * Lets `verify` PRODUCE a HAR from the `@sackville-mcp/api` runner (not just the browser\n * pillar's live capture), then validate it against the contract via the SHIPPED\n * {@link validateCapturedTraffic} — full REST + GraphQL parity.\n *\n * This module is a PURE leaf: it imports ONLY `fflate` (no runner/undici/spawn-capable\n * code), so the new `@sackville-mcp/browser → @sackville-mcp/api` dep edge it creates (browser's\n * `finalizeHar` delegates its Buffer→Buffer transform here) cannot drag heavy code into\n * the browser pillar, and the gate suite exercises synthesis with no network.\n *\n * Security posture (ADR 0013 §3): a synthesized HAR carries the REAL request/response\n * bodies + urls. {@link redactHarZip} is the blanket-redaction pass (lifted from the\n * browser pillar's `finalizeHar` core, shared so the 5e attach-mimeType fix is inherited),\n * and {@link synthesizeRedactedHarZip} folds it in so NO un-redacted buffer is ever\n * returned. The redactor MUST carry the run-resolved `{{secret:NAME}}` values.\n */\nimport { strFromU8, strToU8, unzipSync, zipSync } from 'fflate'\n\n/** fflate is unbounded by default; cap the inflated HAR archive (ADR 0013 §3e). */\nconst MAX_HAR_INFLATED_BYTES = 64 * 1024 * 1024\n\n// Text entries in a HAR `.zip` where a secret can land: the `.har` JSON itself\n// (urls/headers/query/postData) and any persisted text resource bodies. Binary\n// resources pass through untouched. Entries are content-addressed but referenced by\n// name, so redacting their bytes in place is safe — the HAR still resolves them by name.\nconst HAR_TEXT_ENTRY = /\\.(har|json|txt|html|htm|css|js|xml|svg)$/\n\n// A body's DECLARED mimeType is text-like (so its bytes may carry a secret as text and\n// must be redacted), even when its content-addressed attach filename has no text\n// extension. Inclusive on purpose — a genuinely binary type is excluded so it passes\n// through byte-for-byte. Mirrors `@sackville-mcp/browser` `har.ts` (one redaction posture).\nconst TEXT_MIME = /^text\\/|(?:json|xml|javascript|ecmascript|graphql|html|urlencoded|csv|yaml)/i\n\n/**\n * In `content:'attach'` mode a body lives in a SEPARATE archive entry whose name is\n * content-addressed — frequently WITHOUT a text extension — so {@link HAR_TEXT_ENTRY}\n * (a filename gate) would pass a JSON/GraphQL body through unredacted. Walk the `.har`\n * JSON and collect the `_file` names of every body whose DECLARED mimeType is text-like,\n * so they are redacted by type, not by extension.\n */\nfunction textAttachFiles(harJson: string): Set<string> {\n const files = new Set<string>()\n let entries: unknown[] = []\n try {\n const log = (JSON.parse(harJson) as { log?: { entries?: unknown[] } }).log\n if (Array.isArray(log?.entries)) entries = log.entries\n } catch {\n return files\n }\n const consider = (part: { mimeType?: unknown; _file?: unknown } | undefined) => {\n if (\n part &&\n typeof part._file === 'string' &&\n typeof part.mimeType === 'string' &&\n TEXT_MIME.test(part.mimeType)\n ) {\n files.add(part._file)\n }\n }\n for (const e of entries as {\n request?: { postData?: { mimeType?: unknown; _file?: unknown } }\n response?: { content?: { mimeType?: unknown; _file?: unknown } }\n }[]) {\n consider(e?.request?.postData)\n consider(e?.response?.content)\n }\n return files\n}\n\n/** Compact tallies over a parsed HAR; tolerant of a malformed/empty log. */\nexport interface HarCounts {\n entryCount: number\n byStatus: Record<string, number>\n byMethod: Record<string, number>\n}\n\n/** Parse the `.har` JSON into compact tallies; tolerant of a malformed/empty log. */\nexport function summarizeHar(harJson: string): HarCounts {\n const byStatus: Record<string, number> = {}\n const byMethod: Record<string, number> = {}\n let entries: unknown[] = []\n try {\n const log = (JSON.parse(harJson) as { log?: { entries?: unknown[] } }).log\n if (Array.isArray(log?.entries)) entries = log.entries\n } catch {\n return { entryCount: 0, byStatus, byMethod }\n }\n for (const e of entries as {\n request?: { method?: unknown }\n response?: { status?: unknown }\n }[]) {\n const status = e?.response?.status\n if (typeof status === 'number') byStatus[String(status)] = (byStatus[String(status)] ?? 0) + 1\n const method = e?.request?.method\n if (typeof method === 'string') byMethod[method] = (byMethod[method] ?? 0) + 1\n }\n return { entryCount: entries.length, byStatus, byMethod }\n}\n\n/**\n * The blanket-redaction pass over a HAR `.zip` Buffer (PURE — no file I/O). Unzips,\n * collects the text-like attach `_file` bodies by DECLARED mimeType (so a body stored\n * under a non-text filename is still scrubbed), redacts every text member — the `.har`\n * JSON + text-extension bodies + those attach bodies — and re-zips. A genuinely binary\n * member passes through byte-for-byte. Shared by the browser pillar's `finalizeHar`\n * (file wrapper) and api synthesis (in-memory), so they share ONE redaction code path.\n */\nexport function redactHarZip(zip: Buffer, redact: (value: string) => string): Buffer {\n const entries = unzipSync(new Uint8Array(zip), {\n filter: (file) => file.originalSize <= MAX_HAR_INFLATED_BYTES,\n })\n // The `.har` JSON names the text-like attach bodies (by declared mimeType) the\n // filename gate would miss — collect them first so they are redacted by TYPE.\n let attachText = new Set<string>()\n for (const [name, bytes] of Object.entries(entries)) {\n if (name.endsWith('.har')) attachText = textAttachFiles(strFromU8(bytes))\n }\n const out: Record<string, Uint8Array> = {}\n for (const [name, bytes] of Object.entries(entries)) {\n if (HAR_TEXT_ENTRY.test(name) || attachText.has(name)) {\n out[name] = strToU8(redact(strFromU8(bytes)))\n } else {\n out[name] = bytes\n }\n }\n return Buffer.from(zipSync(out))\n}\n\n/**\n * One captured HTTP exchange (a single request OR a single redirect hop) reduced to\n * what {@link synthesizeRedactedHarZip} needs. The runner's produce channel\n * (`runRequestForHar`, slice 4) emits one of these per hop — so a redirect chain\n * becomes one HAR entry per hop, never a collapsed chain (ADR 0013 Addendum 4 gap a).\n * Bodies are STRING-only: a Buffer/FormData (file/multipart) request body leaves\n * `reqBody` undefined ⇒ no `postData` is synthesized (lossless — the response still\n * validates; gap b's GraphQL path needs only string JSON bodies anyway).\n */\nexport interface HarHopRecord {\n method: string\n url: string\n /** The real numeric HTTP status. A missing status is INCOMPLETE capture and THROWS\n * (never coerced to 0, which the bridge would read as an undocumented-status finding —\n * a false fail masking the true inconclusive state). */\n status: number\n resContentType?: string\n /** The real (secret-bearing) response body text; redacted by {@link redactHarZip}. */\n resBody?: string\n reqContentType?: string\n /** The real (secret-bearing) request body text (GraphQL's `query` lives here). */\n reqBody?: string\n}\n\ninterface SynthEntry {\n request: { method: string; url: string; postData?: { mimeType: string; text: string } }\n response: { status: number; content: { mimeType: string; text?: string } }\n}\n\n/**\n * Synthesize a HAR `.zip` Buffer from per-hop records and IMMEDIATELY redact it — the\n * ONLY public surface, so no un-redacted synthesized buffer is ever returned/stored/\n * validated (ADR 0013 §3b). Builds `{log:{entries}}` with ONLY the six fields the\n * consume bridge reads, INLINE `text` bodies (we hold the strings — no `_file` attach),\n * one `.har` member, then runs {@link redactHarZip}. THROWS on a status-less record.\n */\nexport function synthesizeRedactedHarZip(\n records: HarHopRecord[],\n redact: (value: string) => string,\n): Buffer {\n const entries: SynthEntry[] = []\n for (const r of records) {\n if (typeof r.status !== 'number' || !Number.isFinite(r.status)) {\n throw new Error(`har-synth: record for ${r.method} ${r.url} has no numeric status`)\n }\n const request: SynthEntry['request'] = { method: r.method, url: r.url }\n // postData only for a string body with a declared content-type (omit for binary).\n if (typeof r.reqBody === 'string' && r.reqContentType) {\n request.postData = { mimeType: r.reqContentType, text: r.reqBody }\n }\n const content: SynthEntry['response']['content'] = { mimeType: r.resContentType ?? '' }\n if (typeof r.resBody === 'string') content.text = r.resBody\n entries.push({ request, response: { status: r.status, content } })\n }\n const har = {\n log: { version: '1.2', creator: { name: 'sackville-api', version: '1.2' }, entries },\n }\n const zip = Buffer.from(zipSync({ 'synth.har': strToU8(JSON.stringify(har)) }))\n return redactHarZip(zip, redact)\n}\n","const VAR_RE = /\\{\\{\\s*([^}\\s]+)\\s*\\}\\}/g\n\n/**\n * Interpolate `{{name}}` placeholders from a variable scope. Unknown names are\n * left intact (so callers can detect them). Secret resolution is layered on\n * later, at the transport boundary.\n */\nexport function interpolate(template: string, scope: Record<string, unknown>): string {\n return template.replace(VAR_RE, (match, name: string) => {\n const value = scope[name]\n return value === undefined ? match : String(value)\n })\n}\n","import { readFile } from 'node:fs/promises'\nimport { basename, resolve } from 'node:path'\nimport { FormData } from 'undici'\nimport type { ApiRequest, RequestBody, SecretStore } from './model.js'\nimport type { Redactor } from './secrets.js'\nimport { interpolate } from './vars.js'\n\nconst SECRET_RE = /\\{\\{\\s*secret:([^}\\s]+)\\s*\\}\\}/g\n\nconst RAW_CONTENT_TYPE: Record<string, string> = {\n json: 'application/json',\n text: 'text/plain',\n xml: 'application/xml',\n sparql: 'application/sparql-query',\n}\n\nexport interface PreparedBody {\n /** Content-Type to set when the request carries none; `undefined` lets undici\n * set it itself (e.g. multipart, which needs a generated boundary). */\n contentType?: string\n /** The payload handed to undici. */\n content: string | Buffer | FormData\n /** A redaction-safe textual rendering of the body for agent-facing output\n * (binary/file content is summarized, never inlined). */\n preview: string\n /** For `form`-style bodies (form-urlencoded / multipart): the decoded TEXT fields\n * (repeated keys → array) — the AUTHORITATIVE structured channel for non-JSON body\n * contract validation (ADR 0016 addendum 4). Built from the structured parts at\n * prepare time, NEVER by re-parsing `content`; file bytes never enter it. */\n formFields?: Record<string, string | string[]>\n /** For multipart bodies: the NAMES of FILE parts (bytes are never inlined). */\n formFileFields?: string[]\n}\n\n/** Append a field into a repeated-keys-→-array map (the form-field channel shape). */\nfunction appendField(map: Record<string, string | string[]>, name: string, value: string): void {\n const cur = map[name]\n if (cur === undefined) map[name] = value\n else if (Array.isArray(cur)) cur.push(value)\n else map[name] = [cur, value]\n}\n\n/** A request prepared for the wire — these strings carry REAL secret values. */\nexport interface Prepared {\n method: string\n url: string\n headers: Record<string, string>\n body?: PreparedBody\n}\n\n/**\n * Resolve `{{secret:NAME}}` (from the store, registered with the redactor) and\n * `{{var}}` (from the scope) across the URL, headers, AND body into the actual\n * values sent on the wire. Fails closed on an unresolved secret.\n */\nexport async function prepareRequest(\n request: ApiRequest,\n scope: Record<string, unknown>,\n secrets: SecretStore,\n redactor: Redactor,\n baseDir?: string,\n): Promise<Prepared> {\n const texts = [request.url, ...request.headers.map((h) => h.value), ...bodyTexts(request.body)]\n const fillSecrets = await secretFiller(texts, secrets, redactor)\n const fill = (text: string) => interpolate(fillSecrets(text), scope)\n\n const headers: Record<string, string> = {}\n for (const header of request.headers) headers[header.name] = fill(header.value)\n return {\n method: request.method,\n url: fill(request.url),\n headers,\n body: await materializeBody(request.body, fill, baseDir),\n }\n}\n\n/** The interpolatable strings inside a body (for secret scanning). */\nfunction bodyTexts(body: RequestBody | undefined): string[] {\n if (!body) return []\n if (body.type === 'graphql') {\n const g = body.graphql\n return g ? [g.query, ...(g.variables ? [g.variables] : [])] : []\n }\n if (body.type === 'multipart-form') {\n return (body.parts ?? []).flatMap((p) =>\n p.kind === 'file' ? (p.filePaths ?? []) : [p.value ?? ''],\n )\n }\n if (body.type === 'file') return body.file ? [body.file.filePath] : []\n if (body.content !== undefined) return [body.content]\n return (body.params ?? []).map((p) => p.value)\n}\n\nasync function materializeBody(\n body: RequestBody | undefined,\n fill: (text: string) => string,\n baseDir?: string,\n): Promise<PreparedBody | undefined> {\n if (!body || body.type === 'none') return undefined\n if (body.type === 'form-urlencoded') {\n const params = new URLSearchParams()\n const formFields: Record<string, string | string[]> = {}\n for (const p of body.params ?? []) {\n const value = fill(p.value)\n params.append(p.name, value)\n appendField(formFields, p.name, value)\n }\n const content = params.toString()\n return {\n contentType: 'application/x-www-form-urlencoded',\n content,\n preview: content,\n formFields,\n }\n }\n if (body.type === 'graphql') {\n const content = materializeGraphql(body.graphql, fill)\n return { contentType: 'application/json', content, preview: content }\n }\n if (body.type === 'multipart-form') {\n return materializeMultipart(body, fill, baseDir)\n }\n if (body.type === 'file') {\n return materializeFile(body, fill, baseDir)\n }\n if (body.content !== undefined) {\n const content = fill(body.content)\n return { contentType: RAW_CONTENT_TYPE[body.type] ?? 'text/plain', content, preview: content }\n }\n // Recognized body type with no payload to materialize.\n return undefined\n}\n\n/**\n * A `multipart/form-data` body. Text parts carry interpolated values; file parts\n * read their bytes from disk (paths resolved against the collection dir — the\n * `.bru` is operator-authored config, and egress is separately gated, so paths\n * are not sandboxed here). undici mints the boundary, so `contentType` is left\n * unset. The preview summarizes parts (file by name + byte size), never inlining\n * file bytes; text values flow through the redactor at the surface.\n */\nasync function materializeMultipart(\n body: RequestBody,\n fill: (text: string) => string,\n baseDir?: string,\n): Promise<PreparedBody> {\n const form = new FormData()\n const lines = ['multipart/form-data:']\n const formFields: Record<string, string | string[]> = {}\n const fileFields = new Set<string>()\n for (const part of body.parts ?? []) {\n if (part.kind === 'file') {\n fileFields.add(part.name) // NAME only — bytes never enter the structured channel\n for (const rawPath of part.filePaths ?? []) {\n const filled = fill(rawPath)\n const buf = await readFile(resolve(baseDir ?? '', filled))\n const blob = new Blob([buf], part.contentType ? { type: part.contentType } : {})\n form.append(part.name, blob as unknown as Blob, basename(filled))\n lines.push(` ${part.name} (file): ${filled} (${buf.byteLength} bytes)`)\n }\n } else {\n const value = fill(part.value ?? '')\n form.append(part.name, value)\n appendField(formFields, part.name, value)\n lines.push(` ${part.name} (text): ${value}`)\n }\n }\n return {\n content: form,\n preview: lines.join('\\n'),\n formFields,\n ...(fileFields.size > 0 ? { formFileFields: [...fileFields] } : {}),\n }\n}\n\n/**\n * A raw file body — the file's bytes are sent as the request body under the\n * declared content type (default `application/octet-stream`). Path resolved\n * against the collection dir (same operator-config trust model as multipart).\n * The preview names the file by path + byte size + content type; the bytes are\n * never inlined into agent-facing output.\n */\nasync function materializeFile(\n body: RequestBody,\n fill: (text: string) => string,\n baseDir?: string,\n): Promise<PreparedBody | undefined> {\n if (!body.file) return undefined\n const filled = fill(body.file.filePath)\n const buf = await readFile(resolve(baseDir ?? '', filled))\n const contentType = body.file.contentType || 'application/octet-stream'\n const preview = `<file: ${filled} (${buf.byteLength} bytes, ${contentType})>`\n return { contentType, content: buf, preview }\n}\n\n/** A GraphQL-over-HTTP envelope: `{query, variables}` as JSON. Variables (a JSON\n * string in the `.bru`) are interpolated then parsed into an object; an empty or\n * whitespace-only variables block is omitted. */\nfunction materializeGraphql(\n graphql: { query: string; variables?: string } | undefined,\n fill: (text: string) => string,\n): string {\n const query = fill(graphql?.query ?? '')\n const rawVars = graphql?.variables?.trim()\n if (!rawVars) return JSON.stringify({ query })\n const filled = fill(rawVars)\n let variables: unknown\n try {\n variables = JSON.parse(filled)\n } catch (e) {\n throw new Error(`invalid graphql variables JSON: ${(e as Error).message}`)\n }\n return JSON.stringify({ query, variables })\n}\n\nasync function secretFiller(\n texts: string[],\n secrets: SecretStore,\n redactor: Redactor,\n): Promise<(text: string) => string> {\n const names = new Set<string>()\n for (const text of texts) {\n for (const match of text.matchAll(SECRET_RE)) names.add(match[1] as string)\n }\n\n const resolved = new Map<string, string>()\n const missing: string[] = []\n for (const name of names) {\n const value = await secrets.get(name)\n if (value === undefined) {\n missing.push(name)\n continue\n }\n resolved.set(name, value)\n redactor.register(name, value)\n }\n if (missing.length > 0) {\n throw new Error(`missing secret(s): ${missing.join(', ')}`)\n }\n\n return (text) =>\n text.replace(SECRET_RE, (_m, name: string) => resolved.get(name) ?? `{{secret:${name}}}`)\n}\n","import { type DnsLookup, resolveAndPin, SsrfError } from '@sackville-mcp/safety'\n\n/** Methods that don't mutate server state run freely. */\nconst SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS'])\n\nexport interface SsrfOptions {\n /** Permit loopback/RFC1918/CGNAT/unique-local targets. Defaults to **true**\n * (local-API testing is a primary use case). Link-local (incl. the\n * 169.254.169.254 metadata IP), multicast, and other always-dangerous ranges\n * are refused regardless. Set false for a hardened, internet-only posture. */\n allowPrivate?: boolean\n /** Injectable DNS resolver (tests). */\n lookup?: DnsLookup\n}\n\n/**\n * Refuse a request on SSRF grounds before it leaves. Applies to EVERY request\n * (safe + mutating) — the cloud-metadata endpoint is reachable by a plain GET.\n * Reuses the shared `@sackville-mcp/safety` classifier: metadata host literals and\n * blocked-range IPs are always refused; loopback/private are refused only when\n * `allowPrivate` is false; a hostname is resolved and its address vetted (so a\n * name pointing at an internal/metadata IP is caught). Throws `SsrfError` when\n * blocked. NOTE: this is a pre-flight resolve-and-refuse, not a connection pin —\n * a narrow DNS-rebinding TOCTOU window remains (the browser pillar's proxy does\n * true pinning); for operator-authored API collections that is an accepted\n * limitation, documented in ADR 0004.\n */\nexport async function assertSsrfAllowed(url: string, opts: SsrfOptions = {}): Promise<void> {\n let hostname: string\n try {\n hostname = new URL(url).hostname\n } catch {\n throw new SsrfError(`invalid request URL: ${url}`)\n }\n // URL IPv6 literals are bracketed (`[::1]`); strip for classification.\n const host = hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname\n // resolveAndPin throws SsrfError on a blocked literal / IP / resolved address;\n // we discard the pinned IP (no connection pinning — see the note above).\n await resolveAndPin(host, opts.lookup, { allowPrivate: opts.allowPrivate ?? true })\n}\n\nexport interface SafetyOptions {\n /** Opt in to actually sending mutating requests. */\n allowUnsafe?: boolean\n /** Hostnames a mutating request is permitted to reach. */\n allowedHosts?: string[]\n}\n\nexport interface SafetyDecision {\n allowed: boolean\n reason: string\n}\n\nexport function isMutating(method: string): boolean {\n return !SAFE_METHODS.has(method.toUpperCase())\n}\n\n/**\n * Decide whether a request may actually be sent. Safe methods always may.\n * Mutating methods are withheld (dry-run) unless explicitly unlocked\n * (`allowUnsafe`) AND the target host is on the allowlist — never silently fired.\n */\nexport function checkGate(method: string, host: string, opts: SafetyOptions = {}): SafetyDecision {\n if (!isMutating(method)) {\n return { allowed: true, reason: `${method.toUpperCase()} is a safe method` }\n }\n if (!opts.allowUnsafe) {\n return {\n allowed: false,\n reason: `${method.toUpperCase()} is a mutating method; dry-run only (pass allowUnsafe to send)`,\n }\n }\n const allowed = opts.allowedHosts ?? []\n if (!allowed.includes(host)) {\n return {\n allowed: false,\n reason: `host ${host} is not in the allowlist for mutating requests (${allowed.join(', ') || 'none'})`,\n }\n }\n return { allowed: true, reason: `${method.toUpperCase()} to ${host} is allowlisted` }\n}\n","import {\n getQuickJS,\n type QuickJSWASMModule,\n shouldInterruptAfterDeadline,\n} from 'quickjs-emscripten'\nimport type { ScriptTest } from './model.js'\n\nexport type { ScriptTest } from './model.js'\n\nexport interface ScriptResponseView {\n status: number\n headers: Record<string, string>\n body: string\n json: unknown\n}\n\nexport interface ScriptResult {\n /** The full variable scope after the script ran (incl. `bru.setVar` writes). */\n vars: Record<string, unknown>\n tests: ScriptTest[]\n logs: string[]\n /** A top-level (non-`test`) error thrown by the script, if any. */\n error?: string\n}\n\nconst TIMEOUT_MS = 1000\n\n// Curated API injected into the sandbox. No host bindings — everything is plain\n// data, exchanged as JSON, so the only thing crossing the WASM boundary is text.\nconst PRELUDE = `\nglobalThis.console = { log: (...a) => __logs.push(a.map(String).join(' ')), error: (...a) => __logs.push(a.map(String).join(' ')) };\nglobalThis.bru = {\n getVar: (k) => __vars[k],\n setVar: (k, v) => { __vars[k] = v; },\n};\nfunction __mk(actual) {\n const fail = (m) => { throw new Error(m); };\n const eq = (a, b) => JSON.stringify(a) === JSON.stringify(b);\n return {\n toBe: (e) => { if (actual !== e) fail('expected ' + JSON.stringify(actual) + ' to be ' + JSON.stringify(e)); },\n toEqual: (e) => { if (!eq(actual, e)) fail('expected ' + JSON.stringify(actual) + ' to equal ' + JSON.stringify(e)); },\n toContain: (e) => { if (!String(actual).includes(String(e))) fail('expected ' + JSON.stringify(actual) + ' to contain ' + JSON.stringify(e)); },\n toBeGreaterThan: (e) => { if (!(actual > e)) fail('expected ' + actual + ' > ' + e); },\n toBeLessThan: (e) => { if (!(actual < e)) fail('expected ' + actual + ' < ' + e); },\n toBeTruthy: () => { if (!actual) fail('expected truthy, got ' + JSON.stringify(actual)); },\n toBeFalsy: () => { if (actual) fail('expected falsy, got ' + JSON.stringify(actual)); },\n };\n}\nglobalThis.expect = (actual) => __mk(actual);\nglobalThis.test = (name, fn) => {\n try { fn(); __tests.push({ name: name, pass: true }); }\n catch (e) { __tests.push({ name: name, pass: false, error: String((e && e.message) || e) }); }\n};\n`\n\nlet modulePromise: Promise<QuickJSWASMModule> | undefined\nfunction quickjs(): Promise<QuickJSWASMModule> {\n if (!modulePromise) modulePromise = getQuickJS()\n return modulePromise\n}\n\n/**\n * Run a pre/post-request script in a QuickJS WASM sandbox with the curated\n * `bru`/`expect`/`test`/`console` API and a wall-clock interrupt. The script\n * sees `res` (post-response only) and reads/writes variables via `bru`; nothing\n * from the host process is reachable.\n */\nexport async function runScript(\n code: string,\n context: { vars: Record<string, unknown>; res?: ScriptResponseView },\n): Promise<ScriptResult> {\n const QuickJS = await quickjs()\n const runtime = QuickJS.newRuntime()\n runtime.setInterruptHandler(shouldInterruptAfterDeadline(Date.now() + TIMEOUT_MS))\n const vm = runtime.newContext()\n\n try {\n const init =\n `globalThis.__vars = ${JSON.stringify(context.vars)};` +\n 'globalThis.__tests = [];' +\n 'globalThis.__logs = [];' +\n `globalThis.res = ${context.res ? JSON.stringify(context.res) : 'undefined'};` +\n PRELUDE\n const setup = vm.evalCode(init)\n if (setup.error) {\n const message = vm.dump(setup.error)\n setup.error.dispose()\n throw new Error(`script sandbox setup failed: ${JSON.stringify(message)}`)\n }\n setup.value.dispose()\n\n let error: string | undefined\n const run = vm.evalCode(code)\n if (run.error) {\n const dumped = vm.dump(run.error)\n run.error.dispose()\n error =\n typeof dumped === 'object' && dumped?.message ? String(dumped.message) : String(dumped)\n } else {\n run.value.dispose()\n }\n\n const read = vm.evalCode('JSON.stringify({ vars: __vars, tests: __tests, logs: __logs })')\n let data = { vars: context.vars, tests: [] as ScriptTest[], logs: [] as string[] }\n if (read.error) {\n read.error.dispose()\n } else {\n data = JSON.parse(vm.dump(read.value))\n read.value.dispose()\n }\n\n return { vars: data.vars ?? {}, tests: data.tests ?? [], logs: data.logs ?? [], error }\n } finally {\n vm.dispose()\n runtime.dispose()\n }\n}\n","import type { SecretStore } from './model.js'\n\n// The redaction boundary is shared across pillars; it lives in @sackville-mcp/safety.\n// Re-exported here so existing `import { Redactor } from './secrets.js'` sites\n// (runner, prepare, script, …) keep working unchanged.\nexport { Redactor } from '@sackville-mcp/safety'\n\n/** In-memory store (tests / explicit injection). */\nexport class StaticSecretStore implements SecretStore {\n constructor(private readonly values: Record<string, string> = {}) {}\n get(name: string): Promise<string | undefined> {\n return Promise.resolve(this.values[name])\n }\n}\n\n/**\n * Reads `<prefix><NAME>` from the environment — the zero-dependency default\n * (Linux/CI). The default prefix is `SACKVILLE_SECRET_`; the aggregate server\n * overrides it to `SACKVILLE_API_SECRET_` so the api pillar's secrets live in its\n * own namespace and can't be read via a bare, shared name (ADR 0019).\n */\nexport class EnvSecretStore implements SecretStore {\n constructor(\n private readonly env: Record<string, string | undefined> = process.env,\n private readonly prefix = 'SACKVILLE_SECRET_',\n ) {}\n get(name: string): Promise<string | undefined> {\n return Promise.resolve(this.env[`${this.prefix}${name}`])\n }\n}\n\n/** OS keychain via @napi-rs/keyring (macOS/Windows/Linux-desktop). The native\n * module is loaded lazily through a non-literal specifier so importing this file\n * never loads it; Secret Service can throw at runtime in headless containers, so\n * failures resolve to undefined. */\nexport class KeyringSecretStore implements SecretStore {\n constructor(private readonly service = 'sackville') {}\n async get(name: string): Promise<string | undefined> {\n try {\n const moduleId: string = '@napi-rs/keyring'\n const { Entry } = await import(moduleId)\n const value = new Entry(this.service, name).getPassword()\n return typeof value === 'string' ? value : undefined\n } catch {\n return undefined\n }\n }\n}\n\n/** Try each store in order, first hit wins. */\nexport class ChainedSecretStore implements SecretStore {\n constructor(private readonly stores: SecretStore[]) {}\n async get(name: string): Promise<string | undefined> {\n for (const store of this.stores) {\n const value = await store.get(name)\n if (value !== undefined) return value\n }\n return undefined\n }\n}\n\n/**\n * Default store: keyring (opt-in) chained ahead of env, else env only.\n * `env`/`envPrefix` override the environment source + variable prefix the\n * `EnvSecretStore` reads (the aggregate server passes `SACKVILLE_API_SECRET_`).\n */\nexport function resolveSecretStore(\n opts: { keyring?: boolean; env?: Record<string, string | undefined>; envPrefix?: string } = {},\n): SecretStore {\n const envStore = new EnvSecretStore(opts.env, opts.envPrefix)\n return opts.keyring ? new ChainedSecretStore([new KeyringSecretStore(), envStore]) : envStore\n}\n","import { randomUUID } from 'node:crypto'\nimport { performance } from 'node:perf_hooks'\nimport { type DnsLookup, SsrfError } from '@sackville-mcp/safety'\nimport { type Dispatcher, type FormData, request } from 'undici'\nimport { ArtifactStore } from './artifacts.js'\nimport { evaluateAssertions, extractCaptures } from './assert.js'\nimport type { HarHopRecord } from './har-synth.js'\nimport type { Collection, PreparedRequest, RunResult, ScriptTest, SecretStore } from './model.js'\nimport { type Prepared, prepareRequest } from './prepare.js'\nimport type { RequestFacts } from './request-contract.js'\nimport { assertSsrfAllowed, checkGate, isMutating } from './safety.js'\nimport { runScript } from './script.js'\nimport { EnvSecretStore, Redactor } from './secrets.js'\n\nexport interface RunOptions {\n /** Variable scope for `{{var}}` interpolation. */\n vars?: Record<string, unknown>\n /** Name of a collection environment whose vars seed the scope (lowest precedence). */\n env?: string\n /** Secret store for `{{secret:NAME}}` resolution (defaults to env). */\n secrets?: SecretStore\n /** Artifact store for the response body (a fresh one is used if omitted). */\n artifacts?: ArtifactStore\n /** Opt in to actually sending mutating requests. */\n allowUnsafe?: boolean\n /** Hostnames a mutating request may reach. */\n allowedHosts?: string[]\n /** Permit loopback/private SSRF targets (default true; see `assertSsrfAllowed`).\n * Set false to block all private ranges, not just metadata/link-local. */\n allowPrivate?: boolean\n /** Injectable DNS resolver for the SSRF pre-flight (tests). */\n lookup?: DnsLookup\n /** Maximum redirect hops to follow (default 0 = don't follow; return the 3xx).\n * Every hop is re-checked: SSRF range-block + the mutation host-allowlist. */\n maxRedirects?: number\n}\n\nconst REDIRECT_CODES = new Set([301, 302, 303, 307, 308])\n/** Headers dropped when a redirect crosses to a different host (browser-like). */\nconst CROSS_ORIGIN_DROP = new Set(['authorization', 'cookie'])\n/** Cap a retained per-hop body so a hostile redirect body can't bloat the synthesized\n * HAR (the read itself is bounded by the response; slicing a JSON body just fails to\n * parse downstream ⇒ unresolved ⇒ inconclusive, never a false pass). 5f. */\nconst MAX_HOP_BODY_BYTES = 4 * 1024 * 1024\n\n/**\n * The PRODUCE-only out-of-band capture channel (ADR 0013 Addendum 4, 5f): the raw\n * per-hop request/response facts a synthesized HAR is built from, plus the run-resolved\n * secret pairs the union redactor must learn. NEVER attached to `RunResult` — raw bodies\n * stay structurally off anything an agent sees; only `runRequestForHar` exposes it, and\n * its consumer ({@link synthesizeRedactedHarZip} via the verify driver) redacts before\n * store + validate.\n */\nexport interface HarCapture {\n hops: HarHopRecord[]\n registeredSecrets: { name: string; value: string }[]\n /** The terminal response was still a 3xx (budget exhausted / unparseable / missing\n * Location): the exchange did not complete to a resource ⇒ the driver throws\n * (inconclusive), never validates a truncated chain. */\n redirectTruncated: boolean\n}\n\n/** Append one hop's facts to the capture sink (string-only request body; binary omitted). */\nfunction recordHop(\n capture: HarCapture,\n hop: {\n method: string\n url: string\n status: number\n resContentType?: string\n resBody?: string\n reqBody: string | undefined\n reqContentType: string | undefined\n },\n): void {\n const record: HarHopRecord = { method: hop.method, url: hop.url, status: hop.status }\n if (hop.resContentType) record.resContentType = hop.resContentType\n if (hop.resBody !== undefined) record.resBody = hop.resBody.slice(0, MAX_HOP_BODY_BYTES)\n if (typeof hop.reqBody === 'string' && hop.reqContentType) {\n record.reqContentType = hop.reqContentType\n record.reqBody = hop.reqBody.slice(0, MAX_HOP_BODY_BYTES)\n }\n capture.hops.push(record)\n}\n\nfunction headerValue(\n headers: Record<string, string | string[] | undefined>,\n name: string,\n): string | undefined {\n const v = headers[name]\n return Array.isArray(v) ? v[0] : v\n}\n\n/** Method/body for the next hop. 303 (and POST on 301/302) downgrades to GET and\n * drops the body; 307/308 preserve both. */\nfunction redirectTransition(\n status: number,\n method: string,\n body: string | Buffer | FormData | undefined,\n): { method: string; body: string | Buffer | FormData | undefined } {\n if (status === 303 || ((status === 301 || status === 302) && method.toUpperCase() === 'POST')) {\n return { method: 'GET', body: undefined }\n }\n return { method, body }\n}\n\nfunction dropCrossOriginHeaders(headers: Record<string, string>): Record<string, string> {\n const out: Record<string, string> = {}\n for (const [key, value] of Object.entries(headers)) {\n if (!CROSS_ORIGIN_DROP.has(key.toLowerCase())) out[key] = value\n }\n return out\n}\n\nfunction hasHeader(headers: Record<string, string>, name: string): boolean {\n const lower = name.toLowerCase()\n return Object.keys(headers).some((k) => k.toLowerCase() === lower)\n}\n\nfunction hostOf(url: string): string {\n try {\n return new URL(url).hostname\n } catch {\n return ''\n }\n}\n\nfunction flattenHeaders(\n headers: Record<string, string | string[] | undefined>,\n): Record<string, string> {\n const out: Record<string, string> = {}\n for (const [key, value] of Object.entries(headers)) {\n out[key.toLowerCase()] = Array.isArray(value) ? value.join(', ') : String(value ?? '')\n }\n return out\n}\n\n/**\n * Execute one request: resolve vars + secrets, apply the mutation safety gate\n * (mutating methods dry-run unless explicitly unlocked), dispatch via undici if\n * allowed, evaluate assertions, and return a result whose surfaced strings\n * (request, response headers, body artifact) are all secret-redacted.\n */\nexport async function runRequest(\n collection: Collection,\n name: string,\n opts: RunOptions = {},\n): Promise<RunResult> {\n return runRequestImpl(collection, name, opts)\n}\n\n/**\n * Drive a request AND retain the raw per-hop facts a synthesized HAR is built from\n * (ADR 0013 Addendum 4, 5f) — the verify-driven api capture path. `RunResult` is\n * returned UNCHANGED (still fully redacted); `capture` is the produce-only raw channel\n * (never on `RunResult`). The caller (verify driver) folds `capture.registeredSecrets`\n * into a union redactor, then synthesizes + redacts + validates.\n */\nexport async function runRequestForHar(\n collection: Collection,\n name: string,\n opts: RunOptions = {},\n): Promise<{ result: RunResult; capture: HarCapture }> {\n const capture: HarCapture = { hops: [], registeredSecrets: [], redirectTruncated: false }\n const result = await runRequestImpl(collection, name, opts, capture)\n return { result, capture }\n}\n\n/**\n * The out-of-band channel surfacing the UN-redacted {@link RequestFacts} a contract\n * validator reads (method, pathname, decoded query, lower-cased headers, JSON-parsed\n * body), plus the run-resolved secret pairs a downstream redactor must learn to scrub\n * findings. Mirrors {@link HarCapture}: NEVER attached to `RunResult` (which stays fully\n * redacted), and populated at PREPARE time so it is available even when the request is\n * withheld (dry-run / gated). Consumed by `api run --openapi`'s request-side validation\n * (ADR 0014).\n */\nexport interface ContractRequestCapture {\n request: RequestFacts\n registeredSecrets: { name: string; value: string }[]\n}\n\n/**\n * Drive a request AND retain the un-redacted request facts a contract validator reads\n * (ADR 0014). `RunResult` is returned UNCHANGED (still fully redacted); `capture` is the\n * raw channel (never on `RunResult`). The caller (`api run --openapi`) folds\n * `capture.registeredSecrets` into a redactor, validates `capture.request` against the\n * contract, then redacts the findings before surfacing them.\n */\nexport async function runRequestForContract(\n collection: Collection,\n name: string,\n opts: RunOptions = {},\n): Promise<{ result: RunResult; capture: ContractRequestCapture }> {\n const capture: ContractRequestCapture = {\n request: { method: '', path: '' },\n registeredSecrets: [],\n }\n const result = await runRequestImpl(collection, name, opts, undefined, capture)\n return { result, capture }\n}\n\n/** JSON-family media type: `application/json` or any `*+json`. */\nfunction isJsonFamily(ct: string | undefined): boolean {\n if (!ct) return false\n const base = (ct.split(';')[0] ?? '').trim().toLowerCase()\n return base === 'application/json' || base.endsWith('+json')\n}\n\n/** Decode a query string into a record; a repeated key collapses to an array. */\nfunction queryRecord(sp: URLSearchParams): Record<string, string | string[]> {\n const out: Record<string, string | string[]> = {}\n for (const key of new Set(sp.keys())) {\n const all = sp.getAll(key)\n out[key] = all.length > 1 ? all : (all[0] ?? '')\n }\n return out\n}\n\n/**\n * Build the UN-redacted {@link RequestFacts} a contract validator reads from a prepared\n * request. A JSON-family body is parsed to its value (so schema validation is\n * meaningful); a present non-JSON / binary body (multipart/file/urlencoded/xml) is passed\n * through as a non-undefined value so the validator routes it to its presence-only\n * `unverified` path — never a false `missing-required-body`. A multipart body's\n * Content-Type (set by undici with the boundary, absent at prepare time) is synthesized as\n * a bare `multipart/form-data` so that routing is correct.\n */\nfunction buildRequestFacts(\n prepared: Prepared,\n sendHeaders: Record<string, string>,\n bodyType: string | undefined,\n): RequestFacts {\n const url = new URL(prepared.url)\n const headers = flattenHeaders(sendHeaders)\n if (bodyType === 'multipart-form' && headers['content-type'] === undefined) {\n headers['content-type'] = 'multipart/form-data'\n }\n let body: unknown\n if (prepared.body) {\n const content = prepared.body.content\n if (typeof content === 'string') {\n if (isJsonFamily(headers['content-type'])) {\n try {\n body = JSON.parse(content)\n } catch {\n body = content // unparseable JSON body: the schema-check reports the violation\n }\n } else {\n body = content // non-JSON text body → validator marks it unverified by Content-Type\n }\n } else {\n // binary/multipart: no string content — surface presence (the redaction-safe\n // preview); the non-JSON Content-Type routes it to `unverified`.\n body = prepared.body.preview\n }\n }\n const query = queryRecord(url.searchParams)\n const facts: RequestFacts = { method: prepared.method, path: url.pathname }\n if (body !== undefined) facts.body = body\n if (Object.keys(query).length > 0) facts.query = query\n if (Object.keys(headers).length > 0) facts.headers = headers\n // The authoritative structured form-field channel for non-JSON body validation\n // (ADR 0016 addendum 4) — never re-parsed from `content`.\n if (prepared.body?.formFields) facts.form = prepared.body.formFields\n if (prepared.body?.formFileFields) facts.formFileFields = prepared.body.formFileFields\n return facts\n}\n\nasync function runRequestImpl(\n collection: Collection,\n name: string,\n opts: RunOptions = {},\n capture?: HarCapture,\n contractSink?: ContractRequestCapture,\n): Promise<RunResult> {\n const entry = collection.requests.get(name)\n if (!entry) {\n throw new Error(`no request '${name}' in collection at ${collection.dir}`)\n }\n\n const secrets = opts.secrets ?? new EnvSecretStore()\n const redactor = new Redactor()\n // Scope precedence: explicit/captured vars override the chosen environment.\n const envVars = opts.env ? (collection.environments.get(opts.env) ?? {}) : {}\n const scope = { ...envVars, ...(opts.vars ?? {}) }\n\n // Pre-request script may set variables used in interpolation.\n if (entry.preScript) {\n const pre = await runScript(entry.preScript, { vars: scope })\n Object.assign(scope, pre.vars)\n }\n\n const prepared = await prepareRequest(entry.request, scope, secrets, redactor, collection.dir)\n\n // The union redactor (verify) must learn the run-resolved {{secret:NAME}} values to\n // scrub a synthesized HAR — the local redactor is the only place they exist (5f).\n if (capture) capture.registeredSecrets = redactor.registeredSecrets()\n\n // Headers actually sent: add a default Content-Type for the body if unset.\n // A body with no explicit contentType (multipart) is left for undici to set,\n // since it must generate the boundary.\n const sendHeaders = { ...prepared.headers }\n if (prepared.body?.contentType && !hasHeader(sendHeaders, 'content-type')) {\n sendHeaders['Content-Type'] = prepared.body.contentType\n }\n\n // Surface the un-redacted request facts + resolved secrets for contract validation\n // (ADR 0014). Done at PREPARE time so they exist even when the request is withheld\n // (the gate may dry-run below); `RunResult` itself stays fully redacted.\n if (contractSink) {\n contractSink.request = buildRequestFacts(prepared, sendHeaders, entry.request.body?.type)\n contractSink.registeredSecrets = redactor.registeredSecrets()\n }\n\n const redactedRequest: PreparedRequest = {\n method: prepared.method,\n url: redactor.redact(prepared.url),\n headers: redactor.redactHeaders(sendHeaders),\n body: prepared.body ? redactor.redact(prepared.body.preview) : undefined,\n }\n\n const gate = checkGate(prepared.method, hostOf(prepared.url), {\n allowUnsafe: opts.allowUnsafe,\n allowedHosts: opts.allowedHosts,\n })\n if (!gate.allowed) {\n return { request: redactedRequest, sent: false, dryRun: true, reason: gate.reason }\n }\n\n // SSRF range-block: applies to every request that would actually go out (a\n // safe GET to the metadata endpoint is the classic SSRF). A block is a safety\n // refusal, not a dry-run — surfaced as withheld with a reason.\n try {\n await assertSsrfAllowed(prepared.url, { allowPrivate: opts.allowPrivate, lookup: opts.lookup })\n } catch (err) {\n if (err instanceof SsrfError) {\n return {\n request: redactedRequest,\n sent: false,\n dryRun: false,\n reason: `blocked: ${err.message}`,\n }\n }\n throw err\n }\n\n const started = performance.now()\n const maxRedirects = opts.maxRedirects ?? 0\n const redirects: { status: number; location: string }[] = []\n\n let currentUrl = prepared.url\n let currentMethod = prepared.method\n let currentHeaders = sendHeaders\n let currentBody = prepared.body?.content\n // The wire content-type tracked per hop for HAR synthesis (dropped when a 303/POST\n // downgrade drops the body); only a string body becomes `postData` (5f).\n let currentContentType = prepared.body?.contentType\n const reqBodyStr = () => (typeof currentBody === 'string' ? currentBody : undefined)\n\n let res = await request(currentUrl, {\n method: currentMethod as Dispatcher.HttpMethod,\n headers: currentHeaders,\n body: currentBody,\n })\n\n // Follow redirects (opt-in), re-checking every hop: SSRF range-block, then the\n // mutation host-allowlist, then strip credential headers on a host change.\n while (REDIRECT_CODES.has(res.statusCode) && redirects.length < maxRedirects) {\n const location = headerValue(res.headers, 'location')\n if (!location) break\n // Capture this just-arrived (legitimate) hop BEFORE vetting/dispatching the next, so\n // a blocked next hop is never recorded as sent. Consume the body either way (5f).\n if (capture) {\n const hopText = await res.body.text()\n recordHop(capture, {\n method: currentMethod,\n url: currentUrl,\n status: res.statusCode,\n resContentType: headerValue(res.headers, 'content-type'),\n resBody: hopText,\n reqBody: reqBodyStr(),\n reqContentType: currentContentType,\n })\n } else {\n await res.body.dump() // drain the intermediate response before the next hop\n }\n\n let nextUrl: string\n try {\n nextUrl = new URL(location, currentUrl).toString()\n } catch {\n break // unparseable Location — surface the 3xx as the response\n }\n\n try {\n await assertSsrfAllowed(nextUrl, { allowPrivate: opts.allowPrivate, lookup: opts.lookup })\n } catch (err) {\n if (err instanceof SsrfError) {\n return {\n request: redactedRequest,\n sent: false,\n dryRun: false,\n reason: `blocked redirect: ${err.message}`,\n }\n }\n throw err\n }\n\n const next = redirectTransition(res.statusCode, currentMethod, currentBody)\n if (isMutating(next.method)) {\n const g = checkGate(next.method, hostOf(nextUrl), {\n allowUnsafe: opts.allowUnsafe,\n allowedHosts: opts.allowedHosts,\n })\n if (!g.allowed) {\n return {\n request: redactedRequest,\n sent: false,\n dryRun: true,\n reason: `redirect blocked: ${g.reason}`,\n }\n }\n }\n\n const sameHost = hostOf(nextUrl) === hostOf(currentUrl)\n const nextHeaders = sameHost ? currentHeaders : dropCrossOriginHeaders(currentHeaders)\n redirects.push({ status: res.statusCode, location: redactor.redact(nextUrl) })\n\n res = await request(nextUrl, {\n method: next.method as Dispatcher.HttpMethod,\n headers: nextHeaders,\n body: next.body,\n })\n currentUrl = nextUrl\n currentMethod = next.method\n currentHeaders = nextHeaders\n currentBody = next.body\n // A 303 (or POST→GET) downgrade dropped the body ⇒ no request content-type for the\n // next hop; 307/308 preserve both.\n if (next.body === undefined) currentContentType = undefined\n }\n\n // The loop exited with a terminal 3xx (budget exhausted / no or unparseable Location):\n // the exchange did not complete to a resource — the driver folds this to inconclusive.\n if (capture && REDIRECT_CODES.has(res.statusCode)) capture.redirectTruncated = true\n\n const bodyText = await res.body.text()\n const latencyMs = performance.now() - started\n const headers = flattenHeaders(res.headers)\n\n // The terminal response is the last HAR hop (raw body — the union redactor scrubs the\n // synthesized archive). One entry per hop, no collapsed chain (5f gap a).\n if (capture) {\n recordHop(capture, {\n method: currentMethod,\n url: currentUrl,\n status: res.statusCode,\n resContentType: headers['content-type'],\n resBody: bodyText,\n reqBody: reqBodyStr(),\n reqContentType: currentContentType,\n })\n }\n\n let json: unknown\n try {\n json = JSON.parse(bodyText)\n } catch {\n json = undefined\n }\n\n // Assertions/captures evaluate the REAL response; only surfaced strings are\n // redacted. Captures feed later requests in a sequence (see runSequence).\n const ctx = { status: res.statusCode, statusText: '', headers, bodyText, json, latencyMs }\n const assertions = evaluateAssertions(entry.assertions, ctx)\n const captured = extractCaptures(entry.captures, ctx)\n\n // Post-response script: programmatic tests + captures over the REAL response.\n let scriptTests: ScriptTest[] = []\n if (entry.postScript) {\n const before = { ...scope }\n const post = await runScript(entry.postScript, {\n vars: scope,\n res: { status: res.statusCode, headers, body: bodyText, json },\n })\n scriptTests = post.tests.map((t) => ({\n name: redactor.redact(t.name),\n pass: t.pass,\n error: t.error ? redactor.redact(t.error) : undefined,\n }))\n for (const [key, value] of Object.entries(post.vars)) {\n if (!(key in before) || before[key] !== value) {\n captured[key] = value\n scope[key] = value\n }\n }\n }\n\n const store = opts.artifacts ?? new ArtifactStore()\n const bodyHandle = store.put(\n randomUUID(),\n redactor.redact(bodyText),\n headers['content-type'] ?? 'application/octet-stream',\n )\n\n return {\n request: redactedRequest,\n sent: true,\n dryRun: false,\n response: {\n status: res.statusCode,\n latencyMs,\n headers: redactor.redactHeaders(headers),\n assertions,\n scriptTests,\n captured,\n bodyHandle,\n redirects,\n },\n }\n}\n","import type { Collection, RunResult } from './model.js'\nimport type { HarCapture } from './runner.js'\nimport { type RunOptions, runRequest, runRequestForHar } from './runner.js'\n\nexport interface SequenceOptions extends RunOptions {\n /** Stop the sequence if a request's assertions fail. */\n stopOnFailure?: boolean\n}\n\nexport interface SequenceStep {\n name: string\n result: RunResult\n}\n\nexport interface SequenceResult {\n steps: SequenceStep[]\n /** Variables captured across the whole sequence (threaded forward). */\n captured: Record<string, unknown>\n}\n\n/**\n * Run requests in order, threading each response's captured variables into the\n * scope of the requests that follow (request chaining). Per-run options\n * (secrets, allowUnsafe, allowlist, artifacts) apply to every request; the\n * variable scope is the shared, accumulating one.\n */\nexport async function runSequence(\n collection: Collection,\n names: string[],\n opts: SequenceOptions = {},\n): Promise<SequenceResult> {\n const scope: Record<string, unknown> = { ...(opts.vars ?? {}) }\n const captured: Record<string, unknown> = {}\n const steps: SequenceStep[] = []\n\n for (const name of names) {\n const result = await runRequest(collection, name, { ...opts, vars: scope })\n steps.push({ name, result })\n\n if (result.sent && result.response) {\n Object.assign(scope, result.response.captured)\n Object.assign(captured, result.response.captured)\n if (opts.stopOnFailure && !result.response.assertions.every((a) => a.pass)) break\n }\n }\n\n return { steps, captured }\n}\n\n/**\n * Like {@link runSequence} but ALSO retains the raw per-hop capture across every step\n * (ADR 0013 Addendum 4, 5f) — for the verify-driven api capture path. Each step's\n * `SequenceStep.result` is UNCHANGED (redacted); `capture` aggregates all hops + the\n * union of run-resolved secret pairs. The transport-completeness guard (every\n * `step.result.sent`) lives in the driver, which folds a non-sent step to inconclusive.\n */\nexport async function runSequenceForHar(\n collection: Collection,\n names: string[],\n opts: SequenceOptions = {},\n): Promise<{ result: SequenceResult; capture: HarCapture }> {\n const scope: Record<string, unknown> = { ...(opts.vars ?? {}) }\n const captured: Record<string, unknown> = {}\n const steps: SequenceStep[] = []\n const capture: HarCapture = { hops: [], registeredSecrets: [], redirectTruncated: false }\n\n for (const name of names) {\n const { result, capture: hopCap } = await runRequestForHar(collection, name, {\n ...opts,\n vars: scope,\n })\n steps.push({ name, result })\n capture.hops.push(...hopCap.hops)\n capture.registeredSecrets.push(...hopCap.registeredSecrets)\n if (hopCap.redirectTruncated) capture.redirectTruncated = true\n\n if (result.sent && result.response) {\n Object.assign(scope, result.response.captured)\n Object.assign(captured, result.response.captured)\n if (opts.stopOnFailure && !result.response.assertions.every((a) => a.pass)) break\n }\n }\n\n return { result: { steps, captured }, capture }\n}\n","/**\n * The verify-DRIVEN API capture driver (ADR 0013 Addendum 4, milestone 5f). Drives the\n * `@sackville-mcp/api` runner for an operator-authored request (or sequence), SYNTHESIZES a\n * HAR from the run, redacts + stores it, and validates it against the contract via the\n * SHIPPED {@link validateCapturedTraffic} — the api-runner analogue of the browser\n * pillar's `driveBrowserFlowToHar` (5e). Unlike `har-synth.ts` this is NOT a pure leaf\n * (it imports the runner), so it lives in its own module.\n *\n * \"Absence is never a pass\" — TRANSPORT completeness is enforced HERE by THROWING\n * (⇒ the verify thunk rejects ⇒ inconclusive, mirroring `driveBrowserFlowToHar`): a\n * withheld/dry-run/blocked request, a non-sent step in a sequence, or a truncated\n * redirect chain never yields a validatable HAR. CONTRACT completeness (the verdict's\n * `clean` flag) is folded to inconclusive downstream by `@sackville-mcp/verdict`\n * `fromCaptureVerdict` (slice 6) — this driver returns the FULL verdict so that fold can.\n *\n * Redaction: the driver folds the run-resolved `{{secret:NAME}}` pairs (off the runner's\n * out-of-band channel) into the caller's union redactor BEFORE synthesizing or\n * validating, and {@link synthesizeRedactedHarZip} re-redacts at store time — so no raw\n * secret reaches the stored artifact or the findings.\n */\nimport { randomUUID } from 'node:crypto'\nimport type { CaptureContract, CaptureContractVerdict } from './har-capture.js'\nimport { validateCapturedTraffic } from './har-capture.js'\nimport { type HarHopRecord, synthesizeRedactedHarZip } from './har-synth.js'\nimport type { Collection } from './model.js'\nimport { type HarCapture, type RunOptions, runRequestForHar } from './runner.js'\nimport type { Redactor } from './secrets.js'\nimport { runSequenceForHar, type SequenceOptions } from './sequence.js'\n\n/** The minimal artifact store the driver writes the redacted HAR to — satisfied by the\n * verify-prefix `@sackville-mcp/artifacts` `ArtifactStore` (kept structural so `@sackville-mcp/api`\n * needn't depend on `@sackville-mcp/artifacts`). */\nexport interface HarArtifactSink {\n put(runId: string, kind: string, body: string | Buffer, contentType: string): string\n}\n\n/** Compact HAR summary (shape-compatible with `@sackville-mcp/browser` `HarSummary`). */\nexport interface ProducedHarSummary {\n handle: string\n byteSize: number\n entryCount: number\n byStatus: Record<string, number>\n byMethod: Record<string, number>\n}\n\nexport interface ProducedHar {\n /** `<store-prefix>://<id>/har` — the redacted, stored HAR archive, by handle. */\n harHandle: string\n summary: ProducedHarSummary\n /** The FULL contract verdict (incl. `clean`/`noSignal`/`unresolvedBodies`) so the\n * downstream fold can hold \"absence is never a pass\" on the contract dimension. */\n verdict: CaptureContractVerdict\n}\n\nexport interface HarProduceDeps {\n store: HarArtifactSink\n /** The union redactor (verify ∪ api seed); the driver folds in the run-resolved\n * secrets and uses it at BOTH chokepoints (synthesize + validate). */\n redactor: Redactor\n contract: CaptureContract\n validate?: { baseDir?: string; allowedOrigins?: string[] }\n idFactory?: () => string\n /** Injected so the gate suite needn't fetch. */\n runForHar?: typeof runRequestForHar\n runSequenceForHar?: typeof runSequenceForHar\n}\n\nfunction countsFromRecords(hops: HarHopRecord[]): Omit<ProducedHarSummary, 'handle' | 'byteSize'> {\n const byStatus: Record<string, number> = {}\n const byMethod: Record<string, number> = {}\n for (const h of hops) {\n byStatus[String(h.status)] = (byStatus[String(h.status)] ?? 0) + 1\n byMethod[h.method] = (byMethod[h.method] ?? 0) + 1\n }\n return { entryCount: hops.length, byStatus, byMethod }\n}\n\n/** Synthesize → redact → store → validate, after the transport guards have passed.\n * The caller has already folded the run-resolved secrets into the union redactor. */\nfunction finishProduce(capture: HarCapture, deps: HarProduceDeps): ProducedHar {\n if (capture.redirectTruncated) {\n throw new Error(\n 'captured traffic did not complete its redirect chain (terminal status was a redirect)',\n )\n }\n const redact = (v: string) => deps.redactor.redact(v)\n const zip = synthesizeRedactedHarZip(capture.hops, redact)\n const id = (deps.idFactory ?? randomUUID)()\n const handle = deps.store.put(id, 'har', zip, 'application/zip')\n const verdict = validateCapturedTraffic(zip, deps.contract, {\n redact,\n baseDir: deps.validate?.baseDir,\n allowedOrigins: deps.validate?.allowedOrigins,\n })\n return {\n harHandle: handle,\n summary: { handle, byteSize: zip.byteLength, ...countsFromRecords(capture.hops) },\n verdict,\n }\n}\n\n/** Drive ONE request → synthesize + validate its HAR. Throws (⇒ inconclusive) when the\n * request was not sent (withheld/dry-run/blocked) or its redirect chain was truncated. */\nexport async function runRequestToHar(\n collection: Collection,\n name: string,\n opts: RunOptions,\n deps: HarProduceDeps,\n): Promise<ProducedHar> {\n const { result, capture } = await (deps.runForHar ?? runRequestForHar)(collection, name, opts)\n // Fold run secrets first so a thrown reason can be scrubbed.\n for (const s of capture.registeredSecrets) deps.redactor.register(s.name, s.value)\n if (result.sent !== true) {\n throw new Error(\n `captured request \"${name}\" was not sent (${deps.redactor.redact(result.reason ?? 'withheld')})`,\n )\n }\n return finishProduce(capture, deps)\n}\n\n/** Drive a SEQUENCE → synthesize + validate the aggregated HAR. Throws (⇒ inconclusive)\n * when ANY step was not sent (per `step.result.sent`) or any hop truncated a redirect. */\nexport async function runSequenceToHar(\n collection: Collection,\n names: string[],\n opts: SequenceOptions,\n deps: HarProduceDeps,\n): Promise<ProducedHar> {\n const { result, capture } = await (deps.runSequenceForHar ?? runSequenceForHar)(\n collection,\n names,\n opts,\n )\n for (const s of capture.registeredSecrets) deps.redactor.register(s.name, s.value)\n const unsent = result.steps.find((s) => s.result.sent !== true)\n if (unsent) {\n throw new Error(\n `captured sequence step \"${unsent.name}\" was not sent (${deps.redactor.redact(unsent.result.reason ?? 'withheld')})`,\n )\n }\n return finishProduce(capture, deps)\n}\n","/**\n * Import foreign API-collection formats into a Bruno `.bru` collection on disk.\n *\n * Supported sources: **Postman** (v2.1 collection), **Insomnia** (v4 export),\n * **OpenAPI** (3.x — one request per operation, + an environment for the server\n * URL), and **HAR** (one request per logged entry). Each is normalized to a small\n * intermediate shape and serialized with `@usebruno/lang`'s `jsonToBruV2`, so the\n * output is a real Bruno collection that `loadCollection` reads back.\n *\n * Scope: method, URL, headers, and the common body types (json/text/xml +\n * form-urlencoded + graphql). multipart/file bodies are noted but not emitted\n * (no portable on-disk file to point at); auth blocks beyond a bearer/`{{var}}`\n * header are left to the operator. `{{var}}` templating passes through unchanged\n * (Postman/Bruno share the syntax).\n */\nimport { mkdirSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { envJsonToBruV2, jsonToBruV2 } from '@usebruno/lang'\nimport { parse as parseYaml } from 'yaml'\n\nexport type ImportFormat = 'postman' | 'insomnia' | 'openapi' | 'har'\n\n/** Normalized request, format-agnostic. */\nexport interface ImportedRequest {\n name: string\n method: string\n url: string\n headers: { name: string; value: string }[]\n body?: ImportedBody\n}\n\nexport interface ImportedBody {\n /** Canonical body type: json | text | xml | form-urlencoded | graphql. */\n type: string\n /** Raw content (json/text/xml). */\n content?: string\n /** form-urlencoded params. */\n params?: { name: string; value: string }[]\n /** graphql query + variables. */\n graphql?: { query: string; variables?: string }\n}\n\nexport interface ImportResult {\n requests: ImportedRequest[]\n /** A discovered environment (e.g. OpenAPI `servers[0]`), if any. */\n environment?: { name: string; variables: Record<string, string> }\n}\n\n// ---------------------------------------------------------------------------\n// Source parsers\n// ---------------------------------------------------------------------------\n\ninterface NameValue {\n name?: string\n key?: string\n value?: string\n disabled?: boolean\n enabled?: boolean\n}\n\nfunction headersFrom(list: NameValue[] | undefined): { name: string; value: string }[] {\n return (list ?? [])\n .filter((h) => h.disabled !== true && h.enabled !== false)\n .map((h) => ({ name: h.name ?? h.key ?? '', value: h.value ?? '' }))\n .filter((h) => h.name)\n}\n\n/** Postman v2.1 collection → requests (folders flattened, depth-first). */\nexport function importPostman(doc: unknown): ImportResult {\n const root = doc as { item?: unknown[] }\n const requests: ImportedRequest[] = []\n\n const walk = (items: unknown[] | undefined): void => {\n for (const raw of items ?? []) {\n const item = raw as { name?: string; item?: unknown[]; request?: unknown }\n if (item.item) {\n walk(item.item) // folder\n continue\n }\n if (!item.request) continue\n const req = item.request as {\n method?: string\n header?: NameValue[]\n url?: string | { raw?: string }\n body?: PostmanBody\n }\n const url = typeof req.url === 'string' ? req.url : (req.url?.raw ?? '')\n requests.push({\n name: item.name ?? `${req.method ?? 'GET'} ${url}`,\n method: (req.method ?? 'GET').toUpperCase(),\n url,\n headers: headersFrom(req.header),\n body: postmanBody(req.body),\n })\n }\n }\n walk(root.item)\n return { requests }\n}\n\ninterface PostmanBody {\n mode?: string\n raw?: string\n urlencoded?: NameValue[]\n graphql?: { query?: string; variables?: string }\n options?: { raw?: { language?: string } }\n}\n\nfunction postmanBody(body: PostmanBody | undefined): ImportedBody | undefined {\n if (!body?.mode) return undefined\n if (body.mode === 'raw') {\n const lang = body.options?.raw?.language\n const type = lang === 'json' || lang === 'xml' ? lang : 'text'\n return { type, content: body.raw ?? '' }\n }\n if (body.mode === 'urlencoded') {\n return { type: 'form-urlencoded', params: kvParams(body.urlencoded) }\n }\n if (body.mode === 'graphql') {\n return {\n type: 'graphql',\n graphql: { query: body.graphql?.query ?? '', variables: body.graphql?.variables },\n }\n }\n return undefined // formdata/file: not portable on import\n}\n\nfunction kvParams(list: NameValue[] | undefined): { name: string; value: string }[] {\n return (list ?? [])\n .filter((p) => p.disabled !== true && p.enabled !== false)\n .map((p) => ({ name: p.name ?? p.key ?? '', value: p.value ?? '' }))\n}\n\n/** Insomnia v4 export → requests. */\nexport function importInsomnia(doc: unknown): ImportResult {\n const resources = (doc as { resources?: unknown[] }).resources ?? []\n const requests: ImportedRequest[] = []\n for (const raw of resources) {\n const r = raw as {\n _type?: string\n name?: string\n method?: string\n url?: string\n headers?: NameValue[]\n body?: { mimeType?: string; text?: string; params?: NameValue[] }\n }\n if (r._type !== 'request') continue\n requests.push({\n name: r.name ?? `${r.method ?? 'GET'} ${r.url ?? ''}`,\n method: (r.method ?? 'GET').toUpperCase(),\n url: r.url ?? '',\n headers: headersFrom(r.headers),\n body: insomniaBody(r.body),\n })\n }\n return { requests }\n}\n\nfunction insomniaBody(\n body: { mimeType?: string; text?: string; params?: NameValue[] } | undefined,\n): ImportedBody | undefined {\n if (!body?.mimeType) return undefined\n if (body.mimeType.includes('json')) return { type: 'json', content: body.text ?? '' }\n if (body.mimeType.includes('xml')) return { type: 'xml', content: body.text ?? '' }\n if (body.mimeType.includes('x-www-form-urlencoded')) {\n return { type: 'form-urlencoded', params: kvParams(body.params) }\n }\n if (body.text) return { type: 'text', content: body.text }\n return undefined\n}\n\nconst HTTP_METHODS = new Set(['get', 'put', 'post', 'delete', 'patch', 'head', 'options', 'trace'])\n\n/** OpenAPI 3.x → one request per operation + an environment for the server URL. */\nexport function importOpenApi(doc: unknown): ImportResult {\n const spec = doc as {\n paths?: Record<string, Record<string, unknown>>\n servers?: { url?: string }[]\n }\n const requests: ImportedRequest[] = []\n for (const [path, item] of Object.entries(spec.paths ?? {})) {\n if (!item || typeof item !== 'object') continue\n for (const [method, op] of Object.entries(item)) {\n if (!HTTP_METHODS.has(method.toLowerCase())) continue\n const operation = op as { operationId?: string; requestBody?: OpenApiRequestBody }\n requests.push({\n name: operation.operationId ?? `${method.toUpperCase()} ${path}`,\n method: method.toUpperCase(),\n url: `{{baseUrl}}${path}`,\n headers: [],\n body: openApiBody(operation.requestBody),\n })\n }\n }\n const serverUrl = spec.servers?.[0]?.url\n const environment = serverUrl\n ? { name: 'Imported', variables: { baseUrl: serverUrl } }\n : undefined\n return { requests, environment }\n}\n\ninterface OpenApiRequestBody {\n content?: Record<string, { example?: unknown; schema?: unknown }>\n}\n\nfunction openApiBody(rb: OpenApiRequestBody | undefined): ImportedBody | undefined {\n const json = rb?.content?.['application/json']\n if (!json) return undefined\n // Prefer a provided example; otherwise an empty JSON object stub.\n const example = json.example ?? {}\n return { type: 'json', content: JSON.stringify(example, null, 2) }\n}\n\n/** HAR → one request per logged entry. */\nexport function importHar(doc: unknown): ImportResult {\n const entries = (doc as { log?: { entries?: unknown[] } }).log?.entries ?? []\n const requests: ImportedRequest[] = []\n entries.forEach((raw, i) => {\n const req = (raw as { request?: unknown }).request as\n | {\n method?: string\n url?: string\n headers?: NameValue[]\n postData?: { mimeType?: string; text?: string; params?: NameValue[] }\n }\n | undefined\n if (!req) return\n let label = req.url ?? ''\n try {\n label = new URL(req.url ?? '').pathname\n } catch {}\n requests.push({\n name: `${(req.method ?? 'GET').toUpperCase()} ${label} #${i + 1}`,\n method: (req.method ?? 'GET').toUpperCase(),\n url: req.url ?? '',\n headers: headersFrom(req.headers),\n body: insomniaBody(req.postData), // same {mimeType,text,params} shape\n })\n })\n return { requests }\n}\n\nconst PARSERS: Record<ImportFormat, (doc: unknown) => ImportResult> = {\n postman: importPostman,\n insomnia: importInsomnia,\n openapi: importOpenApi,\n har: importHar,\n}\n\n/** Parse a source document (JSON, or YAML for OpenAPI) into normalized requests. */\nexport function parseImport(format: ImportFormat, source: string): ImportResult {\n const doc = format === 'openapi' ? parseYaml(source) : JSON.parse(source)\n return PARSERS[format](doc)\n}\n\n// ---------------------------------------------------------------------------\n// .bru serialization\n// ---------------------------------------------------------------------------\n\n/** Map our canonical body type to the `@usebruno/lang` discriminator + payload. */\nfunction bruBody(body: ImportedBody): { discriminator: string; body: Record<string, unknown> } {\n if (body.type === 'form-urlencoded') {\n return {\n discriminator: 'formUrlEncoded',\n body: {\n formUrlEncoded: (body.params ?? []).map((p) => ({ ...p, enabled: true })),\n },\n }\n }\n if (body.type === 'graphql') {\n return {\n discriminator: 'graphql',\n body: { graphql: { query: body.graphql?.query ?? '', variables: body.graphql?.variables } },\n }\n }\n // raw types\n return { discriminator: body.type, body: { [body.type]: body.content ?? '' } }\n}\n\nfunction toBruJson(req: ImportedRequest, seq: number): Record<string, unknown> {\n const http: Record<string, unknown> = {\n method: req.method.toLowerCase(),\n url: req.url,\n auth: 'none',\n }\n let body: Record<string, unknown> = {}\n if (req.body) {\n const mapped = bruBody(req.body)\n http.body = mapped.discriminator\n body = mapped.body\n }\n return {\n meta: { name: req.name, type: 'http', seq },\n http,\n headers: req.headers.map((h) => ({ ...h, enabled: true })),\n body,\n }\n}\n\n/** Sanitize a request name into a unique `.bru` filename stem. */\nfunction fileStem(name: string, used: Set<string>): string {\n const base =\n name\n .replace(/[^\\w.-]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 80) || 'request'\n let stem = base\n let n = 2\n while (used.has(stem)) stem = `${base}-${n++}`\n used.add(stem)\n return stem\n}\n\nexport interface WriteOptions {\n /** Collection name written to `bruno.json`. */\n name?: string\n}\n\n/**\n * Write a normalized import to `destDir` as a Bruno collection: `bruno.json`, a\n * `<name>.bru` per request, and (if present) an `environments/<env>.bru`. Returns\n * the request count written.\n */\nexport function writeImported(\n destDir: string,\n result: ImportResult,\n opts: WriteOptions = {},\n): number {\n mkdirSync(destDir, { recursive: true })\n writeFileSync(\n join(destDir, 'bruno.json'),\n `${JSON.stringify({ version: '1', name: opts.name ?? 'imported', type: 'collection' }, null, 2)}\\n`,\n )\n\n const used = new Set<string>()\n result.requests.forEach((req, i) => {\n const stem = fileStem(req.name, used)\n writeFileSync(join(destDir, `${stem}.bru`), jsonToBruV2(toBruJson(req, i + 1)))\n })\n\n if (result.environment) {\n mkdirSync(join(destDir, 'environments'), { recursive: true })\n const variables = Object.entries(result.environment.variables).map(([name, value]) => ({\n name,\n value,\n enabled: true,\n }))\n writeFileSync(\n join(destDir, 'environments', `${fileStem(result.environment.name, new Set())}.bru`),\n envJsonToBruV2({ variables }),\n )\n }\n return result.requests.length\n}\n\n/** One-shot: parse a source document and write the Bruno collection to disk. */\nexport function importToCollection(\n format: ImportFormat,\n source: string,\n destDir: string,\n opts: WriteOptions = {},\n): number {\n return writeImported(destDir, parseImport(format, source), opts)\n}\n"],"mappings":"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"}