counterfact 2.14.0 → 2.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,61 +1,77 @@
1
1
  <div align="center" markdown="1">
2
2
 
3
- <h1><img src="./counterfact.svg" alt="Counterfact" border=0></h1>
3
+ <h1><img src="./counterfact.svg" alt="Counterfact" border="0"></h1>
4
4
 
5
- <br>
5
+ ![MIT License](https://img.shields.io/badge/license-MIT-blue) [![Coverage Status](https://coveralls.io/repos/github/counterfact/api-simulator/badge.svg)](https://coveralls.io/github/counterfact/api-simulator) ![Swagger 2.0](https://img.shields.io/badge/Swagger-2.0-85EA2D) ![OpenAPI 3.0–3.2](https://img.shields.io/badge/OpenAPI-3.x-6BA539) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/counterfact/api-simulator)
6
6
 
7
- ![MIT License](https://img.shields.io/badge/license-MIT-blue) [![Coverage Status](https://coveralls.io/repos/github/counterfact/api-simulator/badge.svg)](https://coveralls.io/github/pmcelhaney/counterfact) ![friction 0%](https://img.shields.io/badge/friction-0%25-brightgreen) ![Swagger 2.0](https://img.shields.io/badge/Swagger-2.0-85EA2D) ![OpenAPI 3.0-3.2](https://img.shields.io/badge/OpenAPI-3.x-6BA539)
7
+ ## Turn an OpenAPI document into an editable, stateful local API.
8
8
 
9
9
  </div>
10
10
 
11
- <div align="center" markdown="1">
12
- <h2>Mock servers work—until you need state, failures, or control mid-run.</h2>
13
- </div
11
+ Counterfact generates TypeScript handlers and request/response types for supported OpenAPI operations, then starts a local server. Begin with schema-derived sample responses; add shared state, failures, latency, middleware, or selective proxying as your workflow needs them. Route and context files hot-reload while their in-memory state stays available.
14
12
 
15
- Static responses aren’t enough. There’s no shared state. You can’t inject failures. You can’t test real workflows.<br>
16
- Mock servers make it easy to get started, but hard to keep going.<br>
17
- Counterfact is an API simulator without those limits.
13
+ Counterfact checks contract shape while giving you a path to shape the behavior. Start with schema-derived responses, then turn them into deterministic, stateful scenarios by editing the generated typed handlers and adding shared context. You can explore in seconds and keep the behavior you author as a repeatable local or CI fixture.
18
14
 
19
- Point it at an [OpenAPI](https://www.openapis.org) document and get a live, stateful API in seconds.
20
- Supports Swagger 2.0 and OpenAPI 3.0, 3.1, and 3.2.
21
- - Type-safe TypeScript handlers for every endpoint
22
- - Hot reloading as you edit
23
- - Shared state across routes
24
- - **A built-in REPL to control behavior at runtime**
25
- - Optional proxying to real backends
15
+ ## Run a live API in 60 seconds
26
16
 
27
- Flexbile for humans. Stable for [AI agents](https://github.com/counterfact/api-simulator/blob/main/docs/patterns/ai-assisted-implementation.md).
17
+ ```sh
18
+ npx counterfact@latest https://petstore3.swagger.io/api/v3/openapi.json api
19
+ ```
28
20
 
29
- You’re in control—without restarting.
21
+ This generates editable files in `api/`, starts the server at `http://localhost:3100`, serves Swagger UI at `http://localhost:3100/counterfact/swagger/`, and opens the live REPL. Exit with `.exit`, <kbd>Ctrl</kbd>+<kbd>D</kbd>, or <kbd>Ctrl</kbd>+<kbd>C</kbd> twice.
30
22
 
31
- For a *frontend developer* waiting on a backend,<br>
32
- a *test engineer* who needs clean, reproducible state,<br>
33
- or an *AI agent* that needs a stable API
23
+ Requires Node.js 22 or newer. For a repeatable project or CI workflow, install Counterfact as a dev dependency and commit the lockfile:
34
24
 
35
- Real enough to be useful. Fake enough to be usable.
25
+ ```sh
26
+ npm install --save-dev counterfact
27
+ npx counterfact ./openapi.yaml api
28
+ ```
36
29
 
30
+ ## Start with the workflow you need
37
31
 
38
- ## Try it now
32
+ | When you need to… | You can… | Start here |
33
+ | -------------------------------------- | ---------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
34
+ | Build ahead of your backend | Create a record, read it later, and shape the failure paths | [Build a stateful flow](./docs/first-10-minutes.md#build-a-stateful-flow) |
35
+ | Make failures repeatable | Reset, fail, recover, and tear down the same way every run | [Automate a deterministic test](./docs/first-10-minutes.md#automate-a-deterministic-test) |
36
+ | Give a coding agent a reliable sandbox | Leave a resettable context and an HTTP test for review | [Give an agent a verifiable task](./docs/first-10-minutes.md#give-an-agent-a-verifiable-task) |
37
+ | Bring endpoints online gradually | Keep one client base URL while paths move from local to upstream | [Run the checked hybrid path](./examples/first-10-minutes/#hybrid-path-ownership) |
38
+ | Keep the contract in the loop | Regenerate types and catch drift in your normal type check | [See a contract change reach a client](./examples/first-10-minutes/#see-a-contract-change-reach-the-client) |
39
39
 
40
- ```sh
41
- npx counterfact@latest https://petstore3.swagger.io/api/v3/openapi.json api
42
- ```
40
+ The [first-10-minutes guide](./docs/first-10-minutes.md) includes the shared setup, reset and isolation rules, CI lifecycle, and the boundary between contract checks and behavior realism.
41
+
42
+ Prefer a complete artifact to copy? The [CI-checked first-10-minutes example](./examples/first-10-minutes/) contains a minimal OpenAPI contract, resettable context, typed handlers, real-HTTP test, lockfile, and type-check configuration.
43
+
44
+ ## Confidence you can build on
45
+
46
+ | Where Counterfact helps | What you get | What remains yours |
47
+ | ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
48
+ | Generated TypeScript types | Supported status codes, media types, declared headers, and request/response shapes when your project runs a type check | The business rules that make the API truly yours |
49
+ | Request validation | Required query, header, and cookie parameters plus supported JSON/form bodies; detected mismatches return `400` | Authentication, authorization, path-parameter schemas, and business rules |
50
+ | Response checks | Required response headers and their schema types, with advisory `response-type-error` details when something is off | Response-body enforcement and production correctness |
51
+ | Your handlers, context, and scenarios | The state, rules, failures, reset behavior, and deterministic fixtures your workflow needs | Targeted real-backend and end-to-end coverage for the real service |
52
+
53
+ Counterfact gives you a fast, contract-shaped world to build against. Keep targeted real-backend and end-to-end coverage for the parts only the real service can prove. See [how to make the workflow yours](./docs/first-10-minutes.md#make-it-yours-with-confidence) for the practical checklist.
54
+
55
+ ## Project lifecycle
43
56
 
44
- > Starts a local server with a live REPL to inspect and control API behavior
45
- > Requires Node 22.0.0
57
+ - Commit your OpenAPI document, editable `routes/`, scenarios, and usually the generated `types/` so collaborators share a working contract snapshot.
58
+ - Regeneration overwrites generated types and may append scaffolding for newly added operations; it preserves existing handler bodies unless you explicitly use a destructive option such as `--prune`.
59
+ - In-memory context survives hot reload. A new process creates fresh context, and its constructor or `startup` scenario defines the initial state.
60
+ - Counterfact executes TypeScript route files, but it does not run a TypeScript type-check step for you. Include generated files in your project and run your normal type check in CI.
61
+ - Use a user-defined `reset()` in test setup, and use separate server instances and ports for parallel workers.
46
62
 
47
- ## Go deeper
63
+ ## Documentation
48
64
 
49
- - [Getting started](./docs/getting-started.md) – Detailed walkthrough with state, REPL, and proxy
50
- - [Patterns](./docs/patterns/index.md) – How Counterfact transforms your workflow
51
- - [Example repo](https://github.com/counterfact/example-petstore) – Using Counterfact to implement the Swagger Petstore
52
- - [How it compares](./docs/comparison.md) – json-server, WireMock, Prism, Microcks, MSW
53
- - [Usage](./docs/usage.md) – Explore features and how to use them
54
- - [Reference](./docs/reference.md) – `$` API, CLI flags, architecture
55
- - [FAQ](./docs/faq.md) – State, types, regeneration
65
+ - [Getting started](./docs/getting-started.md) – Generated files, state, REPL, proxying, and spec changes
66
+ - [Usage](./docs/usage.md) – Feature map
67
+ - [Patterns](./docs/patterns/index.md) – Reusable development and testing workflows
68
+ - [Reference](./docs/reference.md) – `$` API, CLI flags, and architecture
69
+ - [FAQ](./docs/faq.md) – State, types, validation, and regeneration
70
+ - [How it compares](./docs/comparison.md) – json-server, WireMock, Prism, Microcks, and MSW
71
+ - [Example repository](https://github.com/counterfact/example-petstore) – A larger Petstore implementation
56
72
 
57
73
  <div align="center" markdown="1">
58
74
 
59
- [Changelog](./CHANGELOG.md) · [Contributing](./CONTRIBUTING.md)
75
+ [Changelog](./CHANGELOG.md) · [Contributing](./CONTRIBUTING.md) · [Security](./SECURITY.md)
60
76
 
61
77
  </div>
@@ -33,6 +33,9 @@ export async function loadConfigFile(configPath, required = false) {
33
33
  }
34
34
  throw error;
35
35
  }
36
+ if (!content.trim()) {
37
+ return {};
38
+ }
36
39
  const parsed = loadYaml(content);
37
40
  if (parsed === null || parsed === undefined) {
38
41
  return {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "counterfact",
3
- "version": "2.14.0",
3
+ "version": "2.14.1",
4
4
  "description": "Generate a TypeScript-based mock server from an OpenAPI spec in seconds — with stateful routes, hot reload, and REPL support.",
5
5
  "type": "module",
6
6
  "main": "./dist/app.js",
@@ -65,7 +65,7 @@
65
65
  ],
66
66
  "sideEffects": false,
67
67
  "scripts": {
68
- "test": "yarn node --experimental-vm-modules ./node_modules/jest-cli/bin/jest --testPathIgnorePatterns=black-box",
68
+ "test": "yarn node --experimental-vm-modules ./node_modules/jest-cli/bin/jest --testPathIgnorePatterns=black-box --testPathIgnorePatterns=examples",
69
69
  "test:black-box": "rimraf dist && yarn build && python3 -m pytest test-black-box/ -v",
70
70
  "test:tsd": "tsd --typings ./dist/server/counterfact-types/index.ts --files ./test/**/*.test-d.ts",
71
71
  "build": "rm -rf dist && tsc && copyfiles -f \"src/counterfact-types/*.ts\" dist/server/counterfact-types && copyfiles -f \"src/server/*.cjs\" dist/server",
@@ -82,10 +82,10 @@
82
82
  "counterfact": "./bin/counterfact.js"
83
83
  },
84
84
  "devDependencies": {
85
- "@changesets/cli": "2.31.0",
85
+ "@changesets/cli": "2.31.1",
86
86
  "@eslint/js": "10.0.1",
87
87
  "@jest/globals": "30.4.1",
88
- "@swc/core": "1.15.40",
88
+ "@swc/core": "1.15.46",
89
89
  "@swc/jest": "0.2.39",
90
90
  "@testing-library/dom": "10.4.1",
91
91
  "@types/debug": "4.1.13",
@@ -96,44 +96,44 @@
96
96
  "@types/koa-proxy": "1.0.8",
97
97
  "@types/koa-static": "4.0.4",
98
98
  "@types/node": "22",
99
- "@typescript-eslint/eslint-plugin": "8.60.0",
100
- "@typescript-eslint/parser": "8.60.0",
99
+ "@typescript-eslint/eslint-plugin": "8.65.0",
100
+ "@typescript-eslint/parser": "8.65.0",
101
101
  "copyfiles": "2.4.1",
102
- "eslint": "10.4.0",
102
+ "eslint": "10.8.0",
103
103
  "eslint-formatter-github-annotations": "0.1.0",
104
- "eslint-import-resolver-typescript": "4.4.4",
104
+ "eslint-import-resolver-typescript": "4.4.5",
105
105
  "eslint-plugin-etc": "2.0.3",
106
106
  "eslint-plugin-file-progress": "4.0.0",
107
107
  "eslint-plugin-import": "2.32.0",
108
- "eslint-plugin-jest": "29.15.2",
109
- "eslint-plugin-jest-dom": "5.5.0",
110
- "eslint-plugin-n": "18.0.1",
108
+ "eslint-plugin-jest": "29.16.0",
109
+ "eslint-plugin-jest-dom": "5.6.0",
110
+ "eslint-plugin-n": "18.2.2",
111
111
  "eslint-plugin-no-explicit-type-exports": "0.12.1",
112
- "eslint-plugin-prettier": "5.5.5",
112
+ "eslint-plugin-prettier": "5.5.6",
113
113
  "eslint-plugin-promise": "7.3.0",
114
- "eslint-plugin-regexp": "3.1.0",
115
- "eslint-plugin-security": "4.0.0",
114
+ "eslint-plugin-regexp": "3.1.1",
115
+ "eslint-plugin-security": "4.0.1",
116
116
  "eslint-plugin-unused-imports": "4.4.1",
117
117
  "husky": "9.1.7",
118
118
  "jest": "30.4.2",
119
119
  "jest-retries": "1.0.1",
120
- "node-mocks-http": "1.17.2",
120
+ "node-mocks-http": "1.18.1",
121
121
  "rimraf": "6.1.3",
122
122
  "supertest": "7.2.2",
123
123
  "tsd": "0.33.0",
124
124
  "using-temporary-files": "2.2.1"
125
125
  },
126
126
  "dependencies": {
127
- "@apidevtools/json-schema-ref-parser": "15.3.5",
127
+ "@apidevtools/json-schema-ref-parser": "15.5.0",
128
128
  "@hapi/accept": "6.0.3",
129
129
  "@types/json-schema": "7.0.15",
130
130
  "ajv": "8.20.0",
131
131
  "chokidar": "5.0.0",
132
- "commander": "14.0.3",
132
+ "commander": "15.0.0",
133
133
  "debug": "4.4.3",
134
- "fs-extra": "11.3.5",
134
+ "fs-extra": "11.4.0",
135
135
  "http-terminator": "3.2.0",
136
- "js-yaml": "4.1.1",
136
+ "js-yaml": "5.2.2",
137
137
  "json-schema-faker": "0.6.2",
138
138
  "jsonpath-plus": "10.4.0",
139
139
  "jsonwebtoken": "9.0.3",
@@ -143,16 +143,15 @@
143
143
  "koa2-swagger-ui": "5.12.0",
144
144
  "node-fetch": "3.3.2",
145
145
  "open": "11.0.0",
146
- "posthog-node": "5.35.5",
147
- "precinct": "13.0.0",
148
- "prettier": "3.8.3",
149
- "recast": "0.23.11",
150
- "tsx": "4.22.3",
146
+ "posthog-node": "5.46.0",
147
+ "precinct": "13.0.1",
148
+ "prettier": "3.8.5",
149
+ "recast": "0.23.12",
150
+ "tsx": "4.23.1",
151
151
  "typescript": "6.0.3"
152
152
  },
153
153
  "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e",
154
154
  "resolutions": {
155
- "js-yaml": "4.1.1",
156
155
  "@typescript-eslint/utils": "^8.58.0"
157
156
  }
158
157
  }