{"_id":"@brentbroeckx/mock-hub","_rev":"5-9e84d02bc99afd98c5ee05284fa4b32f","name":"@brentbroeckx/mock-hub","dist-tags":{"latest":"0.3.0"},"versions":{"0.1.0":{"name":"@brentbroeckx/mock-hub","version":"0.1.0","keywords":["openapi","mock","api","cli","fastify","testing"],"license":"MIT","_id":"@brentbroeckx/mock-hub@0.1.0","maintainers":[{"name":"brentbroeckx","email":"brent.broeckx28@gmail.com"}],"homepage":"https://github.com/brent-broeckx/mock-hub#readme","bugs":{"url":"https://github.com/brent-broeckx/mock-hub/issues"},"bin":{"mock-hub":"dist/cli.js"},"dist":{"shasum":"909be18cde3b84397744003aa9478bf0a8f65805","tarball":"https://registry.npmjs.org/@brentbroeckx/mock-hub/-/mock-hub-0.1.0.tgz","fileCount":11,"integrity":"sha512-tj2h/92JWsF9C3vuiJuLK9GR2XmqR2evTCpR4ZnBnKQqQyGxoH3Y6EQRAVx0MZrRmm/CoJgPa3nutOYMdNbaiQ==","signatures":[{"sig":"MEUCIQCM0D6Zq4ZL2y52Cckrqej6HrY3Fb5SLoJ7CAN9AklkLQIgCxf5Ts5rlo0AyupkecadBCmps85hDuQriqobmVcRlDA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":136543},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"94eadc310350fe13c89a46fdd9ecb146bce8324e","scripts":{"dev":"tsx src/cli/index.ts run --spec ./scenarios/examples/default/openapi.yaml --source ./scenarios/examples/default/scenarios --scenario PartnerDown --ui --logging","build":"tsup","start":"node dist/cli.js run --spec ./scenarios/examples/default/openapi.yaml --source ./scenarios/examples/default/scenarios --scenario PartnerDown --ui --logging","prepack":"npm run build"},"_npmUser":{"name":"brentbroeckx","email":"brent.broeckx28@gmail.com"},"repository":{"url":"git+https://github.com/brent-broeckx/mock-hub.git","type":"git"},"_npmVersion":"11.6.2","description":"Integration Mock Hub - OpenAPI-driven mock server","directories":{},"_nodeVersion":"25.2.1","dependencies":{"ink":"^5.0.1","yaml":"^2.4.5","debug":"^4.3.7","react":"^18.2.0","fastify":"^4.26.2","commander":"^12.1.0","openapi-types":"^12.1.3","swagger-parser":"^10.0.3","ink-select-input":"^6.0.0","json-schema-faker":"^0.5.5"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","tsup":"^8.1.0","typescript":"^5.4.5","@types/node":"^20.11.30","@types/debug":"^4.1.12","@types/react":"^18.2.70"},"_npmOperationalInternal":{"tmp":"tmp/mock-hub_0.1.0_1769864456195_0.3297738514919284","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@brentbroeckx/mock-hub","version":"0.1.1","keywords":["openapi","mock","api","cli","fastify","testing"],"license":"MIT","_id":"@brentbroeckx/mock-hub@0.1.1","maintainers":[{"name":"brentbroeckx","email":"brent.broeckx28@gmail.com"}],"homepage":"https://github.com/brent-broeckx/mock-hub#readme","bugs":{"url":"https://github.com/brent-broeckx/mock-hub/issues"},"bin":{"mock-hub":"dist/cli.js"},"dist":{"shasum":"62370d0e44c526555a304f3d67f8be59f0608690","tarball":"https://registry.npmjs.org/@brentbroeckx/mock-hub/-/mock-hub-0.1.1.tgz","fileCount":11,"integrity":"sha512-lH8G/giDoRSQpNJXYJ9T3vgflABvhurqPKu7GKHKKcN5lwBcVX0YY8+e9FKNmJ9zne5+caXCyeVjrjII1dbLrw==","signatures":[{"sig":"MEQCID7q3thI2OU/47UZd/cU+TFi0py19Lt2P7QjdHfvWP9QAiADt+eoYL6zhUVJPHVpQu0RWG2NsWMqa/FO5WwbJQ8uXg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":137186},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"42e80de57158b770b0bf2ff91d0387d7834732c1","scripts":{"dev":"tsx src/cli/index.ts run --help","build":"tsup","start":"node dist/cli.js run --spec ./scenarios/examples/default/openapi.yaml --source ./scenarios/examples/default/scenarios --scenario PartnerDown --ui --logging","prepack":"npm run build"},"_npmUser":{"name":"brentbroeckx","email":"brent.broeckx28@gmail.com"},"repository":{"url":"git+https://github.com/brent-broeckx/mock-hub.git","type":"git"},"_npmVersion":"11.6.2","description":"Integration Mock Hub - OpenAPI-driven mock server","directories":{},"_nodeVersion":"25.2.1","dependencies":{"ink":"^5.0.1","yaml":"^2.4.5","debug":"^4.3.7","react":"^18.2.0","fastify":"^4.26.2","commander":"^12.1.0","openapi-types":"^12.1.3","swagger-parser":"^10.0.3","ink-select-input":"^6.0.0","json-schema-faker":"^0.5.5"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","tsup":"^8.1.0","typescript":"^5.4.5","@types/node":"^20.11.30","@types/debug":"^4.1.12","@types/react":"^18.2.70"},"_npmOperationalInternal":{"tmp":"tmp/mock-hub_0.1.1_1769865495548_0.14307665116405843","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@brentbroeckx/mock-hub","version":"0.2.0","keywords":["openapi","mock","api","cli","fastify","testing"],"license":"MIT","_id":"@brentbroeckx/mock-hub@0.2.0","maintainers":[{"name":"brentbroeckx","email":"brent.broeckx28@gmail.com"}],"homepage":"https://github.com/brent-broeckx/mock-hub#readme","bugs":{"url":"https://github.com/brent-broeckx/mock-hub/issues"},"bin":{"mock-hub":"dist/cli.js"},"dist":{"shasum":"375f4fee787f06a269f989e911bbbd10680b5512","tarball":"https://registry.npmjs.org/@brentbroeckx/mock-hub/-/mock-hub-0.2.0.tgz","fileCount":11,"integrity":"sha512-ClKiEuaohbyd1sI8AdAGA2ZevBRhKAH9Hr7v/Or9IIesnzKa8ap6iGLYKsRyAElnOgPx6ezeLG4EtlV+ARHVjA==","signatures":[{"sig":"MEYCIQCiGvY1QgW3VGvKPWTyF4OT/UoMDP2yC0nPgFfSmVFWBQIhAIDTXFuyBNcL6a04UvbXszSyEFY7GWvv9V1oig2ylDl4","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":185733},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"880780a73bc3aa6fe0f28748f00d5d199d8a2f1b","scripts":{"dev":"tsx src/cli/index.ts run --spec ./scenarios/examples/templating/openapi.yaml --source ./scenarios/examples/templating/scenarios --ui --logging","build":"tsup","start":"node dist/cli.js run --spec ./scenarios/examples/default/openapi.yaml --source ./scenarios/examples/default/scenarios --scenario PartnerDown --ui --logging","prepack":"npm run build"},"_npmUser":{"name":"brentbroeckx","email":"brent.broeckx28@gmail.com"},"repository":{"url":"git+https://github.com/brent-broeckx/mock-hub.git","type":"git"},"_npmVersion":"11.6.2","description":"Integration Mock Hub - OpenAPI-driven mock server","directories":{},"_nodeVersion":"25.2.1","dependencies":{"ink":"^5.0.1","yaml":"^2.4.5","react":"^18.2.0","fastify":"^4.26.2","commander":"^12.1.0","openapi-types":"^12.1.3","swagger-parser":"^10.0.3","ink-select-input":"^6.0.0","json-schema-faker":"^0.5.5"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","tsup":"^8.1.0","typescript":"^5.4.5","@types/node":"^20.11.30","@types/debug":"^4.1.12","@types/react":"^18.2.70"},"_npmOperationalInternal":{"tmp":"tmp/mock-hub_0.2.0_1769970423441_0.5428998056911456","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@brentbroeckx/mock-hub","version":"0.2.1","keywords":["openapi","mock","api","cli","fastify","testing"],"license":"MIT","_id":"@brentbroeckx/mock-hub@0.2.1","maintainers":[{"name":"brentbroeckx","email":"brent.broeckx28@gmail.com"}],"homepage":"https://github.com/brent-broeckx/mock-hub#readme","bugs":{"url":"https://github.com/brent-broeckx/mock-hub/issues"},"bin":{"mock-hub":"dist/cli.js"},"dist":{"shasum":"7803c1b17b553b09624137f956cbd5f9d25ca834","tarball":"https://registry.npmjs.org/@brentbroeckx/mock-hub/-/mock-hub-0.2.1.tgz","fileCount":11,"integrity":"sha512-mdfRwWhGxg75pPYB1JMQVOWu8A4ev6la88LqEkzC9azgLKdP9mmT9yKbvNGvSn9xntiZM8NBqLPpMn76qn+m0g==","signatures":[{"sig":"MEQCICvkRo8RUFGF4m/JndNY8uh9Tjaep8tldg03EPgjuzsLAiAYGfASiCvp6YnlQFH+yKlitjdWktVW85Kiz+lXkwYDNA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":188065},"type":"module","types":"./dist/index.d.ts","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"abfbde0b0daaf63ac82eb38d4a691207b0f8897c","scripts":{"dev":"tsx src/cli/index.ts run --spec ./scenarios/examples/templating/openapi.yaml --source ./scenarios/examples/templating/scenarios --ui --logging","build":"tsup","start":"node dist/cli.js run --spec ./scenarios/examples/default/openapi.yaml --source ./scenarios/examples/default/scenarios --scenario PartnerDown --ui --logging","prepack":"npm run build"},"_npmUser":{"name":"brentbroeckx","email":"brent.broeckx28@gmail.com"},"repository":{"url":"git+https://github.com/brent-broeckx/mock-hub.git","type":"git"},"_npmVersion":"11.7.0","description":"Integration Mock Hub - OpenAPI-driven mock server","directories":{},"_nodeVersion":"25.2.1","dependencies":{"ink":"^5.0.1","yaml":"^2.4.5","react":"^18.2.0","fastify":"^4.26.2","commander":"^12.1.0","openapi-types":"^12.1.3","swagger-parser":"^10.0.3","ink-select-input":"^6.0.0","json-schema-faker":"^0.5.5"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","tsup":"^8.1.0","typescript":"^5.4.5","@types/node":"^20.11.30","@types/debug":"^4.1.12","@types/react":"^18.2.70"},"_npmOperationalInternal":{"tmp":"tmp/mock-hub_0.2.1_1769978592040_0.5482889842479364","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@brentbroeckx/mock-hub","version":"0.3.0","description":"Integration Mock Hub - OpenAPI-driven mock server","type":"module","bin":{"mock-hub":"dist/cli.js"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"types":"./dist/index.d.ts","engines":{"node":">=18"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/brent-broeckx/mock-hub.git"},"bugs":{"url":"https://github.com/brent-broeckx/mock-hub/issues"},"homepage":"https://github.com/brent-broeckx/mock-hub#readme","keywords":["openapi","mock","api","cli","fastify","testing"],"scripts":{"build":"tsup","prepack":"npm run build","dev":"tsx src/cli/index.ts run --spec ./scenarios/examples/templating/openapi.yaml --source ./scenarios/examples/templating/scenarios --ui --logging","start":"node dist/cli.js run --spec ./scenarios/examples/default/openapi.yaml --source ./scenarios/examples/default/scenarios --scenario PartnerDown --ui --logging","test":"vitest","test:ci":"npm run build && vitest run --reporter=verbose --no-watch --coverage=false"},"dependencies":{"commander":"^12.1.0","fastify":"^4.26.2","ink":"^5.0.1","ink-select-input":"^6.0.0","json-schema-faker":"^0.5.5","openapi-types":"^12.1.3","react":"^18.2.0","swagger-parser":"^10.0.3","yaml":"^2.4.5"},"devDependencies":{"@types/debug":"^4.1.12","@types/node":"^20.11.30","@types/react":"^18.2.70","execa":"^8.0.1","memfs":"^4.17.0","tsup":"^8.1.0","tsx":"^4.19.2","typescript":"^5.4.5","vitest":"^1.6.0"},"gitHead":"f573267b9bdfc2637fcc183a7e1bf69c2009e9d5","_id":"@brentbroeckx/mock-hub@0.3.0","_nodeVersion":"25.6.0","_npmVersion":"11.8.0","dist":{"integrity":"sha512-u2EfLFDUxW+aCySjKuv/Wuu+t1JoZkoZVkpQfYZ1+dgHl+l7s5MOZRef9uNU218afxbh+jzDD2k91h5Mrz/38Q==","shasum":"a34ae8c88b51389d8d8da83bf0732233f3e484c6","tarball":"https://registry.npmjs.org/@brentbroeckx/mock-hub/-/mock-hub-0.3.0.tgz","fileCount":11,"unpackedSize":217218,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDYCsiaQMfoP7ICoRnAK8cah12mIwMLXv2DC2Ul0b+1awIhAOHjxSe1xwwnj0O+Ah06o+t5Hzodg/p9jnJgU3VvQ0WG"}]},"_npmUser":{"name":"brentbroeckx","email":"brent.broeckx28@gmail.com"},"directories":{},"maintainers":[{"name":"brentbroeckx","email":"brent.broeckx28@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mock-hub_0.3.0_1770315344152_0.6891844419445967"},"_hasShrinkwrap":false}},"time":{"created":"2026-01-31T13:00:56.087Z","modified":"2026-02-05T18:15:44.396Z","0.1.0":"2026-01-31T13:00:56.351Z","0.1.1":"2026-01-31T13:18:15.680Z","0.2.0":"2026-02-01T18:27:03.625Z","0.2.1":"2026-02-01T20:43:12.202Z","0.3.0":"2026-02-05T18:15:44.301Z"},"bugs":{"url":"https://github.com/brent-broeckx/mock-hub/issues"},"license":"MIT","homepage":"https://github.com/brent-broeckx/mock-hub#readme","keywords":["openapi","mock","api","cli","fastify","testing"],"repository":{"type":"git","url":"git+https://github.com/brent-broeckx/mock-hub.git"},"description":"Integration Mock Hub - OpenAPI-driven mock server","maintainers":[{"name":"brentbroeckx","email":"brent.broeckx28@gmail.com"}],"readme":"# Integration Mock Hub\r\n\r\nOpenAPI-first mock server with deterministic scenario overrides and strict validation. Also supports proxy mode to intercept real backends.\r\n\r\n![mock-hub demo](https://raw.githubusercontent.com/brent-broeckx/mock-hub/refs/heads/main/assets/cli-mock-hub-example.gif)\r\n\r\n## Install\r\n\r\n```bash\r\nnpm i -D @brentbroeckx/mock-hub\r\n```\r\n\r\nRun without installing:\r\n\r\n```bash\r\nnpx mock-hub run --spec ./openapi.yaml --source ./scenarios\r\n```\r\n\r\nGlobal install:\r\n\r\n```bash\r\nnpm i -g @brentbroeckx/mock-hub\r\nmock-hub run --spec ./openapi.yaml --source ./scenarios\r\n```\r\n\r\n## Quick start\r\n\r\n1. Create an OpenAPI spec (example: [openapi.yaml](scenarios/examples/default/openapi.yaml)).\r\n2. (optional) Create a scenarios directory (example: [scenarios](scenarios)).\r\n3. Run the server:\r\n\r\n```bash\r\nnpx mock-hub run --spec ./openapi.yaml\r\nor\r\nnpx mock-hub run --spec ./openapi.yaml --source ./scenarios\r\n\r\n# Proxy mode (spec optional)\r\nnpx mock-hub run --proxy http://localhost:8080 --source ./scenarios\r\n```\r\n\r\n## CLI usage\r\n\r\n```bash\r\nmock-hub run [--spec <path>] [--proxy <baseUrl>] [--source <dir>] [--scenario <name>] [--ui] [--logging] [--port <number>] [--verbose]\r\n```\r\n\r\nHelp:\r\n\r\n```bash\r\nmock-hub run --help\r\n```\r\n\r\n### CLI options\r\n\r\n- `--spec <path>`: Path to OpenAPI spec (YAML or JSON). Required unless `--proxy` is used.\r\n- `--proxy <baseUrl>`: Enable proxy mode. For unmatched requests, forward to the real backend. Spec is optional in proxy mode.\r\n- `--source <dir>`: Directory containing `.yaml` scenario files. Optional; if omitted, happy-path responses are used.\r\n- `--scenario <name>`: Default scenario name to apply when no header override is provided.\r\n- `--ui`: Launch interactive scenario selector (Ink).\r\n- `--logging`: Enable deterministic logs (pretty in CLI/UI, JSONL in CI).\r\n- `--port <number>`: Port to run the mock server (default: 4010).\r\n\r\n### Examples\r\n\r\n```bash\r\nnpx mock-hub run --spec ./openapi.yaml\r\nnpx mock-hub run --spec ./openapi.yaml --source ./scenarios\r\nnpx mock-hub run --spec ./openapi.yaml --source ./scenarios --scenario PartnerDown\r\nnpx mock-hub run --spec ./openapi.yaml --source ./scenarios --ui\r\nnpx mock-hub run --spec ./openapi.yaml --source ./scenarios --logging\r\nnpx mock-hub run --proxy http://localhost:8080 --source ./scenarios\r\nnpx mock-hub run --proxy http://localhost:8080 --source ./scenarios --scenario RateLimited\r\n```\r\n\r\n## CI Usage\r\n\r\nUse the mock server in CI to make integration points deterministic, fast, and isolated from external system availability.\r\n\r\n### Typical CI Flow\r\n\r\n- Start the mock server on a known port with a fixed scenario and deterministic logging.\r\n- Run your test suite against `http://localhost:<port>`.\r\n- Let the pipeline cleanly shut down the server after tests complete.\r\n\r\n### Example: Backend Integration Tests\r\n\r\n```bash\r\nCI=1 npx mock-hub run --spec ./openapi.yaml --source ./scenarios --scenario PartnerDown --port 4010 --logging\r\n\r\nBASE_URL=http://localhost:4010 npm test\r\n\r\n# Force a single request via header (override for one call in your tests)\r\ncurl -s -H \"X-MockHub-Scenario: PartnerDown\" http://localhost:4010/contracts >/dev/null\r\n```\r\n\r\n### Example: Frontend E2E Tests\r\n\r\n```bash\r\nCI=1 npx mock-hub run --spec ./openapi.yaml --source ./scenarios --scenario HappyPath --port 4010 --logging\r\n\r\nBASE_URL=http://localhost:4010 npx playwright test\r\n```\r\n\r\n### Example: Forcing Error Scenarios\r\n\r\n```bash\r\nCI=1 npx mock-hub run --spec ./openapi.yaml --source ./scenarios --scenario PartnerDown --port 4010 --logging\r\n\r\n# Validate 503 handling\r\ncurl -i -H \"X-MockHub-Scenario: PartnerDown\" http://localhost:4010/contracts\r\n\r\n# Validate 500 handling using another scenario\r\ncurl -i -H \"X-MockHub-Scenario: PaymentFailed\" http://localhost:4010/payments\r\n```\r\n\r\n### Notes on Determinism\r\n\r\n- Same input $\\rightarrow$ same output.\r\n- No random behavior or time‑dependent responses.\r\n- Safe to run in parallel CI jobs when using unique ports per job.\r\n\r\n### What Not to Use in CI\r\n\r\n- UI mode (`--ui`): requires interactive terminals and is non‑deterministic for automation.\r\n- Interactive scenario switching: can introduce state drift across parallel jobs.\r\n\r\n## Proxy mode\r\n\r\nProxy mode lets Mock Hub act as a selective interception proxy. By default, requests are forwarded to the real backend. Scenario rules can override or transform responses without changing your client code. Use this to validate error handling, latency, or headers while still hitting the real service.\r\n\r\nResolution order in proxy mode:\r\n\r\n1. Scenario match → scenario logic applies\r\n2. No match → forward to `--proxy <baseUrl>`\r\n\r\nNotes:\r\n\r\n- If a scenario rule defines `body` or `bodyFile`, the response is fully mocked (no proxy).\r\n- If a rule defines only overrides (status/headers/delay/timeout), the response is proxied and then transformed. The body of the original request is kept when present.\r\n- Happy-path OpenAPI mocks are disabled in proxy mode.\r\n\r\nProxy examples are available in [scenarios/examples/proxy/scenarios](scenarios/examples/proxy/scenarios).\r\n\r\n## Scenario file example\r\n\r\nSave as [scenarios/examples/default/scenarios/partner-down.yaml](scenarios/examples/default/scenarios/partner-down.yaml):\r\n\r\n```yaml\r\nscenario: PartnerDown\r\nversion: 1.0.0\r\ndescription: Simulate partner API being unavailable\r\nrules:\r\n  - id: partner-down-get\r\n    match:\r\n      path: /contracts/*\r\n      method: GET\r\n      headers:\r\n        X-User-Type: premium\r\n    respond:\r\n      status: 503\r\n      bodyFile: responses/partner_down.json\r\n      delayMs: 500\r\n      headers:\r\n        Retry-After: \"30\"\r\n  - id: dryrun-validation\r\n    match:\r\n      path: /contracts\r\n      method: POST\r\n      query:\r\n        dryRun: \"true\"\r\n    respond:\r\n      status: 400\r\n      body:\r\n        error: \"Dry-run validation failed\"\r\n        code: \"VALIDATION_ERROR\"\r\n```\r\n\r\nFor more examples take a look at: [Mock-hub Scenario examples](https://github.com/brent-broeckx/mock-hub/tree/main/scenarios/examples):\r\n\r\n## Header override\r\n\r\nPer-request override using `X-MockHub-Scenario`:\r\n\r\n```\r\nX-MockHub-Scenario: PartnerDown\r\n```\r\n\r\n## Configuration locations\r\n\r\n- OpenAPI spec: `--spec <path>` (YAML or JSON).\r\n- Scenarios directory: `--source <dir>` containing `.yaml` files and optional `responses/` files.\r\n\r\n## Response templating (scenario responses only)\r\n\r\nTemplating is supported only inside `respond.body` and `respond.bodyFile` (including nested objects/arrays) for scenario-defined responses. Templates are string-only and resolved per response generation.\r\n\r\n### Allowed helpers\r\n\r\n- `{{uuid}}` RFC 4122 v4 UUID (new value per response)\r\n- `{{now}}` ISO-8601 timestamp (evaluated at response time)\r\n- `{{increment}}` In-memory counter (increments per response, resets on process restart)\r\n\r\nNo arguments, no nesting, no conditionals, no loops.\r\n\r\n### Escaping\r\n\r\nUse `\\\\{{...}}` to output a literal `{{...}}`.\r\n\r\n### Example: inline body templating\r\n\r\n```yaml\r\nrespond:\r\n  status: 201\r\n  body:\r\n    id: \"{{uuid}}\"\r\n    createdAt: \"{{now}}\"\r\n    sequence: \"{{increment}}\"\r\n    note: \"Literal: \\\\{{not-a-template}}\"\r\n```\r\n\r\n### Example: bodyFile templating\r\n\r\nScenario:\r\n\r\n```yaml\r\nrespond:\r\n  status: 201\r\n  bodyFile: responses/templated_body.json\r\n```\r\n\r\nResponse file (templates allowed inside JSON string values):\r\n\r\n```json\r\n{\r\n  \"id\": \"{{uuid}}\",\r\n  \"createdAt\": \"{{now}}\",\r\n  \"sequence\": \"{{increment}}\"\r\n}\r\n```\r\n\r\n### Validation rules\r\n\r\n- Templates are only allowed in `respond.body` and `respond.bodyFile` string values (including nested objects/arrays).\r\n- Templates are not allowed in status codes, headers, match rules, delays/timeouts, or paths/methods.\r\n- Unknown helpers, arguments, nesting, malformed syntax, or templates in non-string values fail validation before startup.\r\n\r\n## Validation behavior (strict)\r\n\r\nValidation happens before any scenario execution. Invalid files fail fast with precise errors.\r\n\r\n### YAML-level\r\n\r\n- Syntax errors are rejected with file and line/column.\r\n- Duplicate keys are rejected.\r\n- Only known root keys are allowed.\r\n\r\n### Schema-level\r\n\r\n- No additional properties allowed.\r\n- Required fields must exist.\r\n- Arrays like `rules` must be non-empty.\r\n- Rule `id` values must be unique within a file.\r\n\r\n### Semantic checks\r\n\r\n- HTTP status must be $100$–$599$.\r\n- HTTP method must be valid (GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD).\r\n- `path` must start with `/` and may include at most one `*` wildcard.\r\n- `body` and `bodyFile` are mutually exclusive.\r\n- `delayMs`/`timeout` must be non-negative.\r\n- `version` must match `x.y.z`.\r\n\r\n### Cross-scenario checks\r\n\r\n- Scenario names must be unique.\r\n- Reserved scenario names (prefix `auto-gen-`) are rejected.\r\n\r\n### Error output example\r\n\r\n```\r\nERROR scenarios/auth.yaml:12:4\r\n ○ payment-failure: rules[0].match.method\r\n   → \"FETCH\" is not a valid HTTP method\r\n```\r\n\r\n## Project structure (recommended)\r\n\r\n```\r\n.\r\n├── src\r\n│   ├── cli\r\n│   ├── openapi\r\n│   ├── responses\r\n│   ├── rules\r\n│   ├── scenarios\r\n│   ├── server\r\n│   ├── state\r\n│   ├── ui\r\n│   └── ...\r\n├── dist\r\n├── scenarios\r\n└── openapi.yaml\r\n```\r\n","readmeFilename":"README.md"}