@apicircle/mock-server-core 1.0.8 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/parsers/openapi.ts","../src/faker/schemaToExample.ts","../src/parsers/buildEndpoint.ts","../src/parsers/postman.ts","../src/parsers/insomnia.ts","../src/handlers/buildRouter.ts","../src/cors.ts","../src/validation/evaluate.ts","../src/rules/evaluate.ts","../src/response/applyMultipliers.ts","../src/runtime/nodeAdapter.ts","../src/runtime/portFinder.ts","../src/index.ts"],"sourcesContent":["// OpenAPI / Swagger 2.0 → MockEndpoint[] parser.\n//\n// Two-step pipeline:\n// 1. Parse the source string (JSON or YAML) and run swagger-parser's\n// `dereference` so all `$ref` chains are resolved up-front. The mock\n// server doesn't carry a $ref resolver at runtime — every endpoint\n// ships a self-contained body.\n// 2. Walk `paths.{path}.{method}.responses.{status}.content.{mediaType}`\n// and pull either an `example`, the first `examples` entry, or\n// synthesize one from the schema via `schemaToExample`.\n//\n// We pick the lowest 2xx response when multiple are present (200 wins\n// over 201; if neither, take the first 2xx). Errors and 5xx are ignored\n// — mock servers should default to the success path; users override via\n// the editor when they want failure cases.\n\nimport SwaggerParser from '@apidevtools/swagger-parser';\nimport yaml from 'js-yaml';\nimport type { HttpMethod, MockEndpoint } from '@apicircle/shared';\nimport { schemaToExample, type JsonSchemaLike } from '../faker/schemaToExample';\nimport { buildMockEndpoint } from './buildEndpoint';\n\nconst SUPPORTED_METHODS: ReadonlyArray<HttpMethod> = [\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'HEAD',\n 'OPTIONS',\n];\n\ninterface OpenApiOperation {\n operationId?: string;\n summary?: string;\n responses?: Record<string, OpenApiResponse>;\n // Swagger 2.0 carries `produces` here; we honor it as a fallback for\n // content-type when `responses[status].content` is absent.\n produces?: string[];\n}\n\ninterface OpenApiResponse {\n description?: string;\n content?: Record<\n string,\n { example?: unknown; examples?: Record<string, { value?: unknown }>; schema?: JsonSchemaLike }\n >;\n // Swagger 2.0\n schema?: JsonSchemaLike;\n examples?: Record<string, unknown>;\n headers?: Record<string, { schema?: JsonSchemaLike; example?: unknown }>;\n}\n\nexport interface ParseOpenApiOptions {\n /**\n * When the OpenAPI doc has multiple 2xx responses, this picks which one\n * becomes the mock. Default: the lowest numeric 2xx (200 wins over 201).\n */\n preferStatus?: number;\n}\n\nexport interface ParseOpenApiResult {\n endpoints: MockEndpoint[];\n warnings: string[];\n}\n\n/**\n * Parse an OpenAPI / Swagger 2.0 spec string and return the mock endpoint\n * table. `format` is a hint — the parser will fall back to JSON.parse if\n * YAML parse fails.\n */\nexport async function parseOpenApiToEndpoints(\n source: string,\n format: 'json' | 'yaml' = 'json',\n opts: ParseOpenApiOptions = {},\n): Promise<ParseOpenApiResult> {\n const warnings: string[] = [];\n\n const raw = format === 'yaml' ? safeYamlLoad(source) : safeJsonParse(source);\n if (!raw || typeof raw !== 'object') {\n return { endpoints: [], warnings: ['Could not parse OpenAPI source'] };\n }\n\n // SwaggerParser.dereference takes either a path or an in-memory object\n // and mutates `$ref` chains in place so downstream code can ignore refs\n // entirely. Cast through unknown — the SDK's types are narrower than we\n // need (they assume a path input and an `info` block).\n let api: Record<string, unknown>;\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const dereffed = await (SwaggerParser as any).dereference(raw);\n api = dereffed as Record<string, unknown>;\n } catch (err) {\n warnings.push(\n `swagger-parser failed: ${err instanceof Error ? err.message : 'unknown error'}; ` +\n 'falling back to raw spec',\n );\n api = raw as Record<string, unknown>;\n }\n\n const paths = (api.paths ?? {}) as Record<string, Record<string, OpenApiOperation>>;\n const endpoints: MockEndpoint[] = [];\n let endpointId = 0;\n\n for (const [path, ops] of Object.entries(paths)) {\n if (!ops || typeof ops !== 'object') continue;\n for (const method of Object.keys(ops)) {\n const upper = method.toUpperCase() as HttpMethod;\n if (!SUPPORTED_METHODS.includes(upper)) continue;\n const op = ops[method];\n if (!op || typeof op !== 'object') continue;\n\n const built = buildEndpointFromOp(path, upper, op, opts, warnings, endpointId++);\n if (built) endpoints.push(built);\n }\n }\n\n return { endpoints, warnings };\n}\n\nfunction buildEndpointFromOp(\n path: string,\n method: HttpMethod,\n op: OpenApiOperation,\n opts: ParseOpenApiOptions,\n warnings: string[],\n index: number,\n): MockEndpoint | null {\n const responses = op.responses ?? {};\n const candidates = Object.keys(responses)\n .filter((code) => /^2\\d\\d$/.test(code))\n .map((code) => Number(code));\n if (candidates.length === 0) {\n warnings.push(`No 2xx response defined for ${method} ${path} — skipping`);\n return null;\n }\n const status = opts.preferStatus\n ? candidates.includes(opts.preferStatus)\n ? opts.preferStatus\n : Math.min(...candidates)\n : Math.min(...candidates);\n const response = responses[String(status)];\n if (!response) {\n warnings.push(`Response ${status} missing for ${method} ${path}`);\n return null;\n }\n\n const { contentType, body, exampleName } = pickResponsePayload(response, op);\n\n const headers = pickResponseHeaders(response, contentType);\n\n return buildMockEndpoint({\n id: `op-${index}-${method.toLowerCase()}-${slug(path)}`,\n method,\n pathPattern: path,\n example: exampleName,\n response: { status, headers, body },\n });\n}\n\nfunction pickResponsePayload(\n response: OpenApiResponse,\n op: OpenApiOperation,\n): { contentType: string; body: string; exampleName: string | undefined } {\n // OpenAPI 3.x: `response.content` is keyed by media type.\n if (response.content) {\n const mediaTypes = Object.keys(response.content);\n const preferred =\n mediaTypes.find((m) => m.toLowerCase().includes('json')) ??\n mediaTypes[0] ??\n 'application/json';\n const entry = response.content[preferred];\n if (entry) {\n if (entry.example !== undefined) {\n return {\n contentType: preferred,\n body: stringifyForContentType(entry.example, preferred),\n exampleName: undefined,\n };\n }\n if (entry.examples) {\n const firstExampleName = Object.keys(entry.examples)[0];\n if (firstExampleName) {\n const v = entry.examples[firstExampleName];\n return {\n contentType: preferred,\n body: stringifyForContentType(v?.value, preferred),\n exampleName: firstExampleName,\n };\n }\n }\n if (entry.schema) {\n return {\n contentType: preferred,\n body: stringifyForContentType(schemaToExample(entry.schema), preferred),\n exampleName: undefined,\n };\n }\n }\n }\n\n // Swagger 2.0 fallback.\n if (response.schema) {\n const ct = (op.produces && op.produces[0]) ?? 'application/json';\n return {\n contentType: ct,\n body: stringifyForContentType(schemaToExample(response.schema), ct),\n exampleName: undefined,\n };\n }\n if (response.examples) {\n const firstName = Object.keys(response.examples)[0];\n if (firstName) {\n const v = response.examples[firstName];\n return {\n contentType: firstName,\n body: stringifyForContentType(v, firstName),\n exampleName: firstName,\n };\n }\n }\n\n return {\n contentType: 'application/json',\n body: '{}',\n exampleName: undefined,\n };\n}\n\ntype ParsedHeader = { key: string; value: string };\n\nfunction pickResponseHeaders(response: OpenApiResponse, contentType: string): ParsedHeader[] {\n const headers: ParsedHeader[] = [{ key: 'Content-Type', value: contentType }];\n if (response.headers) {\n for (const [name, def] of Object.entries(response.headers)) {\n if (name.toLowerCase() === 'content-type') continue;\n const value = def.example !== undefined ? def.example : schemaToExample(def.schema);\n if (value === undefined || value === null) continue;\n // Header values must be strings. Strings pass through; everything\n // else gets JSON-encoded — covers objects/arrays/numbers/booleans\n // without ever falling back to \"[object Object]\".\n const text = typeof value === 'string' ? value : JSON.stringify(value);\n headers.push({ key: name, value: text });\n }\n }\n return headers;\n}\n\nfunction stringifyForContentType(value: unknown, contentType: string): string {\n if (value === undefined || value === null) return '';\n if (typeof value === 'string') return value;\n if (contentType.toLowerCase().includes('json')) {\n return JSON.stringify(value, null, 2);\n }\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n return JSON.stringify(value);\n}\n\nfunction slug(s: string): string {\n return (\n s\n .replace(/[^a-z0-9]+/gi, '-')\n .replace(/^-|-$/g, '')\n .toLowerCase() || 'root'\n );\n}\n\nfunction safeJsonParse(s: string): unknown {\n try {\n return JSON.parse(s);\n } catch {\n return null;\n }\n}\n\nfunction safeYamlLoad(s: string): unknown {\n try {\n return yaml.load(s);\n } catch {\n return safeJsonParse(s);\n }\n}\n","// Minimal JSON Schema → example value generator. Used when an OpenAPI\n// operation has no `example` / `examples` map, but the response body's\n// schema is defined. Handles the common cases:\n//\n// • primitives (string, number, integer, boolean, null) — picks a\n// plausible default per `format` when present\n// • arrays — single-element with the items schema sampled\n// • objects — every required property; falls back to all properties\n// when `required` is missing\n// • enums — first value\n// • const — verbatim\n// • allOf / oneOf / anyOf — first branch\n//\n// Doesn't try to be a full faker — the goal is \"realistic enough for a\n// developer testing happy paths\", not exhaustive boundary cases.\n\nexport interface JsonSchemaLike {\n type?: string | string[];\n format?: string;\n enum?: unknown[];\n const?: unknown;\n default?: unknown;\n example?: unknown;\n properties?: Record<string, JsonSchemaLike>;\n required?: string[];\n items?: JsonSchemaLike;\n allOf?: JsonSchemaLike[];\n oneOf?: JsonSchemaLike[];\n anyOf?: JsonSchemaLike[];\n}\n\nconst FORMAT_DEFAULTS: Record<string, string> = {\n 'date-time': '2026-04-27T00:00:00.000Z',\n date: '2026-04-27',\n time: '00:00:00',\n email: 'user@example.com',\n hostname: 'example.com',\n ipv4: '127.0.0.1',\n ipv6: '::1',\n uri: 'https://example.com',\n url: 'https://example.com',\n uuid: '00000000-0000-4000-8000-000000000000',\n byte: 'AA==',\n binary: '',\n};\n\nexport function schemaToExample(schema: JsonSchemaLike | undefined): unknown {\n if (!schema) return null;\n\n // Explicit example / default / const win in that order.\n if (schema.example !== undefined) return schema.example;\n if (schema.default !== undefined) return schema.default;\n if (schema.const !== undefined) return schema.const;\n\n if (Array.isArray(schema.enum) && schema.enum.length > 0) {\n return schema.enum[0];\n }\n\n // Compositors: pick the first branch.\n const branch = schema.allOf?.[0] ?? schema.oneOf?.[0] ?? schema.anyOf?.[0];\n if (branch) return schemaToExample(branch);\n\n // Type can be a single string or an array; pick the first non-null.\n const type = pickType(schema.type);\n\n switch (type) {\n case 'string':\n return schema.format ? (FORMAT_DEFAULTS[schema.format] ?? 'string') : 'string';\n case 'integer':\n return 0;\n case 'number':\n return 0;\n case 'boolean':\n return false;\n case 'null':\n return null;\n case 'array': {\n const items = schema.items ? schemaToExample(schema.items) : null;\n return [items];\n }\n case 'object':\n default: {\n const properties = schema.properties ?? {};\n const required = schema.required ?? Object.keys(properties);\n const out: Record<string, unknown> = {};\n for (const key of required) {\n const propSchema = properties[key];\n out[key] = schemaToExample(propSchema);\n }\n return out;\n }\n }\n}\n\nfunction pickType(type: string | string[] | undefined): string | undefined {\n if (!type) return undefined;\n if (typeof type === 'string') return type;\n // Prefer non-null types so the example isn't trivially `null`.\n return type.find((t) => t !== 'null') ?? type[0];\n}\n","// Helpers shared by every parser (OpenAPI / Postman / Insomnia) that wrap\n// the legacy \"flat\" parsed shape (status / headers / body string) into the\n// current `MockEndpoint` schema (defaultResponse + responseRules + validation).\n//\n// Parsers stay agnostic about validation / response rules — those are\n// authoring-time concerns. They emit endpoints with empty `requestValidation`\n// and `responseRules` and a single `defaultResponse` that holds the parsed\n// 2xx (OpenAPI) / first example (Postman/Insomnia) payload.\n\nimport type {\n HttpMethod,\n MockEndpoint,\n MockResponseBody,\n MockResponseBodyType,\n MockResponseConfig,\n} from '@apicircle/shared';\n\nexport interface ParsedResponseShape {\n status: number;\n /** Wire-shape headers — `enabled` is added when wrapping into the endpoint. */\n headers: Array<{ key: string; value: string }>;\n body: string;\n /** Optional artificial latency. */\n delayMs?: number;\n}\n\nexport interface BuildEndpointInput {\n id: string;\n /** User-friendly label; defaults to \"{METHOD} {pathPattern}\" when omitted. */\n name?: string;\n method: HttpMethod;\n pathPattern: string;\n description?: string;\n example?: string;\n response: ParsedResponseShape;\n}\n\nfunction bodyTypeForContentType(contentType: string | undefined): MockResponseBodyType {\n if (!contentType) return 'json';\n const main = contentType.toLowerCase().split(';')[0]?.trim() ?? '';\n if (main.includes('json')) return 'json';\n if (main.includes('xml')) return 'xml';\n if (main === 'application/x-www-form-urlencoded') return 'urlencoded';\n if (main === 'multipart/form-data') return 'form-data';\n if (main === 'application/octet-stream') return 'binary';\n if (main.startsWith('text/')) return 'text';\n return 'text';\n}\n\nfunction bodyFromString(content: string, type: MockResponseBodyType): MockResponseBody {\n switch (type) {\n case 'none':\n return { type: 'none', content: '' };\n case 'binary':\n return { type: 'binary', content: '' };\n case 'form-data':\n return { type: 'form-data', content: '', formRows: [] };\n default:\n return { type, content };\n }\n}\n\n/** Wrap a flat status/headers/body parse into a `MockResponseConfig`. */\nfunction buildMockResponse(parsed: ParsedResponseShape): MockResponseConfig {\n const contentType = parsed.headers.find((h) => h.key.toLowerCase() === 'content-type')?.value;\n const bodyType = bodyTypeForContentType(contentType);\n return {\n status: parsed.status,\n headers: parsed.headers.map((h) => ({ ...h, enabled: true })),\n body: bodyFromString(parsed.body, bodyType),\n ...(parsed.delayMs !== undefined ? { delayMs: parsed.delayMs } : {}),\n };\n}\n\n/** Compose a new `MockEndpoint` with sensible empty defaults for the rest. */\nexport function buildMockEndpoint(input: BuildEndpointInput): MockEndpoint {\n return {\n id: input.id,\n name: input.name ?? `${input.method} ${input.pathPattern}`,\n method: input.method,\n pathPattern: input.pathPattern,\n description: input.description,\n requestSchema: { pathParams: [], queryParams: [], headers: [], cookies: [] },\n requestValidation: [],\n responseRules: [],\n defaultResponse: buildMockResponse(input.response),\n example: input.example,\n };\n}\n","// Postman v2.1 collection → MockEndpoint[].\n//\n// Postman's collection JSON has a recursive `item[]` structure where each\n// item is either:\n// • a folder: `{ name, item: [...] }`\n// • a request: `{ name, request: {...}, response?: [...] }`\n//\n// For mocking, the most useful payload is `response[]` — Postman lets\n// users save example responses against each request. We pull the first\n// response from each request that has any. When a request has no saved\n// example, we synthesize a 200 with an empty JSON body.\n\nimport type { HttpMethod, MockEndpoint } from '@apicircle/shared';\nimport { buildMockEndpoint } from './buildEndpoint';\n\ninterface PostmanCollection {\n info?: { name?: string; schema?: string };\n item?: PostmanItem[];\n}\n\ninterface PostmanItem {\n name?: string;\n item?: PostmanItem[]; // folder\n request?: PostmanRequest;\n response?: PostmanResponse[];\n}\n\ninterface PostmanRequest {\n method?: string;\n url?: string | { raw?: string; path?: string[] | string };\n header?: Array<{ key: string; value: string }>;\n body?: { raw?: string; mode?: string };\n}\n\ninterface PostmanResponse {\n name?: string;\n status?: string;\n code?: number;\n header?: Array<{ key: string; value: string }>;\n body?: string;\n _postman_previewlanguage?: string;\n}\n\nconst SUPPORTED_METHODS: ReadonlyArray<HttpMethod> = [\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'HEAD',\n 'OPTIONS',\n];\n\nexport interface ParsePostmanResult {\n endpoints: MockEndpoint[];\n warnings: string[];\n}\n\nexport function parsePostmanToEndpoints(source: string): ParsePostmanResult {\n const warnings: string[] = [];\n let parsed: PostmanCollection;\n try {\n parsed = JSON.parse(source) as PostmanCollection;\n } catch {\n return { endpoints: [], warnings: ['Could not parse Postman collection JSON'] };\n }\n\n const endpoints: MockEndpoint[] = [];\n let endpointId = 0;\n walkItems(parsed.item ?? [], (item) => {\n if (!item.request) return;\n const method = (item.request.method ?? 'GET').toUpperCase() as HttpMethod;\n if (!SUPPORTED_METHODS.includes(method)) {\n warnings.push(`Skipping ${method} (unsupported method): ${item.name ?? '(unnamed)'}`);\n return;\n }\n const path = extractPath(item.request.url);\n if (!path) {\n warnings.push(`Skipping request with no extractable path: ${item.name ?? '(unnamed)'}`);\n return;\n }\n\n // First saved response wins. Postman stores examples in\n // `response[]` — a request without saved examples falls through to\n // the synthesized default below.\n const example = item.response?.[0];\n if (example) {\n endpoints.push(\n buildMockEndpoint({\n id: `pm-${endpointId++}-${slug(path)}`,\n name: item.name,\n method,\n pathPattern: path,\n example: example.name,\n response: {\n // Postman's `code` is the canonical numeric status; `status` is a\n // human-readable label that *sometimes* parses as a number. Try\n // both, fall back to 200 only when neither yields a finite number.\n status:\n example.code ??\n (Number.isFinite(Number(example.status)) ? Number(example.status) : 200),\n headers: (example.header ?? []).map((h) => ({ key: h.key, value: h.value })),\n body: example.body ?? '',\n },\n }),\n );\n } else {\n endpoints.push(\n buildMockEndpoint({\n id: `pm-${endpointId++}-${slug(path)}`,\n name: item.name,\n method,\n pathPattern: path,\n response: {\n status: 200,\n headers: [{ key: 'Content-Type', value: 'application/json' }],\n body: '{}',\n },\n }),\n );\n }\n });\n\n return { endpoints, warnings };\n}\n\nfunction walkItems(items: PostmanItem[], visit: (item: PostmanItem) => void): void {\n for (const item of items) {\n if (item.item) walkItems(item.item, visit);\n else if (item.request) visit(item);\n }\n}\n\nfunction extractPath(url: PostmanRequest['url']): string | null {\n if (!url) return null;\n if (typeof url === 'string') {\n return urlToPath(url);\n }\n if (url.raw) return urlToPath(url.raw);\n if (url.path) {\n const segments = Array.isArray(url.path) ? url.path : [url.path];\n return '/' + segments.filter(Boolean).join('/');\n }\n return null;\n}\n\nfunction urlToPath(raw: string): string | null {\n // Postman often stores absolute URLs (e.g. https://api.example.com/users).\n // The mock server cares about the path only.\n try {\n const parsed = new URL(raw.replace(/^https?:\\/\\/[^/]*$/, raw + '/'));\n return parsed.pathname || '/';\n } catch {\n // Already a path or a template like {{baseUrl}}/users.\n const idx = raw.indexOf('/');\n return idx === -1 ? '/' : raw.slice(idx);\n }\n}\n\nfunction slug(s: string): string {\n return (\n s\n .replace(/[^a-z0-9]+/gi, '-')\n .replace(/^-|-$/g, '')\n .toLowerCase() || 'root'\n );\n}\n","// Insomnia v4 export → MockEndpoint[].\n//\n// Insomnia's export format is a flat `resources[]` array where each entry\n// has a `_type` discriminator (`request`, `request_group`, `environment`,\n// `workspace`). We only consume `_type === 'request'`.\n//\n// Insomnia doesn't ship saved-response examples, so every endpoint gets a\n// synthesized 200 with an empty JSON body. The user can override per-\n// endpoint via the editor.\n\nimport type { HttpMethod, MockEndpoint } from '@apicircle/shared';\nimport { buildMockEndpoint } from './buildEndpoint';\n\ninterface InsomniaExport {\n resources?: InsomniaResource[];\n}\n\ninterface InsomniaResource {\n _id?: string;\n _type?: string;\n name?: string;\n method?: string;\n url?: string;\n parentId?: string;\n}\n\nconst SUPPORTED_METHODS: ReadonlyArray<HttpMethod> = [\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'HEAD',\n 'OPTIONS',\n];\n\nexport interface ParseInsomniaResult {\n endpoints: MockEndpoint[];\n warnings: string[];\n}\n\nexport function parseInsomniaToEndpoints(source: string): ParseInsomniaResult {\n const warnings: string[] = [];\n let parsed: InsomniaExport;\n try {\n parsed = JSON.parse(source) as InsomniaExport;\n } catch {\n return { endpoints: [], warnings: ['Could not parse Insomnia export JSON'] };\n }\n\n const endpoints: MockEndpoint[] = [];\n let endpointId = 0;\n\n for (const r of parsed.resources ?? []) {\n if (r._type !== 'request') continue;\n const method = (r.method ?? 'GET').toUpperCase() as HttpMethod;\n if (!SUPPORTED_METHODS.includes(method)) {\n warnings.push(`Skipping ${method} (unsupported method): ${r.name ?? '(unnamed)'}`);\n continue;\n }\n const path = extractPath(r.url);\n if (!path) {\n warnings.push(`Skipping request with no path: ${r.name ?? '(unnamed)'}`);\n continue;\n }\n endpoints.push(\n buildMockEndpoint({\n id: `ins-${endpointId++}-${slug(path)}`,\n name: r.name,\n method,\n pathPattern: path,\n response: {\n status: 200,\n headers: [{ key: 'Content-Type', value: 'application/json' }],\n body: '{}',\n },\n }),\n );\n }\n\n return { endpoints, warnings };\n}\n\nfunction extractPath(url: string | undefined): string | null {\n if (!url) return null;\n try {\n return new URL(url).pathname || '/';\n } catch {\n const idx = url.indexOf('/');\n return idx === -1 ? '/' : url.slice(idx);\n }\n}\n\nfunction slug(s: string): string {\n return (\n s\n .replace(/[^a-z0-9]+/gi, '-')\n .replace(/^-|-$/g, '')\n .toLowerCase() || 'root'\n );\n}\n","// Build a Hono app from a MockServer's resolved endpoints.\n//\n// Path conversion: OpenAPI uses `{id}` for path params; Hono uses `:id`.\n// Translation is a single regex.\n//\n// Match precedence: more-specific routes first. Hono matches in\n// registration order, so we sort the endpoint list by path-specificity\n// (literal segments beat parameterised ones).\n//\n// Per-request pipeline:\n// request → evaluateValidation → evaluateResponseRules → applyMultipliers → respond\n//\n// The legacy `MockServer.overrides` map is intentionally NOT consulted\n// here — it was the pre-rules-redesign override layer; the new editor\n// produces `requestValidation` + `responseRules` + `defaultResponse`\n// instead.\n\nimport { Hono } from 'hono';\nimport type { Context } from 'hono';\nimport type { MockEndpoint, MockResponseConfig, MockServer } from '@apicircle/shared';\nimport { buildCors } from '../cors';\nimport { evaluateValidation } from '../validation/evaluate';\nimport { evaluateResponseRules, type RequestContext } from '../rules/evaluate';\nimport { applyMultipliers } from '../response/applyMultipliers';\n\nexport interface BuildRouterOptions {\n /** Called whenever a request hits a mock endpoint — used to tick\n * `MockRuntimeEntry.requestCount` from the host process. */\n onRequest?: (ctx: { endpointId: string; method: string; path: string }) => void;\n}\n\nexport function buildRouter(server: MockServer, opts: BuildRouterOptions = {}): Hono {\n const app = new Hono();\n\n const corsMiddleware = buildCors(server.cors);\n if (corsMiddleware) app.use('*', corsMiddleware);\n\n // Sort: more-specific routes register first. Endpoints without a `{`\n // param are strictly more specific than those with one.\n const sorted = [...server.endpoints].sort((a, b) => {\n const aHasParam = /\\{/.test(a.pathPattern);\n const bHasParam = /\\{/.test(b.pathPattern);\n if (aHasParam !== bHasParam) return aHasParam ? 1 : -1;\n // Then prefer longer paths (more segments).\n return b.pathPattern.length - a.pathPattern.length;\n });\n\n for (const endpoint of sorted) {\n const honoPath = openApiPathToHono(endpoint.pathPattern);\n const handler = makeHandler(endpoint, opts);\n switch (endpoint.method) {\n case 'GET':\n app.get(honoPath, handler);\n break;\n case 'POST':\n app.post(honoPath, handler);\n break;\n case 'PUT':\n app.put(honoPath, handler);\n break;\n case 'PATCH':\n app.patch(honoPath, handler);\n break;\n case 'DELETE':\n app.delete(honoPath, handler);\n break;\n case 'HEAD':\n case 'OPTIONS':\n app.on(endpoint.method, honoPath, handler);\n break;\n }\n }\n\n // 404 fallback — always JSON so curl users see a structured response.\n app.notFound((c) =>\n c.json(\n {\n error: 'No mock endpoint matches this path',\n method: c.req.method,\n path: new URL(c.req.url).pathname,\n },\n 404,\n ),\n );\n\n return app;\n}\n\nfunction makeHandler(endpoint: MockEndpoint, opts: BuildRouterOptions) {\n return async (c: Context) => {\n opts.onRequest?.({\n endpointId: endpoint.id,\n method: endpoint.method,\n path: endpoint.pathPattern,\n });\n\n const ctx = await buildRequestContext(c);\n\n // 1) Pre-validation gates fire first; the first failing rule wins.\n const failResponse = evaluateValidation(endpoint, ctx);\n if (failResponse) {\n return await respond(c, failResponse, ctx);\n }\n\n // 2) Conditional response rules — first matching rule wins, falling\n // through to defaultResponse otherwise.\n const matched = evaluateResponseRules(endpoint, ctx);\n return await respond(c, matched, ctx);\n };\n}\n\nasync function buildRequestContext(c: Context): Promise<RequestContext> {\n const url = new URL(c.req.url);\n const queryEntries = Array.from(url.searchParams.entries());\n // Use Object.create(null) so user-controlled keys like `__proto__` or\n // `constructor` can't shadow prototype members. Downstream rule evaluators\n // do property reads on these dicts; a polluted prototype would surprise them.\n const query: Record<string, string> = Object.create(null);\n for (const [k, v] of queryEntries) {\n // First value wins on repeated keys — mirrors Hono's `c.req.query()`\n // behavior and matches what most APIs treat as canonical.\n if (!(k in query)) query[k] = v;\n }\n const headers: Record<string, string> = Object.create(null);\n for (const [k, v] of c.req.raw.headers.entries()) {\n headers[k.toLowerCase()] = v;\n }\n // c.req.param() returns all path params for this matched route. Hono returns\n // a plain object; copy onto a null-prototype dict so consumers can't be\n // tripped by an attacker setting `__proto__` as a path-param name.\n const honoParams: Record<string, string> = c.req.param();\n const pathParams: Record<string, string> = Object.create(null);\n for (const k of Object.keys(honoParams)) {\n pathParams[k] = honoParams[k];\n }\n const cookies = parseCookieHeader(headers['cookie']);\n\n // Body parsing is best-effort: only attempt JSON parse when the\n // Content-Type advertises JSON. Other body types stay opaque (string)\n // because validation rules don't currently target them.\n let bodyJson: unknown = undefined;\n let bodyText = '';\n const ct = headers['content-type'] ?? '';\n if (ct.toLowerCase().includes('json')) {\n try {\n bodyText = await c.req.text();\n bodyJson = bodyText ? (JSON.parse(bodyText) as unknown) : undefined;\n } catch {\n // Malformed JSON — leave bodyJson undefined; validation rules that\n // require body presence will still see bodyText.\n }\n } else {\n try {\n bodyText = await c.req.text();\n } catch {\n // ignore\n }\n }\n\n return { query, pathParams, headers, cookies, bodyText, bodyJson };\n}\n\nfunction parseCookieHeader(cookieHeader: string | undefined): Record<string, string> {\n const out: Record<string, string> = Object.create(null);\n if (!cookieHeader) return out;\n for (const part of cookieHeader.split(';')) {\n const eq = part.indexOf('=');\n if (eq === -1) continue;\n const k = part.slice(0, eq).trim();\n const v = part.slice(eq + 1).trim();\n if (k && !(k in out)) out[k] = v;\n }\n return out;\n}\n\nasync function respond(\n c: Context,\n response: MockResponseConfig,\n ctx: RequestContext,\n): Promise<Response> {\n if (response.delayMs && response.delayMs > 0) {\n await new Promise((resolve) => setTimeout(resolve, response.delayMs));\n }\n\n const finalResponse = applyMultipliers(response, ctx);\n\n // Track whether the user-configured headers already pin Content-Type — if\n // they don't, we derive one from `body.type` so the browser can't MIME-sniff\n // a JSON/text body into HTML (XSS risk for any consumer that loads the\n // mock URL in an <iframe> or <script src>).\n let userSetContentType = false;\n for (const h of finalResponse.headers) {\n if (!h.enabled) continue;\n if (!h.key.trim()) continue;\n if (h.key.toLowerCase() === 'content-type') userSetContentType = true;\n c.header(h.key, h.value);\n }\n\n const body = finalResponse.body;\n if (!userSetContentType) {\n const defaultCt = defaultContentTypeFor(body.type);\n if (defaultCt) c.header('Content-Type', defaultCt);\n }\n // Belt-and-braces: tell browsers not to override the declared type. Without\n // this header, even a correct Content-Type can be sniffed away by old IE-\n // compatible heuristics in some Chromium edge cases.\n c.header('X-Content-Type-Options', 'nosniff');\n\n // No body / 204-style: respond with empty body and the configured status.\n if (body.type === 'none') {\n return c.body(null, finalResponse.status as 200);\n }\n if (body.type === 'binary' || body.type === 'form-data') {\n // The runtime doesn't materialize attachments yet — emit an empty body\n // so the headers + status still go out.\n return c.body(null, finalResponse.status as 200);\n }\n return c.body(body.content, finalResponse.status as 200);\n}\n\nfunction defaultContentTypeFor(bodyType: MockResponseConfig['body']['type']): string | null {\n switch (bodyType) {\n case 'json':\n return 'application/json; charset=utf-8';\n case 'text':\n return 'text/plain; charset=utf-8';\n case 'binary':\n return 'application/octet-stream';\n case 'form-data':\n return 'multipart/form-data';\n case 'none':\n default:\n return null;\n }\n}\n\n/**\n * Translate OpenAPI path templates (`/pets/{id}/items/{itemId}`) to Hono\n * route patterns (`/pets/:id/items/:itemId`). Hono treats `:` as the\n * param prefix; the OpenAPI braces are unsupported.\n */\nexport function openApiPathToHono(path: string): string {\n return path.replace(/\\{([^}]+)\\}/g, ':$1');\n}\n","// CORS middleware honoring `MockServer.cors`. Hono ships a `cors()`\n// middleware in `hono/cors`; we wrap it so the origins list comes from\n// the workspace doc instead of being hardcoded.\n\nimport { cors as honoCors } from 'hono/cors';\nimport type { MiddlewareHandler } from 'hono';\nimport type { MockServer } from '@apicircle/shared';\n\nexport function buildCors(config: MockServer['cors']): MiddlewareHandler | null {\n // Match the UI contract: CORS off (or enabled with no explicit origins) ⇒\n // same-origin only. We never silently wildcard. Users must list at least\n // one origin to opt into cross-origin access; see CorsSection in\n // MockServersPanel for the editor.\n if (!config.enabled) return null;\n if (config.origins.length === 0) return null;\n return honoCors({\n origin: config.origins,\n allowMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'],\n allowHeaders: ['Content-Type', 'Authorization', 'Accept', 'X-Requested-With'],\n exposeHeaders: ['Content-Type'],\n credentials: false,\n maxAge: 600,\n });\n}\n","// Pre-validation evaluator. Runs every enabled rule on the inbound\n// request; returns the first failing rule's `failResponse` (or null when\n// all pass). Order is significant — the editor lets users reorder.\n\nimport type { MockEndpoint, MockResponseConfig, MockValidationRule } from '@apicircle/shared';\nimport type { RequestContext } from '../rules/evaluate';\n\nexport function evaluateValidation(\n endpoint: MockEndpoint,\n ctx: RequestContext,\n): MockResponseConfig | null {\n for (const rule of endpoint.requestValidation) {\n if (!rule.enabled) continue;\n if (!rulePasses(rule, ctx)) {\n return rule.failResponse;\n }\n }\n return null;\n}\n\nfunction rulePasses(rule: MockValidationRule, ctx: RequestContext): boolean {\n switch (rule.kind) {\n case 'header-required': {\n const v = ctx.headers[rule.target.toLowerCase()];\n return v !== undefined && v !== '';\n }\n case 'header-equals': {\n const v = ctx.headers[rule.target.toLowerCase()];\n return v !== undefined && v === (rule.expected ?? '');\n }\n case 'header-matches': {\n const v = ctx.headers[rule.target.toLowerCase()];\n if (v === undefined) return false;\n return safeRegexTest(rule.expected, v);\n }\n case 'query-required': {\n const v = ctx.query[rule.target];\n return v !== undefined && v !== '';\n }\n case 'query-equals': {\n const v = ctx.query[rule.target];\n return v !== undefined && v === (rule.expected ?? '');\n }\n case 'query-matches': {\n const v = ctx.query[rule.target];\n if (v === undefined) return false;\n return safeRegexTest(rule.expected, v);\n }\n case 'cookie-required': {\n const v = ctx.cookies[rule.target];\n return v !== undefined && v !== '';\n }\n case 'body-required': {\n // Pass if either the parsed JSON body has at least one key/element\n // OR the raw text body is non-empty. Matches the user expectation\n // that any body — JSON or text — counts.\n if (ctx.bodyJson !== undefined && ctx.bodyJson !== null) {\n if (Array.isArray(ctx.bodyJson)) return ctx.bodyJson.length > 0;\n if (typeof ctx.bodyJson === 'object') {\n return Object.keys(ctx.bodyJson).length > 0;\n }\n return true;\n }\n return ctx.bodyText.length > 0;\n }\n case 'content-type-equals': {\n const ct = ctx.headers['content-type'] ?? '';\n // Strip parameters (`;charset=utf-8`) for the comparison so common\n // server-flavors of Content-Type still match a plain\n // `application/json` expectation.\n const main = ct.split(';')[0]?.trim().toLowerCase() ?? '';\n return main === (rule.expected ?? '').trim().toLowerCase();\n }\n }\n}\n\nfunction safeRegexTest(pattern: string | undefined, value: string): boolean {\n if (pattern === undefined) return false;\n try {\n const m = /^\\/(.*)\\/([a-z]*)$/.exec(pattern);\n const re = m ? new RegExp(m[1], m[2]) : new RegExp(pattern);\n return re.test(value);\n } catch {\n return false;\n }\n}\n","// Response-rule evaluator. Pure: takes an endpoint + the inbound request\n// context and returns the response config to send back. Disabled rules are\n// skipped; the first rule whose every clause matches wins. If no rule\n// matches, `defaultResponse` is returned.\n//\n// This module also defines `RequestContext` — the runtime-side view of an\n// inbound request, normalized so all evaluators read from the same shape.\n\nimport type {\n MockConditionClause,\n MockConditionOp,\n MockConditionScope,\n MockEndpoint,\n MockResponseConfig,\n} from '@apicircle/shared';\n\nexport interface RequestContext {\n /** Lowercased query keys → first value (repeats are dropped). */\n query: Record<string, string>;\n /** Path params resolved by Hono — original case preserved. */\n pathParams: Record<string, string>;\n /** Lowercased header names → value. */\n headers: Record<string, string>;\n /** Parsed cookies (Cookie header). Names case-preserved. */\n cookies: Record<string, string>;\n /** Raw body text (best-effort — empty string when unread or non-text). */\n bodyText: string;\n /** Parsed JSON body when the Content-Type advertised JSON; otherwise undefined. */\n bodyJson: unknown;\n}\n\nexport function evaluateResponseRules(\n endpoint: MockEndpoint,\n ctx: RequestContext,\n): MockResponseConfig {\n for (const rule of endpoint.responseRules) {\n if (!rule.enabled) continue;\n if (rule.when.length === 0) continue; // Defensive: a clause-less rule never fires.\n if (rule.when.every((clause) => matchesClause(clause, ctx))) {\n return rule.response;\n }\n }\n return endpoint.defaultResponse;\n}\n\nfunction matchesClause(clause: MockConditionClause, ctx: RequestContext): boolean {\n const actual = readScopeValue(clause.scope, clause.target, ctx);\n return applyOp(clause.op, actual, clause.value);\n}\n\nfunction readScopeValue(\n scope: MockConditionScope,\n target: string,\n ctx: RequestContext,\n): string | undefined {\n switch (scope) {\n case 'query':\n return ctx.query[target];\n case 'pathParam':\n return ctx.pathParams[target];\n case 'header':\n return ctx.headers[target.toLowerCase()];\n case 'cookie':\n return ctx.cookies[target];\n case 'body-json-path':\n return resolveJsonPathString(ctx.bodyJson, target);\n }\n}\n\nfunction applyOp(\n op: MockConditionOp,\n actual: string | undefined,\n expected: string | undefined,\n): boolean {\n switch (op) {\n case 'present':\n return actual !== undefined && actual !== '';\n case 'absent':\n return actual === undefined || actual === '';\n case 'equals':\n return actual !== undefined && expected !== undefined && actual === expected;\n case 'not-equals':\n return actual === undefined || expected === undefined || actual !== expected;\n case 'matches': {\n if (actual === undefined || expected === undefined) return false;\n try {\n const re = compileMaybeFlaggedRegex(expected);\n return re.test(actual);\n } catch {\n return false;\n }\n }\n case 'gt':\n case 'lt':\n case 'gte':\n case 'lte': {\n if (actual === undefined || expected === undefined) return false;\n const a = Number(actual);\n const e = Number(expected);\n if (!Number.isFinite(a) || !Number.isFinite(e)) return false;\n switch (op) {\n case 'gt':\n return a > e;\n case 'lt':\n return a < e;\n case 'gte':\n return a >= e;\n case 'lte':\n return a <= e;\n }\n }\n }\n}\n\n/**\n * Accept either a raw regex source (`^bearer .+`) or `/source/flags` form.\n * Mirrors how the editor surfaces the placeholder `/^bearer .+/i`.\n */\nfunction compileMaybeFlaggedRegex(input: string): RegExp {\n const m = /^\\/(.*)\\/([a-z]*)$/.exec(input);\n if (m) return new RegExp(m[1], m[2]);\n return new RegExp(input);\n}\n\n/**\n * Walk a `$.foo.bar[0]` style JSON path on a parsed body. Returns a string\n * coercion of the resolved value, or undefined when the path doesn't\n * resolve. Supports dot segments + numeric `[idx]`.\n *\n * Kept tiny + dependency-free — full jsonpath-plus support can land later\n * if users need the more exotic operators.\n */\nfunction resolveJsonPathString(body: unknown, jsonPath: string): string | undefined {\n const value = resolveJsonPath(body, jsonPath);\n if (value === undefined || value === null) return undefined;\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n return JSON.stringify(value);\n}\n\nexport function resolveJsonPath(body: unknown, jsonPath: string): unknown {\n if (body === undefined || body === null) return undefined;\n let path = jsonPath.trim();\n if (path.startsWith('$')) path = path.slice(1);\n if (path.startsWith('.')) path = path.slice(1);\n if (path === '') return body;\n\n let cursor: unknown = body;\n // Tokens: alternating between a dotted property name and an optional\n // [idx]. Use a greedy regex to walk in order.\n const re = /([^.[\\]]+)|\\[([^\\]]+)\\]/g;\n let match: RegExpExecArray | null;\n while ((match = re.exec(path)) !== null) {\n if (cursor === undefined || cursor === null) return undefined;\n const key = match[1] ?? match[2];\n if (key === undefined) return undefined;\n if (Array.isArray(cursor)) {\n const idx = Number(key);\n if (!Number.isInteger(idx)) return undefined;\n cursor = cursor[idx];\n continue;\n }\n if (typeof cursor === 'object') {\n cursor = (cursor as Record<string, unknown>)[key];\n continue;\n }\n return undefined;\n }\n return cursor;\n}\n","// Response multipliers — read a value from the inbound request, then\n// repeat the array element at `targetJsonPath` inside the response body\n// that many times. Only fires when the response body type is JSON; other\n// body types (text/xml/binary/etc.) are returned unchanged.\n//\n// Fallback rule: when the source value is missing or doesn't coerce to a\n// finite integer, fall back to `defaultCount`. The resolved count is\n// clamped to `[min, max]` when those bounds are set.\n//\n// Edge cases:\n// • The targetJsonPath doesn't resolve to an array → no-op (we don't\n// warn here — buildRouter has nowhere to log; the editor lints).\n// • The array is empty → no-op (no template to repeat).\n// • The body string isn't valid JSON → no-op (returns the original).\n\nimport type { MockResponseConfig, MockResponseMultiplier } from '@apicircle/shared';\nimport { resolveJsonPath } from '../rules/evaluate';\nimport type { RequestContext } from '../rules/evaluate';\n\nexport function applyMultipliers(\n response: MockResponseConfig,\n ctx: RequestContext,\n): MockResponseConfig {\n const multipliers = response.multipliers;\n if (!multipliers || multipliers.length === 0) return response;\n if (response.body.type !== 'json') return response;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(response.body.content);\n } catch {\n return response;\n }\n\n let mutated = false;\n for (const multiplier of multipliers) {\n const count = resolveCount(multiplier, ctx);\n if (count === null) continue;\n const next = applyOneMultiplier(parsed, multiplier.targetJsonPath, count);\n if (next.changed) {\n parsed = next.value;\n mutated = true;\n }\n }\n\n if (!mutated) return response;\n\n return {\n ...response,\n body: { type: 'json', content: JSON.stringify(parsed) },\n };\n}\n\nfunction resolveCount(multiplier: MockResponseMultiplier, ctx: RequestContext): number | null {\n const raw = readSource(multiplier, ctx);\n let count: number;\n if (raw === undefined || raw === '' || raw === null) {\n count = multiplier.defaultCount;\n } else {\n const parsed = Number(raw);\n if (!Number.isFinite(parsed)) {\n count = multiplier.defaultCount;\n } else {\n count = Math.trunc(parsed);\n }\n }\n\n if (multiplier.min !== undefined && count < multiplier.min) count = multiplier.min;\n if (multiplier.max !== undefined && count > multiplier.max) count = multiplier.max;\n if (count < 0) count = 0;\n return count;\n}\n\nfunction readSource(multiplier: MockResponseMultiplier, ctx: RequestContext): unknown {\n const { kind, key } = multiplier.source;\n switch (kind) {\n case 'query':\n return ctx.query[key];\n case 'pathParam':\n return ctx.pathParams[key];\n case 'header':\n return ctx.headers[key.toLowerCase()];\n case 'body-json-path':\n return resolveJsonPath(ctx.bodyJson, key);\n }\n}\n\ninterface ApplyResult {\n changed: boolean;\n value: unknown;\n}\n\n/**\n * Walk the JSON path on the parsed body, repeat the first array element\n * `count` times, and return the new tree. Pure — never mutates `body`.\n */\nfunction applyOneMultiplier(body: unknown, jsonPath: string, count: number): ApplyResult {\n const segments = parsePathSegments(jsonPath);\n if (segments.length === 0) {\n if (Array.isArray(body) && body.length > 0) {\n return { changed: true, value: repeatArray(body, count) };\n }\n return { changed: false, value: body };\n }\n return setAtPath(body, segments, 0, count);\n}\n\ntype PathSegment = { kind: 'key'; name: string } | { kind: 'index'; idx: number };\n\n// Names we never traverse into, even if the user-supplied path explicitly\n// requests them. `__proto__`/`constructor`/`prototype` always resolve via the\n// prototype chain on plain objects and have no place in a JSON multiplier.\nconst FORBIDDEN_KEYS: ReadonlySet<string> = new Set(['__proto__', 'constructor', 'prototype']);\n\nfunction parsePathSegments(jsonPath: string): PathSegment[] {\n let path = jsonPath.trim();\n if (path.startsWith('$')) path = path.slice(1);\n if (path.startsWith('.')) path = path.slice(1);\n if (path === '') return [];\n\n const out: PathSegment[] = [];\n const re = /([^.[\\]]+)|\\[([^\\]]+)\\]/g;\n let match: RegExpExecArray | null;\n while ((match = re.exec(path)) !== null) {\n if (match[1] !== undefined) {\n if (FORBIDDEN_KEYS.has(match[1])) return [];\n out.push({ kind: 'key', name: match[1] });\n } else if (match[2] !== undefined) {\n const n = Number(match[2]);\n if (Number.isInteger(n)) {\n out.push({ kind: 'index', idx: n });\n } else {\n if (FORBIDDEN_KEYS.has(match[2])) return [];\n out.push({ kind: 'key', name: match[2] });\n }\n }\n }\n return out;\n}\n\nfunction setAtPath(\n cursor: unknown,\n segments: PathSegment[],\n depth: number,\n count: number,\n): ApplyResult {\n if (depth === segments.length) {\n if (Array.isArray(cursor) && cursor.length > 0) {\n return { changed: true, value: repeatArray(cursor, count) };\n }\n return { changed: false, value: cursor };\n }\n const seg = segments[depth];\n if (seg.kind === 'index') {\n if (!Array.isArray(cursor)) return { changed: false, value: cursor };\n if (seg.idx < 0 || seg.idx >= cursor.length) return { changed: false, value: cursor };\n const inner = setAtPath(cursor[seg.idx], segments, depth + 1, count);\n if (!inner.changed) return { changed: false, value: cursor };\n const next = cursor.slice();\n next[seg.idx] = inner.value;\n return { changed: true, value: next };\n }\n // 'key' segment.\n if (cursor === null || typeof cursor !== 'object' || Array.isArray(cursor)) {\n return { changed: false, value: cursor };\n }\n const obj = cursor as Record<string, unknown>;\n if (!(seg.name in obj)) return { changed: false, value: cursor };\n const inner = setAtPath(obj[seg.name], segments, depth + 1, count);\n if (!inner.changed) return { changed: false, value: cursor };\n return { changed: true, value: { ...obj, [seg.name]: inner.value } };\n}\n\nfunction repeatArray(arr: unknown[], count: number): unknown[] {\n if (count <= 0) return [];\n const template = arr[0];\n const out: unknown[] = [];\n for (let i = 0; i < count; i++) {\n // Shallow-clone object templates so consumers don't get aliased\n // references — preserves the \"each item is its own object\" invariant\n // most paginated responses assume.\n out.push(cloneShallow(template));\n }\n return out;\n}\n\nfunction cloneShallow(value: unknown): unknown {\n if (value === null || typeof value !== 'object') return value;\n if (Array.isArray(value)) return value.slice();\n return { ...(value as Record<string, unknown>) };\n}\n","// Node.js runtime adapter. Wraps `@hono/node-server`'s `serve()` so the\n// public API can return a typed `MockServerHandle` regardless of the\n// underlying transport (Node / Bun / Workers).\n\nimport { serve, type ServerType } from '@hono/node-server';\nimport type { Hono } from 'hono';\nimport { getFreePort } from './portFinder';\n\nexport interface MockServerHandle {\n port: number;\n /** Stop the server. Resolves once the listener is closed. */\n close: () => Promise<void>;\n}\n\nexport interface ServeOptions {\n /** Use this port; if undefined or 0, pick a free port via portFinder. */\n port?: number;\n /** Bind address. Default `127.0.0.1` so the server isn't internet-exposed. */\n host?: string;\n}\n\n// Hard cap on how long we'll wait for a graceful close before treating the\n// server as stopped anyway. Node's `http.Server.close()` resolves only after\n// every open connection has ended — browsers hold keep-alive sockets open for\n// minutes after the last response, so without intervention `stop()` looks\n// like it hangs forever from the user's perspective. We force-drop sockets\n// (closeAllConnections / closeIdleConnections) before awaiting; the timeout\n// is the belt-and-braces fallback if a socket somehow refuses to die.\nconst CLOSE_TIMEOUT_MS = 3_000;\n\nexport async function serveOnNode(app: Hono, opts: ServeOptions = {}): Promise<MockServerHandle> {\n const port = opts.port && opts.port > 0 ? opts.port : await getFreePort();\n const host = opts.host ?? '127.0.0.1';\n\n let server: ServerType | null = null;\n await new Promise<void>((resolve, reject) => {\n try {\n server = serve(\n {\n fetch: app.fetch,\n port,\n hostname: host,\n },\n () => resolve(),\n );\n server.on('error', reject);\n } catch (err) {\n reject(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n return {\n port,\n close: () =>\n new Promise<void>((resolve) => {\n if (!server) return resolve();\n const s = server;\n // Force-drop every open socket (active + idle) before awaiting the\n // close callback. Node ≥18.2 exposes these as first-class APIs;\n // typed loosely here because @hono/node-server's ServerType union\n // doesn't include them.\n const withCloseHelpers = s as ServerType & {\n closeAllConnections?: () => void;\n closeIdleConnections?: () => void;\n };\n try {\n withCloseHelpers.closeIdleConnections?.();\n withCloseHelpers.closeAllConnections?.();\n } catch {\n // Best-effort: if a helper throws (older Node, exotic transport),\n // we still rely on the timeout below to bound the wait.\n }\n let settled = false;\n const settle = () => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve();\n };\n const timer = setTimeout(settle, CLOSE_TIMEOUT_MS);\n s.close(() => settle());\n }),\n };\n}\n","// Find a free TCP port. Listens on port 0 (OS assigns), captures the\n// chosen port, then releases the listener immediately. Standard pattern;\n// the caveat is the tiny race where a different process grabs the port\n// between our close and the caller's bind — but for desktop / CLI mock\n// servers this race is negligible.\n\nimport { createServer } from 'node:net';\n\nexport async function getFreePort(): Promise<number> {\n return new Promise<number>((resolve, reject) => {\n const server = createServer();\n server.unref();\n server.on('error', reject);\n server.listen(0, () => {\n const address = server.address();\n if (typeof address === 'object' && address !== null) {\n const port = address.port;\n server.close(() => resolve(port));\n } else {\n server.close(() => reject(new Error('Could not determine free port')));\n }\n });\n });\n}\n\nexport async function isPortFree(port: number): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n const server = createServer();\n server.unref();\n server.once('error', () => resolve(false));\n server.once('listening', () => {\n server.close(() => resolve(true));\n });\n server.listen(port);\n });\n}\n","// Public API for @apicircle/mock-server-core.\n//\n// The engine is split into:\n// • Parsers (OpenAPI / Postman / Insomnia → MockEndpoint[])\n// • Router builder (MockServer → Hono app, with per-endpoint overrides)\n// • Node runtime adapter (Hono app → live HTTP server)\n//\n// Consumers (Desktop / CLI / future hosted) call `parseSourceToEndpoints`\n// once when a MockServer is created or refreshed, then `startMockServer`\n// every time the user clicks Start.\n\nimport type { MockServer, MockServerSource, MockEndpoint } from '@apicircle/shared';\nimport type { Hono } from 'hono';\nimport { parseOpenApiToEndpoints } from './parsers/openapi';\nimport { parsePostmanToEndpoints } from './parsers/postman';\nimport { parseInsomniaToEndpoints } from './parsers/insomnia';\nimport { buildRouter, type BuildRouterOptions } from './handlers/buildRouter';\nimport { serveOnNode, type MockServerHandle, type ServeOptions } from './runtime/nodeAdapter';\n\nexport type { MockServerHandle, ServeOptions } from './runtime/nodeAdapter';\nexport type { BuildRouterOptions } from './handlers/buildRouter';\nexport { openApiPathToHono } from './handlers/buildRouter';\nexport { parseOpenApiToEndpoints } from './parsers/openapi';\nexport { parsePostmanToEndpoints } from './parsers/postman';\nexport { parseInsomniaToEndpoints } from './parsers/insomnia';\nexport { schemaToExample } from './faker/schemaToExample';\nexport { getFreePort, isPortFree } from './runtime/portFinder';\nexport { buildRouter };\n\nexport interface ParseSourceResult {\n endpoints: MockEndpoint[];\n warnings: string[];\n}\n\n/**\n * Dispatch the right parser for a `MockServerSource`. Returns the\n * resolved `MockEndpoint[]` along with any non-fatal warnings the\n * parser surfaced. The caller persists `endpoints` onto\n * `MockServer.endpoints`.\n */\nexport async function parseSourceToEndpoints(source: MockServerSource): Promise<ParseSourceResult> {\n switch (source.kind) {\n case 'openapi':\n return parseOpenApiToEndpoints(source.spec, source.format);\n case 'postman':\n return parsePostmanToEndpoints(source.collection);\n case 'insomnia':\n return parseInsomniaToEndpoints(source.export);\n case 'manual':\n return { endpoints: source.endpoints, warnings: [] };\n }\n}\n\n/**\n * Build a Hono app for an in-memory MockServer without binding a port.\n * Useful for tests and for hosted/edge transports that bring their own\n * server.\n */\nexport function createMockApp(server: MockServer, opts: BuildRouterOptions = {}): Hono {\n return buildRouter(server, opts);\n}\n\n/**\n * Start a mock server on Node. Picks a free port when\n * `MockServer.defaultPort` is null or `opts.port` is omitted; otherwise\n * uses the requested port and errors if it's busy.\n */\nexport async function startMockServer(\n server: MockServer,\n opts: { port?: number; host?: string; onRequest?: BuildRouterOptions['onRequest'] } = {},\n): Promise<MockServerHandle> {\n const app = createMockApp(server, { onRequest: opts.onRequest });\n const desired: ServeOptions = {\n host: opts.host,\n port: opts.port ?? server.defaultPort ?? undefined,\n };\n return serveOnNode(app, desired);\n}\n\n/** Convenience: stop a previously-started server. */\nexport async function stopMockServer(handle: MockServerHandle): Promise<void> {\n return handle.close();\n}\n"],"mappings":"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","names":["SUPPORTED_METHODS","slug","SUPPORTED_METHODS","extractPath","slug","inner"]}
1
+ {"version":3,"sources":["../src/parsers/openapi.ts","../src/faker/schemaToExample.ts","../src/parsers/buildEndpoint.ts","../src/parsers/postman.ts","../src/parsers/insomnia.ts","../src/handlers/buildRouter.ts","../src/cors.ts","../src/validation/evaluate.ts","../src/rules/evaluate.ts","../src/response/applyMultipliers.ts","../src/runtime/nodeAdapter.ts","../src/runtime/portFinder.ts","../src/index.ts"],"sourcesContent":["// OpenAPI / Swagger 2.0 → MockEndpoint[] parser.\n//\n// Two-step pipeline:\n// 1. Parse the source string (JSON or YAML) and run swagger-parser's\n// `dereference` so all `$ref` chains are resolved up-front. The mock\n// server doesn't carry a $ref resolver at runtime — every endpoint\n// ships a self-contained body.\n// 2. Walk `paths.{path}.{method}.responses.{status}.content.{mediaType}`\n// and pull either an `example`, the first `examples` entry, or\n// synthesize one from the schema via `schemaToExample`.\n//\n// We pick the lowest 2xx response when multiple are present (200 wins\n// over 201; if neither, take the first 2xx). Errors and 5xx are ignored\n// — mock servers should default to the success path; users override via\n// the editor when they want failure cases.\n\nimport SwaggerParser from '@apidevtools/swagger-parser';\nimport yaml from 'js-yaml';\nimport type { HttpMethod, MockEndpoint, MockRequestSchema } from '@apicircle/shared';\nimport { makeDefaultRequestSchema } from '@apicircle/shared';\nimport { schemaToExample, type JsonSchemaLike } from '../faker/schemaToExample';\nimport { paramDef } from './buildEndpoint';\nimport { buildMockEndpoint } from './buildEndpoint';\n\nconst SUPPORTED_METHODS: ReadonlyArray<HttpMethod> = [\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'HEAD',\n 'OPTIONS',\n];\n\ninterface OpenApiParameter {\n name?: string;\n in?: string; // 'path' | 'query' | 'header' | 'cookie'\n required?: boolean;\n description?: string;\n schema?: JsonSchemaLike;\n // Swagger 2.0 carries `type` directly on the parameter (no `schema`).\n type?: string;\n example?: unknown;\n}\n\ninterface OpenApiOperation {\n operationId?: string;\n summary?: string;\n responses?: Record<string, OpenApiResponse>;\n parameters?: OpenApiParameter[];\n // Swagger 2.0 carries `produces` here; we honor it as a fallback for\n // content-type when `responses[status].content` is absent.\n produces?: string[];\n}\n\ninterface OpenApiResponse {\n description?: string;\n content?: Record<\n string,\n { example?: unknown; examples?: Record<string, { value?: unknown }>; schema?: JsonSchemaLike }\n >;\n // Swagger 2.0\n schema?: JsonSchemaLike;\n examples?: Record<string, unknown>;\n headers?: Record<string, { schema?: JsonSchemaLike; example?: unknown }>;\n}\n\nexport interface ParseOpenApiOptions {\n /**\n * When the OpenAPI doc has multiple 2xx responses, this picks which one\n * becomes the mock. Default: the lowest numeric 2xx (200 wins over 201).\n */\n preferStatus?: number;\n}\n\nexport interface ParseOpenApiResult {\n endpoints: MockEndpoint[];\n warnings: string[];\n}\n\n/**\n * Parse an OpenAPI / Swagger 2.0 spec string and return the mock endpoint\n * table. `format` is a hint — the parser will fall back to JSON.parse if\n * YAML parse fails.\n */\nexport async function parseOpenApiToEndpoints(\n source: string,\n format: 'json' | 'yaml' = 'json',\n opts: ParseOpenApiOptions = {},\n): Promise<ParseOpenApiResult> {\n const warnings: string[] = [];\n\n const raw = format === 'yaml' ? safeYamlLoad(source) : safeJsonParse(source);\n if (!raw || typeof raw !== 'object') {\n return { endpoints: [], warnings: ['Could not parse OpenAPI source'] };\n }\n\n // SwaggerParser.dereference takes either a path or an in-memory object\n // and mutates `$ref` chains in place so downstream code can ignore refs\n // entirely. Cast through unknown — the SDK's types are narrower than we\n // need (they assume a path input and an `info` block).\n let api: Record<string, unknown>;\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const dereffed = await (SwaggerParser as any).dereference(raw);\n api = dereffed as Record<string, unknown>;\n } catch (err) {\n warnings.push(\n `swagger-parser failed: ${err instanceof Error ? err.message : 'unknown error'}; ` +\n 'falling back to raw spec',\n );\n api = raw as Record<string, unknown>;\n }\n\n const paths = (api.paths ?? {}) as Record<string, Record<string, OpenApiOperation>>;\n const endpoints: MockEndpoint[] = [];\n let endpointId = 0;\n\n for (const [path, ops] of Object.entries(paths)) {\n if (!ops || typeof ops !== 'object') continue;\n // Path-item-level parameters apply to every operation under the path; an\n // operation's own parameters override them by (name, in).\n const pathItemParams = (ops as { parameters?: OpenApiParameter[] }).parameters ?? [];\n for (const method of Object.keys(ops)) {\n const upper = method.toUpperCase() as HttpMethod;\n if (!SUPPORTED_METHODS.includes(upper)) continue;\n const op = ops[method];\n if (!op || typeof op !== 'object') continue;\n\n const built = buildEndpointFromOp(\n path,\n upper,\n op,\n pathItemParams,\n opts,\n warnings,\n endpointId++,\n );\n if (built) endpoints.push(built);\n }\n }\n\n return { endpoints, warnings };\n}\n\n/** Merge path-item + operation parameters (operation wins by name+in) and map\n * them into a `MockRequestSchema`. Pure. */\nfunction buildRequestSchema(\n pathItemParams: OpenApiParameter[],\n op: OpenApiOperation,\n): MockRequestSchema {\n const merged = new Map<string, OpenApiParameter>();\n for (const p of [...pathItemParams, ...(op.parameters ?? [])]) {\n if (p && typeof p === 'object' && typeof p.name === 'string') {\n merged.set(`${p.in ?? 'query'}:${p.name}`, p);\n }\n }\n const schema = makeDefaultRequestSchema();\n for (const p of merged.values()) {\n const rawType = p.schema?.type ?? p.type;\n const typeHint = p.schema?.format ?? (Array.isArray(rawType) ? rawType[0] : rawType);\n const exampleVal = p.example ?? p.schema?.example;\n const def = paramDef(p.name as string, {\n typeHint: typeof typeHint === 'string' ? typeHint : undefined,\n required: typeof p.required === 'boolean' ? p.required : undefined,\n description: typeof p.description === 'string' ? p.description : undefined,\n example:\n exampleVal === undefined\n ? undefined\n : typeof exampleVal === 'string'\n ? exampleVal\n : JSON.stringify(exampleVal),\n });\n switch (p.in) {\n case 'path':\n schema.pathParams.push(def);\n break;\n case 'query':\n schema.queryParams.push(def);\n break;\n case 'header':\n schema.headers.push(def);\n break;\n case 'cookie':\n schema.cookies.push(def);\n break;\n default:\n // Swagger 2.0 `in: body` / `in: formData` aren't request-param schema\n // entries — skip them (the body shape is documented elsewhere).\n break;\n }\n }\n return schema;\n}\n\nfunction buildEndpointFromOp(\n path: string,\n method: HttpMethod,\n op: OpenApiOperation,\n pathItemParams: OpenApiParameter[],\n opts: ParseOpenApiOptions,\n warnings: string[],\n index: number,\n): MockEndpoint | null {\n const responses = op.responses ?? {};\n const candidates = Object.keys(responses)\n .filter((code) => /^2\\d\\d$/.test(code))\n .map((code) => Number(code));\n if (candidates.length === 0) {\n warnings.push(`No 2xx response defined for ${method} ${path} — skipping`);\n return null;\n }\n const status = opts.preferStatus\n ? candidates.includes(opts.preferStatus)\n ? opts.preferStatus\n : Math.min(...candidates)\n : Math.min(...candidates);\n const response = responses[String(status)];\n if (!response) {\n warnings.push(`Response ${status} missing for ${method} ${path}`);\n return null;\n }\n\n const { contentType, body, exampleName } = pickResponsePayload(response, op);\n\n const headers = pickResponseHeaders(response, contentType);\n\n return buildMockEndpoint({\n id: `op-${index}-${method.toLowerCase()}-${slug(path)}`,\n method,\n pathPattern: path,\n example: exampleName,\n requestSchema: buildRequestSchema(pathItemParams, op),\n response: { status, headers, body },\n });\n}\n\nfunction pickResponsePayload(\n response: OpenApiResponse,\n op: OpenApiOperation,\n): { contentType: string; body: string; exampleName: string | undefined } {\n // OpenAPI 3.x: `response.content` is keyed by media type.\n if (response.content) {\n const mediaTypes = Object.keys(response.content);\n const preferred =\n mediaTypes.find((m) => m.toLowerCase().includes('json')) ??\n mediaTypes[0] ??\n 'application/json';\n const entry = response.content[preferred];\n if (entry) {\n if (entry.example !== undefined) {\n return {\n contentType: preferred,\n body: stringifyForContentType(entry.example, preferred),\n exampleName: undefined,\n };\n }\n if (entry.examples) {\n const firstExampleName = Object.keys(entry.examples)[0];\n if (firstExampleName) {\n const v = entry.examples[firstExampleName];\n return {\n contentType: preferred,\n body: stringifyForContentType(v?.value, preferred),\n exampleName: firstExampleName,\n };\n }\n }\n if (entry.schema) {\n return {\n contentType: preferred,\n body: stringifyForContentType(schemaToExample(entry.schema), preferred),\n exampleName: undefined,\n };\n }\n }\n }\n\n // Swagger 2.0 fallback.\n if (response.schema) {\n const ct = (op.produces && op.produces[0]) ?? 'application/json';\n return {\n contentType: ct,\n body: stringifyForContentType(schemaToExample(response.schema), ct),\n exampleName: undefined,\n };\n }\n if (response.examples) {\n const firstName = Object.keys(response.examples)[0];\n if (firstName) {\n const v = response.examples[firstName];\n return {\n contentType: firstName,\n body: stringifyForContentType(v, firstName),\n exampleName: firstName,\n };\n }\n }\n\n return {\n contentType: 'application/json',\n body: '{}',\n exampleName: undefined,\n };\n}\n\ntype ParsedHeader = { key: string; value: string };\n\nfunction pickResponseHeaders(response: OpenApiResponse, contentType: string): ParsedHeader[] {\n const headers: ParsedHeader[] = [{ key: 'Content-Type', value: contentType }];\n if (response.headers) {\n for (const [name, def] of Object.entries(response.headers)) {\n if (name.toLowerCase() === 'content-type') continue;\n const value = def.example !== undefined ? def.example : schemaToExample(def.schema);\n if (value === undefined || value === null) continue;\n // Header values must be strings. Strings pass through; everything\n // else gets JSON-encoded — covers objects/arrays/numbers/booleans\n // without ever falling back to \"[object Object]\".\n const text = typeof value === 'string' ? value : JSON.stringify(value);\n headers.push({ key: name, value: text });\n }\n }\n return headers;\n}\n\nfunction stringifyForContentType(value: unknown, contentType: string): string {\n if (value === undefined || value === null) return '';\n if (typeof value === 'string') return value;\n if (contentType.toLowerCase().includes('json')) {\n return JSON.stringify(value, null, 2);\n }\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n return JSON.stringify(value);\n}\n\nfunction slug(s: string): string {\n return (\n s\n .replace(/[^a-z0-9]+/gi, '-')\n .replace(/^-|-$/g, '')\n .toLowerCase() || 'root'\n );\n}\n\nfunction safeJsonParse(s: string): unknown {\n try {\n return JSON.parse(s);\n } catch {\n return null;\n }\n}\n\nfunction safeYamlLoad(s: string): unknown {\n try {\n return yaml.load(s);\n } catch {\n return safeJsonParse(s);\n }\n}\n","// Minimal JSON Schema → example value generator. Used when an OpenAPI\n// operation has no `example` / `examples` map, but the response body's\n// schema is defined. Handles the common cases:\n//\n// • primitives (string, number, integer, boolean, null) — picks a\n// plausible default per `format` when present\n// • arrays — single-element with the items schema sampled\n// • objects — every required property; falls back to all properties\n// when `required` is missing\n// • enums — first value\n// • const — verbatim\n// • allOf / oneOf / anyOf — first branch\n//\n// Doesn't try to be a full faker — the goal is \"realistic enough for a\n// developer testing happy paths\", not exhaustive boundary cases.\n\nexport interface JsonSchemaLike {\n type?: string | string[];\n format?: string;\n enum?: unknown[];\n const?: unknown;\n default?: unknown;\n example?: unknown;\n properties?: Record<string, JsonSchemaLike>;\n required?: string[];\n items?: JsonSchemaLike;\n allOf?: JsonSchemaLike[];\n oneOf?: JsonSchemaLike[];\n anyOf?: JsonSchemaLike[];\n}\n\nconst FORMAT_DEFAULTS: Record<string, string> = {\n 'date-time': '2026-04-27T00:00:00.000Z',\n date: '2026-04-27',\n time: '00:00:00',\n email: 'user@example.com',\n hostname: 'example.com',\n ipv4: '127.0.0.1',\n ipv6: '::1',\n uri: 'https://example.com',\n url: 'https://example.com',\n uuid: '00000000-0000-4000-8000-000000000000',\n byte: 'AA==',\n binary: '',\n};\n\nexport function schemaToExample(schema: JsonSchemaLike | undefined): unknown {\n if (!schema) return null;\n\n // Explicit example / default / const win in that order.\n if (schema.example !== undefined) return schema.example;\n if (schema.default !== undefined) return schema.default;\n if (schema.const !== undefined) return schema.const;\n\n if (Array.isArray(schema.enum) && schema.enum.length > 0) {\n return schema.enum[0];\n }\n\n // Compositors: pick the first branch.\n const branch = schema.allOf?.[0] ?? schema.oneOf?.[0] ?? schema.anyOf?.[0];\n if (branch) return schemaToExample(branch);\n\n // Type can be a single string or an array; pick the first non-null.\n const type = pickType(schema.type);\n\n switch (type) {\n case 'string':\n return schema.format ? (FORMAT_DEFAULTS[schema.format] ?? 'string') : 'string';\n case 'integer':\n return 0;\n case 'number':\n return 0;\n case 'boolean':\n return false;\n case 'null':\n return null;\n case 'array': {\n const items = schema.items ? schemaToExample(schema.items) : null;\n return [items];\n }\n case 'object':\n default: {\n const properties = schema.properties ?? {};\n const required = schema.required ?? Object.keys(properties);\n const out: Record<string, unknown> = {};\n for (const key of required) {\n const propSchema = properties[key];\n out[key] = schemaToExample(propSchema);\n }\n return out;\n }\n }\n}\n\nfunction pickType(type: string | string[] | undefined): string | undefined {\n if (!type) return undefined;\n if (typeof type === 'string') return type;\n // Prefer non-null types so the example isn't trivially `null`.\n return type.find((t) => t !== 'null') ?? type[0];\n}\n","// Helpers shared by every parser (OpenAPI / Postman / Insomnia) that wrap\n// the legacy \"flat\" parsed shape (status / headers / body string) into the\n// current `MockEndpoint` schema (defaultResponse + responseRules + validation).\n//\n// Parsers stay agnostic about validation / response rules — those are\n// authoring-time concerns. They emit endpoints with empty `requestValidation`\n// and `responseRules` and a single `defaultResponse` that holds the parsed\n// 2xx (OpenAPI) / first example (Postman/Insomnia) payload.\n\nimport type {\n HttpMethod,\n MockEndpoint,\n MockParamDef,\n MockRequestSchema,\n MockResponseBody,\n MockResponseBodyType,\n MockResponseConfig,\n} from '@apicircle/shared';\nimport { generateId, makeDefaultRequestSchema } from '@apicircle/shared';\n\nexport interface ParsedResponseShape {\n status: number;\n /** Wire-shape headers — `enabled` is added when wrapping into the endpoint. */\n headers: Array<{ key: string; value: string }>;\n body: string;\n /** Optional artificial latency. */\n delayMs?: number;\n}\n\nexport interface BuildEndpointInput {\n id: string;\n /** User-friendly label; defaults to \"{METHOD} {pathPattern}\" when omitted. */\n name?: string;\n method: HttpMethod;\n pathPattern: string;\n description?: string;\n example?: string;\n response: ParsedResponseShape;\n /** Declared inputs extracted from the spec (path / query / header / cookie\n * params + body docs). Defaults to an empty schema when the source carries\n * no parameters. */\n requestSchema?: MockRequestSchema;\n}\n\n/** Build a `MockParamDef` with a fresh id. Shared by the OpenAPI / Postman /\n * Insomnia parsers so an imported endpoint's declared params land in the\n * requestSchema editor (VS Code / Web / Desktop / MCP). */\nexport function paramDef(\n name: string,\n opts?: { typeHint?: string; required?: boolean; description?: string; example?: string },\n): MockParamDef {\n return {\n id: generateId(),\n name,\n typeHint: opts?.typeHint,\n required: opts?.required,\n description: opts?.description,\n example: opts?.example,\n };\n}\n\nfunction bodyTypeForContentType(contentType: string | undefined): MockResponseBodyType {\n if (!contentType) return 'json';\n const main = contentType.toLowerCase().split(';')[0]?.trim() ?? '';\n if (main.includes('json')) return 'json';\n if (main.includes('xml')) return 'xml';\n if (main === 'application/x-www-form-urlencoded') return 'urlencoded';\n if (main === 'multipart/form-data') return 'form-data';\n if (main === 'application/octet-stream') return 'binary';\n if (main.startsWith('text/')) return 'text';\n return 'text';\n}\n\nfunction bodyFromString(content: string, type: MockResponseBodyType): MockResponseBody {\n switch (type) {\n case 'none':\n return { type: 'none', content: '' };\n case 'binary':\n return { type: 'binary', content: '' };\n case 'form-data':\n return { type: 'form-data', content: '', formRows: [] };\n default:\n return { type, content };\n }\n}\n\n/** Wrap a flat status/headers/body parse into a `MockResponseConfig`. */\nfunction buildMockResponse(parsed: ParsedResponseShape): MockResponseConfig {\n const contentType = parsed.headers.find((h) => h.key.toLowerCase() === 'content-type')?.value;\n const bodyType = bodyTypeForContentType(contentType);\n return {\n status: parsed.status,\n headers: parsed.headers.map((h) => ({ ...h, enabled: true })),\n body: bodyFromString(parsed.body, bodyType),\n ...(parsed.delayMs !== undefined ? { delayMs: parsed.delayMs } : {}),\n };\n}\n\n/** Compose a new `MockEndpoint` with sensible empty defaults for the rest. */\nexport function buildMockEndpoint(input: BuildEndpointInput): MockEndpoint {\n return {\n id: input.id,\n name: input.name ?? `${input.method} ${input.pathPattern}`,\n method: input.method,\n pathPattern: input.pathPattern,\n description: input.description,\n requestSchema: input.requestSchema ?? makeDefaultRequestSchema(),\n requestValidation: [],\n responseRules: [],\n defaultResponse: buildMockResponse(input.response),\n example: input.example,\n };\n}\n","// Postman v2.1 collection → MockEndpoint[].\n//\n// Postman's collection JSON has a recursive `item[]` structure where each\n// item is either:\n// • a folder: `{ name, item: [...] }`\n// • a request: `{ name, request: {...}, response?: [...] }`\n//\n// For mocking, the most useful payload is `response[]` — Postman lets\n// users save example responses against each request. We pull the first\n// response from each request that has any. When a request has no saved\n// example, we synthesize a 200 with an empty JSON body.\n\nimport type { HttpMethod, MockEndpoint, MockRequestSchema } from '@apicircle/shared';\nimport { makeDefaultRequestSchema } from '@apicircle/shared';\nimport { buildMockEndpoint, paramDef } from './buildEndpoint';\n\ninterface PostmanCollection {\n info?: { name?: string; schema?: string };\n item?: PostmanItem[];\n}\n\ninterface PostmanItem {\n name?: string;\n item?: PostmanItem[]; // folder\n request?: PostmanRequest;\n response?: PostmanResponse[];\n}\n\ninterface PostmanKV {\n key?: string;\n value?: string;\n description?: string;\n disabled?: boolean;\n}\n\ninterface PostmanRequest {\n method?: string;\n url?:\n | string\n | { raw?: string; path?: string[] | string; query?: PostmanKV[]; variable?: PostmanKV[] };\n header?: Array<{ key: string; value?: string; description?: string; disabled?: boolean }>;\n body?: { raw?: string; mode?: string };\n}\n\n/** Map a Postman request's declared inputs into a `MockRequestSchema`: path\n * variables → pathParams, query → queryParams, headers → headers. Disabled\n * rows are skipped (they wouldn't be sent). */\nfunction postmanRequestSchema(req: PostmanRequest): MockRequestSchema {\n const schema = makeDefaultRequestSchema();\n const url = req.url;\n if (url && typeof url === 'object') {\n for (const v of url.variable ?? []) {\n if (v?.key)\n schema.pathParams.push(paramDef(v.key, { example: v.value, description: v.description }));\n }\n for (const q of url.query ?? []) {\n if (q?.key && !q.disabled)\n schema.queryParams.push(paramDef(q.key, { example: q.value, description: q.description }));\n }\n }\n for (const h of req.header ?? []) {\n if (h?.key && !h.disabled)\n schema.headers.push(paramDef(h.key, { example: h.value, description: h.description }));\n }\n return schema;\n}\n\ninterface PostmanResponse {\n name?: string;\n status?: string;\n code?: number;\n header?: Array<{ key: string; value: string }>;\n body?: string;\n _postman_previewlanguage?: string;\n}\n\nconst SUPPORTED_METHODS: ReadonlyArray<HttpMethod> = [\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'HEAD',\n 'OPTIONS',\n];\n\nexport interface ParsePostmanResult {\n endpoints: MockEndpoint[];\n warnings: string[];\n}\n\nexport function parsePostmanToEndpoints(source: string): ParsePostmanResult {\n const warnings: string[] = [];\n let parsed: PostmanCollection;\n try {\n parsed = JSON.parse(source) as PostmanCollection;\n } catch {\n return { endpoints: [], warnings: ['Could not parse Postman collection JSON'] };\n }\n\n const endpoints: MockEndpoint[] = [];\n let endpointId = 0;\n walkItems(parsed.item ?? [], (item) => {\n if (!item.request) return;\n const method = (item.request.method ?? 'GET').toUpperCase() as HttpMethod;\n if (!SUPPORTED_METHODS.includes(method)) {\n warnings.push(`Skipping ${method} (unsupported method): ${item.name ?? '(unnamed)'}`);\n return;\n }\n const path = extractPath(item.request.url);\n if (!path) {\n warnings.push(`Skipping request with no extractable path: ${item.name ?? '(unnamed)'}`);\n return;\n }\n\n // First saved response wins. Postman stores examples in\n // `response[]` — a request without saved examples falls through to\n // the synthesized default below.\n const requestSchema = postmanRequestSchema(item.request);\n const example = item.response?.[0];\n if (example) {\n endpoints.push(\n buildMockEndpoint({\n id: `pm-${endpointId++}-${slug(path)}`,\n name: item.name,\n method,\n pathPattern: path,\n example: example.name,\n requestSchema,\n response: {\n // Postman's `code` is the canonical numeric status; `status` is a\n // human-readable label that *sometimes* parses as a number. Try\n // both, fall back to 200 only when neither yields a finite number.\n status:\n example.code ??\n (Number.isFinite(Number(example.status)) ? Number(example.status) : 200),\n headers: (example.header ?? []).map((h) => ({ key: h.key, value: h.value })),\n body: example.body ?? '',\n },\n }),\n );\n } else {\n endpoints.push(\n buildMockEndpoint({\n id: `pm-${endpointId++}-${slug(path)}`,\n name: item.name,\n method,\n pathPattern: path,\n requestSchema,\n response: {\n status: 200,\n headers: [{ key: 'Content-Type', value: 'application/json' }],\n body: '{}',\n },\n }),\n );\n }\n });\n\n return { endpoints, warnings };\n}\n\nfunction walkItems(items: PostmanItem[], visit: (item: PostmanItem) => void): void {\n for (const item of items) {\n if (item.item) walkItems(item.item, visit);\n else if (item.request) visit(item);\n }\n}\n\nfunction extractPath(url: PostmanRequest['url']): string | null {\n if (!url) return null;\n if (typeof url === 'string') {\n return urlToPath(url);\n }\n if (url.raw) return urlToPath(url.raw);\n if (url.path) {\n const segments = Array.isArray(url.path) ? url.path : [url.path];\n return '/' + segments.filter(Boolean).join('/');\n }\n return null;\n}\n\nfunction urlToPath(raw: string): string | null {\n // Postman often stores absolute URLs (e.g. https://api.example.com/users).\n // The mock server cares about the path only.\n try {\n const parsed = new URL(raw.replace(/^https?:\\/\\/[^/]*$/, raw + '/'));\n return parsed.pathname || '/';\n } catch {\n // Already a path or a template like {{baseUrl}}/users.\n const idx = raw.indexOf('/');\n return idx === -1 ? '/' : raw.slice(idx);\n }\n}\n\nfunction slug(s: string): string {\n return (\n s\n .replace(/[^a-z0-9]+/gi, '-')\n .replace(/^-|-$/g, '')\n .toLowerCase() || 'root'\n );\n}\n","// Insomnia v4 export → MockEndpoint[].\n//\n// Insomnia's export format is a flat `resources[]` array where each entry\n// has a `_type` discriminator (`request`, `request_group`, `environment`,\n// `workspace`). We only consume `_type === 'request'`.\n//\n// Insomnia doesn't ship saved-response examples, so every endpoint gets a\n// synthesized 200 with an empty JSON body. The user can override per-\n// endpoint via the editor.\n\nimport type { HttpMethod, MockEndpoint, MockRequestSchema } from '@apicircle/shared';\nimport { makeDefaultRequestSchema } from '@apicircle/shared';\nimport { buildMockEndpoint, paramDef } from './buildEndpoint';\n\ninterface InsomniaExport {\n resources?: InsomniaResource[];\n}\n\ninterface InsomniaKV {\n name?: string;\n value?: string;\n description?: string;\n disabled?: boolean;\n}\n\ninterface InsomniaResource {\n _id?: string;\n _type?: string;\n name?: string;\n method?: string;\n url?: string;\n parentId?: string;\n // Insomnia models query params + headers as `{ name, value, ... }` rows;\n // path params are embedded as `:slot` / `{slot}` in the URL.\n parameters?: InsomniaKV[];\n headers?: InsomniaKV[];\n}\n\n/** `:slot` / `{slot}` segment names in a path. */\nfunction extractPathSlots(path: string): string[] {\n const out = new Set<string>();\n for (const m of path.matchAll(/[:{]([A-Za-z0-9_]+)\\}?/g)) out.add(m[1]);\n return [...out];\n}\n\n/** Map an Insomnia request's declared inputs into a `MockRequestSchema`. */\nfunction insomniaRequestSchema(r: InsomniaResource, path: string): MockRequestSchema {\n const schema = makeDefaultRequestSchema();\n for (const slot of extractPathSlots(path))\n schema.pathParams.push(paramDef(slot, { required: true }));\n for (const p of r.parameters ?? []) {\n if (p?.name && !p.disabled)\n schema.queryParams.push(paramDef(p.name, { example: p.value, description: p.description }));\n }\n for (const h of r.headers ?? []) {\n if (h?.name && !h.disabled)\n schema.headers.push(paramDef(h.name, { example: h.value, description: h.description }));\n }\n return schema;\n}\n\nconst SUPPORTED_METHODS: ReadonlyArray<HttpMethod> = [\n 'GET',\n 'POST',\n 'PUT',\n 'PATCH',\n 'DELETE',\n 'HEAD',\n 'OPTIONS',\n];\n\nexport interface ParseInsomniaResult {\n endpoints: MockEndpoint[];\n warnings: string[];\n}\n\nexport function parseInsomniaToEndpoints(source: string): ParseInsomniaResult {\n const warnings: string[] = [];\n let parsed: InsomniaExport;\n try {\n parsed = JSON.parse(source) as InsomniaExport;\n } catch {\n return { endpoints: [], warnings: ['Could not parse Insomnia export JSON'] };\n }\n\n const endpoints: MockEndpoint[] = [];\n let endpointId = 0;\n\n for (const r of parsed.resources ?? []) {\n if (r._type !== 'request') continue;\n const method = (r.method ?? 'GET').toUpperCase() as HttpMethod;\n if (!SUPPORTED_METHODS.includes(method)) {\n warnings.push(`Skipping ${method} (unsupported method): ${r.name ?? '(unnamed)'}`);\n continue;\n }\n const path = extractPath(r.url);\n if (!path) {\n warnings.push(`Skipping request with no path: ${r.name ?? '(unnamed)'}`);\n continue;\n }\n endpoints.push(\n buildMockEndpoint({\n id: `ins-${endpointId++}-${slug(path)}`,\n name: r.name,\n method,\n pathPattern: path,\n requestSchema: insomniaRequestSchema(r, path),\n response: {\n status: 200,\n headers: [{ key: 'Content-Type', value: 'application/json' }],\n body: '{}',\n },\n }),\n );\n }\n\n return { endpoints, warnings };\n}\n\nfunction extractPath(url: string | undefined): string | null {\n if (!url) return null;\n try {\n return new URL(url).pathname || '/';\n } catch {\n const idx = url.indexOf('/');\n return idx === -1 ? '/' : url.slice(idx);\n }\n}\n\nfunction slug(s: string): string {\n return (\n s\n .replace(/[^a-z0-9]+/gi, '-')\n .replace(/^-|-$/g, '')\n .toLowerCase() || 'root'\n );\n}\n","// Build a Hono app from a MockServer's resolved endpoints.\n//\n// Path conversion: OpenAPI uses `{id}` for path params; Hono uses `:id`.\n// Translation is a single regex.\n//\n// Match precedence: more-specific routes first. Hono matches in\n// registration order, so we sort the endpoint list by path-specificity\n// (literal segments beat parameterised ones).\n//\n// Per-request pipeline:\n// request → evaluateValidation → evaluateResponseRules → applyMultipliers → respond\n//\n// The legacy `MockServer.overrides` map is intentionally NOT consulted\n// here — it was the pre-rules-redesign override layer; the new editor\n// produces `requestValidation` + `responseRules` + `defaultResponse`\n// instead.\n\nimport { Hono } from 'hono';\nimport type { Context } from 'hono';\nimport type { MockEndpoint, MockResponseConfig, MockServer } from '@apicircle/shared';\nimport { buildCors } from '../cors';\nimport { evaluateValidation } from '../validation/evaluate';\nimport { evaluateResponseRules, type RequestContext } from '../rules/evaluate';\nimport { applyMultipliers } from '../response/applyMultipliers';\n\nexport interface BuildRouterOptions {\n /** Called whenever a request hits a mock endpoint — used to tick\n * `MockRuntimeEntry.requestCount` from the host process. */\n onRequest?: (ctx: { endpointId: string; method: string; path: string }) => void;\n}\n\nexport function buildRouter(server: MockServer, opts: BuildRouterOptions = {}): Hono {\n const app = new Hono();\n\n const corsMiddleware = buildCors(server.cors);\n if (corsMiddleware) app.use('*', corsMiddleware);\n\n // Sort: more-specific routes register first. Endpoints without a `{`\n // param are strictly more specific than those with one.\n const sorted = [...server.endpoints].sort((a, b) => {\n const aHasParam = /\\{/.test(a.pathPattern);\n const bHasParam = /\\{/.test(b.pathPattern);\n if (aHasParam !== bHasParam) return aHasParam ? 1 : -1;\n // Then prefer longer paths (more segments).\n return b.pathPattern.length - a.pathPattern.length;\n });\n\n for (const endpoint of sorted) {\n const honoPath = openApiPathToHono(endpoint.pathPattern);\n const handler = makeHandler(endpoint, opts);\n switch (endpoint.method) {\n case 'GET':\n app.get(honoPath, handler);\n break;\n case 'POST':\n app.post(honoPath, handler);\n break;\n case 'PUT':\n app.put(honoPath, handler);\n break;\n case 'PATCH':\n app.patch(honoPath, handler);\n break;\n case 'DELETE':\n app.delete(honoPath, handler);\n break;\n case 'HEAD':\n case 'OPTIONS':\n app.on(endpoint.method, honoPath, handler);\n break;\n }\n }\n\n // 404 fallback — always JSON so curl users see a structured response.\n app.notFound((c) =>\n c.json(\n {\n error: 'No mock endpoint matches this path',\n method: c.req.method,\n path: new URL(c.req.url).pathname,\n },\n 404,\n ),\n );\n\n return app;\n}\n\nfunction makeHandler(endpoint: MockEndpoint, opts: BuildRouterOptions) {\n return async (c: Context) => {\n opts.onRequest?.({\n endpointId: endpoint.id,\n method: endpoint.method,\n path: endpoint.pathPattern,\n });\n\n const ctx = await buildRequestContext(c);\n\n // 1) Pre-validation gates fire first; the first failing rule wins.\n const failResponse = evaluateValidation(endpoint, ctx);\n if (failResponse) {\n return await respond(c, failResponse, ctx);\n }\n\n // 2) Conditional response rules — first matching rule wins, falling\n // through to defaultResponse otherwise.\n const matched = evaluateResponseRules(endpoint, ctx);\n return await respond(c, matched, ctx);\n };\n}\n\nasync function buildRequestContext(c: Context): Promise<RequestContext> {\n const url = new URL(c.req.url);\n const queryEntries = Array.from(url.searchParams.entries());\n // Use Object.create(null) so user-controlled keys like `__proto__` or\n // `constructor` can't shadow prototype members. Downstream rule evaluators\n // do property reads on these dicts; a polluted prototype would surprise them.\n const query: Record<string, string> = Object.create(null);\n for (const [k, v] of queryEntries) {\n // First value wins on repeated keys — mirrors Hono's `c.req.query()`\n // behavior and matches what most APIs treat as canonical.\n if (!(k in query)) query[k] = v;\n }\n const headers: Record<string, string> = Object.create(null);\n for (const [k, v] of c.req.raw.headers.entries()) {\n headers[k.toLowerCase()] = v;\n }\n // c.req.param() returns all path params for this matched route. Hono returns\n // a plain object; copy onto a null-prototype dict so consumers can't be\n // tripped by an attacker setting `__proto__` as a path-param name.\n const honoParams: Record<string, string> = c.req.param();\n const pathParams: Record<string, string> = Object.create(null);\n for (const k of Object.keys(honoParams)) {\n pathParams[k] = honoParams[k];\n }\n const cookies = parseCookieHeader(headers['cookie']);\n\n // Body parsing is best-effort: only attempt JSON parse when the\n // Content-Type advertises JSON. Other body types stay opaque (string)\n // because validation rules don't currently target them.\n let bodyJson: unknown = undefined;\n let bodyText = '';\n const ct = headers['content-type'] ?? '';\n if (ct.toLowerCase().includes('json')) {\n try {\n bodyText = await c.req.text();\n bodyJson = bodyText ? (JSON.parse(bodyText) as unknown) : undefined;\n } catch {\n // Malformed JSON — leave bodyJson undefined; validation rules that\n // require body presence will still see bodyText.\n }\n } else {\n try {\n bodyText = await c.req.text();\n } catch {\n // ignore\n }\n }\n\n return { query, pathParams, headers, cookies, bodyText, bodyJson };\n}\n\nfunction parseCookieHeader(cookieHeader: string | undefined): Record<string, string> {\n const out: Record<string, string> = Object.create(null);\n if (!cookieHeader) return out;\n for (const part of cookieHeader.split(';')) {\n const eq = part.indexOf('=');\n if (eq === -1) continue;\n const k = part.slice(0, eq).trim();\n const v = part.slice(eq + 1).trim();\n if (k && !(k in out)) out[k] = v;\n }\n return out;\n}\n\nasync function respond(\n c: Context,\n response: MockResponseConfig,\n ctx: RequestContext,\n): Promise<Response> {\n if (response.delayMs && response.delayMs > 0) {\n await new Promise((resolve) => setTimeout(resolve, response.delayMs));\n }\n\n const finalResponse = applyMultipliers(response, ctx);\n\n // Track whether the user-configured headers already pin Content-Type — if\n // they don't, we derive one from `body.type` so the browser can't MIME-sniff\n // a JSON/text body into HTML (XSS risk for any consumer that loads the\n // mock URL in an <iframe> or <script src>).\n let userSetContentType = false;\n for (const h of finalResponse.headers) {\n if (!h.enabled) continue;\n if (!h.key.trim()) continue;\n if (h.key.toLowerCase() === 'content-type') userSetContentType = true;\n c.header(h.key, h.value);\n }\n\n const body = finalResponse.body;\n if (!userSetContentType) {\n const defaultCt = defaultContentTypeFor(body.type);\n if (defaultCt) c.header('Content-Type', defaultCt);\n }\n // Belt-and-braces: tell browsers not to override the declared type. Without\n // this header, even a correct Content-Type can be sniffed away by old IE-\n // compatible heuristics in some Chromium edge cases.\n c.header('X-Content-Type-Options', 'nosniff');\n\n // No body / 204-style: respond with empty body and the configured status.\n if (body.type === 'none') {\n return c.body(null, finalResponse.status as 200);\n }\n if (body.type === 'binary' || body.type === 'form-data') {\n // The runtime doesn't materialize attachments yet — emit an empty body\n // so the headers + status still go out.\n return c.body(null, finalResponse.status as 200);\n }\n return c.body(body.content, finalResponse.status as 200);\n}\n\nfunction defaultContentTypeFor(bodyType: MockResponseConfig['body']['type']): string | null {\n switch (bodyType) {\n case 'json':\n return 'application/json; charset=utf-8';\n case 'text':\n return 'text/plain; charset=utf-8';\n case 'binary':\n return 'application/octet-stream';\n case 'form-data':\n return 'multipart/form-data';\n case 'none':\n default:\n return null;\n }\n}\n\n/**\n * Translate OpenAPI path templates (`/pets/{id}/items/{itemId}`) to Hono\n * route patterns (`/pets/:id/items/:itemId`). Hono treats `:` as the\n * param prefix; the OpenAPI braces are unsupported.\n *\n * Manual O(n) scan instead of `path.replace(/\\{[^}]+\\}/g, …)` so we don't\n * trip CodeQL's polynomial-regex detector on user-supplied paths from\n * imported OpenAPI specs.\n */\nexport function openApiPathToHono(path: string): string {\n let out = '';\n let i = 0;\n while (i < path.length) {\n if (path[i] === '{') {\n const close = path.indexOf('}', i + 1);\n if (close === -1) {\n out += path.slice(i);\n break;\n }\n out += ':' + path.slice(i + 1, close);\n i = close + 1;\n } else {\n out += path[i];\n i++;\n }\n }\n return out;\n}\n","// CORS middleware honoring `MockServer.cors`. Hono ships a `cors()`\n// middleware in `hono/cors`; we wrap it so the origins list comes from\n// the workspace doc instead of being hardcoded.\n\nimport { cors as honoCors } from 'hono/cors';\nimport type { MiddlewareHandler } from 'hono';\nimport type { MockServer } from '@apicircle/shared';\n\nexport function buildCors(config: MockServer['cors']): MiddlewareHandler | null {\n // Match the UI contract: CORS off (or enabled with no explicit origins) ⇒\n // same-origin only. We never silently wildcard. Users must list at least\n // one origin to opt into cross-origin access; see CorsSection in\n // MockServersPanel for the editor.\n if (!config.enabled) return null;\n if (config.origins.length === 0) return null;\n return honoCors({\n origin: config.origins,\n allowMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'],\n allowHeaders: ['Content-Type', 'Authorization', 'Accept', 'X-Requested-With'],\n exposeHeaders: ['Content-Type'],\n credentials: false,\n maxAge: 600,\n });\n}\n","// Pre-validation evaluator. Runs every enabled rule on the inbound\n// request; returns the first failing rule's `failResponse` (or null when\n// all pass). Order is significant — the editor lets users reorder.\n\nimport type { MockEndpoint, MockResponseConfig, MockValidationRule } from '@apicircle/shared';\nimport type { RequestContext } from '../rules/evaluate';\n\nexport function evaluateValidation(\n endpoint: MockEndpoint,\n ctx: RequestContext,\n): MockResponseConfig | null {\n for (const rule of endpoint.requestValidation) {\n if (!rule.enabled) continue;\n if (!rulePasses(rule, ctx)) {\n return rule.failResponse;\n }\n }\n return null;\n}\n\nfunction rulePasses(rule: MockValidationRule, ctx: RequestContext): boolean {\n switch (rule.kind) {\n case 'header-required': {\n const v = ctx.headers[rule.target.toLowerCase()];\n return v !== undefined && v !== '';\n }\n case 'header-equals': {\n const v = ctx.headers[rule.target.toLowerCase()];\n return v !== undefined && v === (rule.expected ?? '');\n }\n case 'header-matches': {\n const v = ctx.headers[rule.target.toLowerCase()];\n if (v === undefined) return false;\n return safeRegexTest(rule.expected, v);\n }\n case 'query-required': {\n const v = ctx.query[rule.target];\n return v !== undefined && v !== '';\n }\n case 'query-equals': {\n const v = ctx.query[rule.target];\n return v !== undefined && v === (rule.expected ?? '');\n }\n case 'query-matches': {\n const v = ctx.query[rule.target];\n if (v === undefined) return false;\n return safeRegexTest(rule.expected, v);\n }\n case 'cookie-required': {\n const v = ctx.cookies[rule.target];\n return v !== undefined && v !== '';\n }\n case 'body-required': {\n // Pass if either the parsed JSON body has at least one key/element\n // OR the raw text body is non-empty. Matches the user expectation\n // that any body — JSON or text — counts.\n if (ctx.bodyJson !== undefined && ctx.bodyJson !== null) {\n if (Array.isArray(ctx.bodyJson)) return ctx.bodyJson.length > 0;\n if (typeof ctx.bodyJson === 'object') {\n return Object.keys(ctx.bodyJson).length > 0;\n }\n return true;\n }\n return ctx.bodyText.length > 0;\n }\n case 'content-type-equals': {\n const ct = ctx.headers['content-type'] ?? '';\n // Strip parameters (`;charset=utf-8`) for the comparison so common\n // server-flavors of Content-Type still match a plain\n // `application/json` expectation.\n const main = ct.split(';')[0]?.trim().toLowerCase() ?? '';\n return main === (rule.expected ?? '').trim().toLowerCase();\n }\n }\n}\n\nfunction safeRegexTest(pattern: string | undefined, value: string): boolean {\n if (pattern === undefined) return false;\n try {\n const m = /^\\/(.*)\\/([a-z]*)$/.exec(pattern);\n const re = m ? new RegExp(m[1], m[2]) : new RegExp(pattern);\n return re.test(value);\n } catch {\n return false;\n }\n}\n","// Response-rule evaluator. Pure: takes an endpoint + the inbound request\n// context and returns the response config to send back. Disabled rules are\n// skipped; the first rule whose every clause matches wins. If no rule\n// matches, `defaultResponse` is returned.\n//\n// This module also defines `RequestContext` — the runtime-side view of an\n// inbound request, normalized so all evaluators read from the same shape.\n\nimport type {\n MockConditionClause,\n MockConditionOp,\n MockConditionScope,\n MockEndpoint,\n MockResponseConfig,\n} from '@apicircle/shared';\n\nexport interface RequestContext {\n /** Lowercased query keys → first value (repeats are dropped). */\n query: Record<string, string>;\n /** Path params resolved by Hono — original case preserved. */\n pathParams: Record<string, string>;\n /** Lowercased header names → value. */\n headers: Record<string, string>;\n /** Parsed cookies (Cookie header). Names case-preserved. */\n cookies: Record<string, string>;\n /** Raw body text (best-effort — empty string when unread or non-text). */\n bodyText: string;\n /** Parsed JSON body when the Content-Type advertised JSON; otherwise undefined. */\n bodyJson: unknown;\n}\n\nexport function evaluateResponseRules(\n endpoint: MockEndpoint,\n ctx: RequestContext,\n): MockResponseConfig {\n for (const rule of endpoint.responseRules) {\n if (!rule.enabled) continue;\n if (rule.when.length === 0) continue; // Defensive: a clause-less rule never fires.\n if (rule.when.every((clause) => matchesClause(clause, ctx))) {\n return rule.response;\n }\n }\n return endpoint.defaultResponse;\n}\n\nfunction matchesClause(clause: MockConditionClause, ctx: RequestContext): boolean {\n const actual = readScopeValue(clause.scope, clause.target, ctx);\n return applyOp(clause.op, actual, clause.value);\n}\n\nfunction readScopeValue(\n scope: MockConditionScope,\n target: string,\n ctx: RequestContext,\n): string | undefined {\n switch (scope) {\n case 'query':\n return ctx.query[target];\n case 'pathParam':\n return ctx.pathParams[target];\n case 'header':\n return ctx.headers[target.toLowerCase()];\n case 'cookie':\n return ctx.cookies[target];\n case 'body-json-path':\n return resolveJsonPathString(ctx.bodyJson, target);\n }\n}\n\nfunction applyOp(\n op: MockConditionOp,\n actual: string | undefined,\n expected: string | undefined,\n): boolean {\n switch (op) {\n case 'present':\n return actual !== undefined && actual !== '';\n case 'absent':\n return actual === undefined || actual === '';\n case 'equals':\n return actual !== undefined && expected !== undefined && actual === expected;\n case 'not-equals':\n return actual === undefined || expected === undefined || actual !== expected;\n case 'matches': {\n if (actual === undefined || expected === undefined) return false;\n try {\n const re = compileMaybeFlaggedRegex(expected);\n return re.test(actual);\n } catch {\n return false;\n }\n }\n case 'gt':\n case 'lt':\n case 'gte':\n case 'lte': {\n if (actual === undefined || expected === undefined) return false;\n const a = Number(actual);\n const e = Number(expected);\n if (!Number.isFinite(a) || !Number.isFinite(e)) return false;\n switch (op) {\n case 'gt':\n return a > e;\n case 'lt':\n return a < e;\n case 'gte':\n return a >= e;\n case 'lte':\n return a <= e;\n }\n }\n }\n}\n\n/**\n * Accept either a raw regex source (`^bearer .+`) or `/source/flags` form.\n * Mirrors how the editor surfaces the placeholder `/^bearer .+/i`.\n */\nfunction compileMaybeFlaggedRegex(input: string): RegExp {\n const m = /^\\/(.*)\\/([a-z]*)$/.exec(input);\n if (m) return new RegExp(m[1], m[2]);\n return new RegExp(input);\n}\n\n/**\n * Walk a `$.foo.bar[0]` style JSON path on a parsed body. Returns a string\n * coercion of the resolved value, or undefined when the path doesn't\n * resolve. Supports dot segments + numeric `[idx]`.\n *\n * Kept tiny + dependency-free — full jsonpath-plus support can land later\n * if users need the more exotic operators.\n */\nfunction resolveJsonPathString(body: unknown, jsonPath: string): string | undefined {\n const value = resolveJsonPath(body, jsonPath);\n if (value === undefined || value === null) return undefined;\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n return JSON.stringify(value);\n}\n\nexport function resolveJsonPath(body: unknown, jsonPath: string): unknown {\n if (body === undefined || body === null) return undefined;\n let path = jsonPath.trim();\n if (path.startsWith('$')) path = path.slice(1);\n if (path.startsWith('.')) path = path.slice(1);\n if (path === '') return body;\n\n let cursor: unknown = body;\n // Manual O(n) tokenizer: alternates dotted keys and `[…]` brackets.\n // Implemented as a state machine instead of a regex to avoid CodeQL's\n // polynomial-regex detector on user-authored JSON paths from mock rules.\n for (const key of iterJsonPathTokens(path)) {\n if (cursor === undefined || cursor === null) return undefined;\n if (Array.isArray(cursor)) {\n const idx = Number(key);\n if (!Number.isInteger(idx)) return undefined;\n cursor = cursor[idx];\n continue;\n }\n if (typeof cursor === 'object') {\n cursor = (cursor as Record<string, unknown>)[key];\n continue;\n }\n return undefined;\n }\n return cursor;\n}\n\nfunction* iterJsonPathTokens(path: string): Iterable<string> {\n let i = 0;\n while (i < path.length) {\n const ch = path[i];\n if (ch === '.' || ch === ']') {\n i++;\n continue;\n }\n if (ch === '[') {\n const close = path.indexOf(']', i + 1);\n if (close === -1) return;\n const inner = path.slice(i + 1, close);\n if (inner.length > 0) yield inner;\n i = close + 1;\n continue;\n }\n let j = i + 1;\n while (j < path.length) {\n const c = path[j];\n if (c === '.' || c === '[' || c === ']') break;\n j++;\n }\n yield path.slice(i, j);\n i = j;\n }\n}\n","// Response multipliers — read a value from the inbound request, then repeat\n// the array element at `targetJsonPath` inside the response body that many\n// times. Only fires when the response body type is JSON; other body types\n// (text/xml/binary/etc.) are returned unchanged.\n//\n// The config holds an ARRAY of multipliers (`MockResponseConfig.multipliers`).\n// The authoring surfaces currently cap it at MAX_RESPONSE_MULTIPLIERS (1), but\n// the runtime applies every entry it finds — so bumping the cap (or a manual\n// edit) needs no engine change.\n//\n// Fallback rule: when the source value is missing or doesn't coerce to a\n// finite integer, fall back to `defaultCount`. The resolved count is\n// clamped to `[min, max]` when those bounds are set.\n//\n// Edge cases:\n// • The targetJsonPath doesn't resolve to an array → no-op (we don't\n// warn here — buildRouter has nowhere to log; the editor lints).\n// • The array is empty → no-op (no template to repeat).\n// • The body string isn't valid JSON → no-op (returns the original).\n\nimport type { MockResponseConfig, MockResponseMultiplier } from '@apicircle/shared';\nimport { resolveJsonPath } from '../rules/evaluate';\nimport type { RequestContext } from '../rules/evaluate';\n\nexport function applyMultipliers(\n response: MockResponseConfig,\n ctx: RequestContext,\n): MockResponseConfig {\n const multipliers = response.multipliers;\n if (!multipliers || multipliers.length === 0) return response;\n if (response.body.type !== 'json') return response;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(response.body.content);\n } catch {\n return response;\n }\n\n let mutated = false;\n for (const multiplier of multipliers) {\n const count = resolveCount(multiplier, ctx);\n if (count === null) continue;\n const next = applyOneMultiplier(parsed, multiplier.targetJsonPath, count);\n if (next.changed) {\n parsed = next.value;\n mutated = true;\n }\n }\n\n if (!mutated) return response;\n\n return {\n ...response,\n body: { type: 'json', content: JSON.stringify(parsed) },\n };\n}\n\nfunction resolveCount(multiplier: MockResponseMultiplier, ctx: RequestContext): number | null {\n const raw = readSource(multiplier, ctx);\n let count: number;\n if (raw === undefined || raw === '' || raw === null) {\n count = multiplier.defaultCount;\n } else {\n const parsed = Number(raw);\n if (!Number.isFinite(parsed)) {\n count = multiplier.defaultCount;\n } else {\n count = Math.trunc(parsed);\n }\n }\n\n if (multiplier.min !== undefined && count < multiplier.min) count = multiplier.min;\n if (multiplier.max !== undefined && count > multiplier.max) count = multiplier.max;\n if (count < 0) count = 0;\n return count;\n}\n\nfunction readSource(multiplier: MockResponseMultiplier, ctx: RequestContext): unknown {\n const { kind, key } = multiplier.source;\n switch (kind) {\n case 'query':\n return ctx.query[key];\n case 'pathParam':\n return ctx.pathParams[key];\n case 'header':\n return ctx.headers[key.toLowerCase()];\n case 'body-json-path':\n return resolveJsonPath(ctx.bodyJson, key);\n }\n}\n\ninterface ApplyResult {\n changed: boolean;\n value: unknown;\n}\n\n/**\n * Walk the JSON path on the parsed body, repeat the first array element\n * `count` times, and return the new tree. Pure — never mutates `body`.\n */\nfunction applyOneMultiplier(body: unknown, jsonPath: string, count: number): ApplyResult {\n const segments = parsePathSegments(jsonPath);\n if (segments.length === 0) {\n if (Array.isArray(body) && body.length > 0) {\n return { changed: true, value: repeatArray(body, count) };\n }\n return { changed: false, value: body };\n }\n return setAtPath(body, segments, 0, count);\n}\n\ntype PathSegment = { kind: 'key'; name: string } | { kind: 'index'; idx: number };\n\n// Names we never traverse into, even if the user-supplied path explicitly\n// requests them. `__proto__`/`constructor`/`prototype` always resolve via the\n// prototype chain on plain objects and have no place in a JSON multiplier.\nconst FORBIDDEN_KEYS: ReadonlySet<string> = new Set(['__proto__', 'constructor', 'prototype']);\n\nfunction parsePathSegments(jsonPath: string): PathSegment[] {\n let path = jsonPath.trim();\n if (path.startsWith('$')) path = path.slice(1);\n if (path.startsWith('.')) path = path.slice(1);\n if (path === '') return [];\n\n // Manual O(n) tokenizer instead of a regex with alternation — avoids\n // CodeQL's polynomial-regex detector on user-authored multiplier paths.\n const out: PathSegment[] = [];\n let i = 0;\n while (i < path.length) {\n const ch = path[i];\n if (ch === '.' || ch === ']') {\n i++;\n continue;\n }\n if (ch === '[') {\n const close = path.indexOf(']', i + 1);\n if (close === -1) break;\n const inner = path.slice(i + 1, close);\n if (inner.length > 0) {\n const n = Number(inner);\n if (Number.isInteger(n)) {\n out.push({ kind: 'index', idx: n });\n } else {\n if (FORBIDDEN_KEYS.has(inner)) return [];\n out.push({ kind: 'key', name: inner });\n }\n }\n i = close + 1;\n continue;\n }\n let j = i + 1;\n while (j < path.length) {\n const c = path[j];\n if (c === '.' || c === '[' || c === ']') break;\n j++;\n }\n const name = path.slice(i, j);\n if (FORBIDDEN_KEYS.has(name)) return [];\n out.push({ kind: 'key', name });\n i = j;\n }\n return out;\n}\n\nfunction setAtPath(\n cursor: unknown,\n segments: PathSegment[],\n depth: number,\n count: number,\n): ApplyResult {\n if (depth === segments.length) {\n if (Array.isArray(cursor) && cursor.length > 0) {\n return { changed: true, value: repeatArray(cursor, count) };\n }\n return { changed: false, value: cursor };\n }\n const seg = segments[depth];\n if (seg.kind === 'index') {\n if (!Array.isArray(cursor)) return { changed: false, value: cursor };\n if (seg.idx < 0 || seg.idx >= cursor.length) return { changed: false, value: cursor };\n const inner = setAtPath(cursor[seg.idx], segments, depth + 1, count);\n if (!inner.changed) return { changed: false, value: cursor };\n const next = cursor.slice();\n next[seg.idx] = inner.value;\n return { changed: true, value: next };\n }\n // 'key' segment.\n if (cursor === null || typeof cursor !== 'object' || Array.isArray(cursor)) {\n return { changed: false, value: cursor };\n }\n const obj = cursor as Record<string, unknown>;\n if (!(seg.name in obj)) return { changed: false, value: cursor };\n const inner = setAtPath(obj[seg.name], segments, depth + 1, count);\n if (!inner.changed) return { changed: false, value: cursor };\n return { changed: true, value: { ...obj, [seg.name]: inner.value } };\n}\n\nfunction repeatArray(arr: unknown[], count: number): unknown[] {\n if (count <= 0) return [];\n const template = arr[0];\n const out: unknown[] = [];\n for (let i = 0; i < count; i++) {\n // Shallow-clone object templates so consumers don't get aliased\n // references — preserves the \"each item is its own object\" invariant\n // most paginated responses assume.\n out.push(cloneShallow(template));\n }\n return out;\n}\n\nfunction cloneShallow(value: unknown): unknown {\n if (value === null || typeof value !== 'object') return value;\n if (Array.isArray(value)) return value.slice();\n return { ...(value as Record<string, unknown>) };\n}\n","// Node.js runtime adapter. Wraps `@hono/node-server`'s `serve()` so the\n// public API can return a typed `MockServerHandle` regardless of the\n// underlying transport (Node / Bun / Workers).\n\nimport { serve, type ServerType } from '@hono/node-server';\nimport type { Hono } from 'hono';\nimport { getFreePort } from './portFinder';\n\nexport interface MockServerHandle {\n port: number;\n /** Stop the server. Resolves once the listener is closed. */\n close: () => Promise<void>;\n}\n\nexport interface ServeOptions {\n /** Use this port; if undefined or 0, pick a free port via portFinder. */\n port?: number;\n /** Bind address. Default `127.0.0.1` so the server isn't internet-exposed. */\n host?: string;\n}\n\n// Hard cap on how long we'll wait for a graceful close before treating the\n// server as stopped anyway. Node's `http.Server.close()` resolves only after\n// every open connection has ended — browsers hold keep-alive sockets open for\n// minutes after the last response, so without intervention `stop()` looks\n// like it hangs forever from the user's perspective. We force-drop sockets\n// (closeAllConnections / closeIdleConnections) before awaiting; the timeout\n// is the belt-and-braces fallback if a socket somehow refuses to die.\nconst CLOSE_TIMEOUT_MS = 3_000;\n\n/**\n * Thrown by `serveOnNode` when the requested port is invalid (non-integer,\n * negative, > 65535) OR the OS refuses to bind it (EADDRINUSE / EACCES /\n * EADDRNOTAVAIL). Carries `port`, `host`, and an OS-level `code` so the\n * UI / CLI / VS Code surfaces can render an actionable message instead of\n * Node's raw `listen EADDRINUSE …` line.\n *\n * `code` values you'll see in practice:\n * • `EADDRINUSE` — another process already owns the port\n * • `EACCES` — usually a port below 1024 without privileges\n * • `EADDRNOTAVAIL` — host string doesn't resolve to a local interface\n * • `INVALID_PORT` — caller passed something that isn't a 1-65535 integer\n */\nexport class MockServerStartError extends Error {\n readonly code: string;\n readonly port: number;\n readonly host: string;\n constructor(opts: { code: string; port: number; host: string; message: string }) {\n super(opts.message);\n this.name = 'MockServerStartError';\n this.code = opts.code;\n this.port = opts.port;\n this.host = opts.host;\n }\n}\n\nfunction explainBindError(code: string, port: number, host: string): string {\n switch (code) {\n case 'EADDRINUSE':\n return `Port ${port} on ${host} is already in use. Stop the other process or pick a different port.`;\n case 'EACCES':\n return `Permission denied binding to port ${port} on ${host}. Ports below 1024 usually require elevated privileges — pick a port in 1024–65535.`;\n case 'EADDRNOTAVAIL':\n return `Cannot bind to ${host}:${port} — that address is not available on this machine.`;\n default:\n return `Failed to bind ${host}:${port} (${code}).`;\n }\n}\n\nexport async function serveOnNode(app: Hono, opts: ServeOptions = {}): Promise<MockServerHandle> {\n const host = opts.host ?? '127.0.0.1';\n // `port: 0` (or absent) means \"OS picks a free port\" — we resolve that\n // up-front via getFreePort so the returned handle can report the actual\n // bound port. Any explicit port goes through validation first so we\n // throw a clean MockServerStartError instead of crashing inside\n // @hono/node-server with a raw RangeError.\n let port: number;\n if (opts.port === undefined || opts.port === 0) {\n port = await getFreePort();\n } else {\n if (!Number.isInteger(opts.port) || opts.port < 1 || opts.port > 65535) {\n throw new MockServerStartError({\n code: 'INVALID_PORT',\n port: opts.port,\n host,\n message: `Invalid port ${String(opts.port)} — must be an integer between 1 and 65535.`,\n });\n }\n port = opts.port;\n }\n\n let server: ServerType | null = null;\n await new Promise<void>((resolve, reject) => {\n const wrapError = (err: unknown) => {\n const candidate = err && typeof err === 'object' && 'code' in err ? err.code : undefined;\n const code = typeof candidate === 'string' ? candidate : 'UNKNOWN';\n reject(\n new MockServerStartError({\n code,\n port,\n host,\n message: explainBindError(code, port, host),\n }),\n );\n };\n try {\n server = serve(\n {\n fetch: app.fetch,\n port,\n hostname: host,\n },\n () => resolve(),\n );\n server.on('error', wrapError);\n } catch (err) {\n wrapError(err);\n }\n });\n\n return {\n port,\n close: () =>\n new Promise<void>((resolve) => {\n if (!server) return resolve();\n const s = server;\n // Force-drop every open socket (active + idle) before awaiting the\n // close callback. Node ≥18.2 exposes these as first-class APIs;\n // typed loosely here because @hono/node-server's ServerType union\n // doesn't include them.\n const withCloseHelpers = s as ServerType & {\n closeAllConnections?: () => void;\n closeIdleConnections?: () => void;\n };\n try {\n withCloseHelpers.closeIdleConnections?.();\n withCloseHelpers.closeAllConnections?.();\n } catch {\n // Best-effort: if a helper throws (older Node, exotic transport),\n // we still rely on the timeout below to bound the wait.\n }\n let settled = false;\n const settle = () => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve();\n };\n const timer = setTimeout(settle, CLOSE_TIMEOUT_MS);\n s.close(() => settle());\n }),\n };\n}\n","// Find a free TCP port. Listens on port 0 (OS assigns), captures the\n// chosen port, then releases the listener immediately. Standard pattern;\n// the caveat is the tiny race where a different process grabs the port\n// between our close and the caller's bind — but for desktop / CLI mock\n// servers this race is negligible.\n\nimport { createServer } from 'node:net';\n\nexport async function getFreePort(): Promise<number> {\n return new Promise<number>((resolve, reject) => {\n const server = createServer();\n server.unref();\n server.on('error', reject);\n server.listen(0, () => {\n const address = server.address();\n if (typeof address === 'object' && address !== null) {\n const port = address.port;\n server.close(() => resolve(port));\n } else {\n server.close(() => reject(new Error('Could not determine free port')));\n }\n });\n });\n}\n\nexport async function isPortFree(port: number): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n const server = createServer();\n server.unref();\n server.once('error', () => resolve(false));\n server.once('listening', () => {\n server.close(() => resolve(true));\n });\n server.listen(port);\n });\n}\n","// Public API for @apicircle/mock-server-core.\n//\n// The engine is split into:\n// • Parsers (OpenAPI / Postman / Insomnia → MockEndpoint[])\n// • Router builder (MockServer → Hono app, with per-endpoint overrides)\n// • Node runtime adapter (Hono app → live HTTP server)\n//\n// Consumers (Desktop / CLI / future hosted) call `parseSourceToEndpoints`\n// once when a MockServer is created or refreshed, then `startMockServer`\n// every time the user clicks Start.\n\nimport type { MockServer, MockServerSource, MockEndpoint } from '@apicircle/shared';\nimport type { Hono } from 'hono';\nimport { parseOpenApiToEndpoints } from './parsers/openapi';\nimport { parsePostmanToEndpoints } from './parsers/postman';\nimport { parseInsomniaToEndpoints } from './parsers/insomnia';\nimport { buildRouter, type BuildRouterOptions } from './handlers/buildRouter';\nimport { serveOnNode, type MockServerHandle, type ServeOptions } from './runtime/nodeAdapter';\n\nexport type { MockServerHandle, ServeOptions } from './runtime/nodeAdapter';\nexport { MockServerStartError } from './runtime/nodeAdapter';\nexport type { BuildRouterOptions } from './handlers/buildRouter';\nexport { openApiPathToHono } from './handlers/buildRouter';\nexport { parseOpenApiToEndpoints } from './parsers/openapi';\nexport { parsePostmanToEndpoints } from './parsers/postman';\nexport { parseInsomniaToEndpoints } from './parsers/insomnia';\nexport { schemaToExample } from './faker/schemaToExample';\nexport { getFreePort, isPortFree } from './runtime/portFinder';\nexport { buildRouter };\n\nexport interface ParseSourceResult {\n endpoints: MockEndpoint[];\n warnings: string[];\n}\n\n/**\n * Dispatch the right parser for a `MockServerSource`. Returns the\n * resolved `MockEndpoint[]` along with any non-fatal warnings the\n * parser surfaced. The caller persists `endpoints` onto\n * `MockServer.endpoints`.\n */\nexport async function parseSourceToEndpoints(source: MockServerSource): Promise<ParseSourceResult> {\n switch (source.kind) {\n case 'openapi':\n return parseOpenApiToEndpoints(source.spec, source.format);\n case 'postman':\n return parsePostmanToEndpoints(source.collection);\n case 'insomnia':\n return parseInsomniaToEndpoints(source.export);\n case 'manual':\n return { endpoints: source.endpoints, warnings: [] };\n }\n}\n\n/**\n * Build a Hono app for an in-memory MockServer without binding a port.\n * Useful for tests and for hosted/edge transports that bring their own\n * server.\n */\nexport function createMockApp(server: MockServer, opts: BuildRouterOptions = {}): Hono {\n return buildRouter(server, opts);\n}\n\n/**\n * Start a mock server on Node. Picks a free port when\n * `MockServer.defaultPort` is null or `opts.port` is omitted; otherwise\n * uses the requested port and errors if it's busy.\n */\nexport async function startMockServer(\n server: MockServer,\n opts: { port?: number; host?: string; onRequest?: BuildRouterOptions['onRequest'] } = {},\n): Promise<MockServerHandle> {\n const app = createMockApp(server, { onRequest: opts.onRequest });\n const desired: ServeOptions = {\n host: opts.host,\n port: opts.port ?? server.defaultPort ?? undefined,\n };\n return serveOnNode(app, desired);\n}\n\n/** Convenience: stop a previously-started server. */\nexport async function stopMockServer(handle: MockServerHandle): Promise<void> {\n return handle.close();\n}\n"],"mappings":"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","names":["makeDefaultRequestSchema","makeDefaultRequestSchema","makeDefaultRequestSchema","makeDefaultRequestSchema","SUPPORTED_METHODS","slug","makeDefaultRequestSchema","makeDefaultRequestSchema","SUPPORTED_METHODS","extractPath","slug","inner"]}
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@apicircle/mock-server-core",
3
- "version": "1.0.8",
3
+ "version": "1.1.0",
4
4
  "private": false,
5
5
  "type": "module",
6
+ "sideEffects": false,
6
7
  "description": "Hono-based mock server engine for API Circle. Parses OpenAPI/Postman/Insomnia into mock endpoints, serves them on Node/Bun/edge runtimes.",
7
8
  "keywords": [
8
9
  "apicircle",
@@ -58,7 +59,7 @@
58
59
  "hono": "^4.12.18",
59
60
  "@apidevtools/swagger-parser": "^10.1.0",
60
61
  "js-yaml": "^4.1.0",
61
- "@apicircle/shared": "1.0.8"
62
+ "@apicircle/shared": "1.1.0"
62
63
  },
63
64
  "devDependencies": {
64
65
  "@types/js-yaml": "^4.0.9",