counterfact 2.7.0 → 2.9.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/README.md +5 -160
- package/bin/README.md +39 -14
- package/bin/counterfact.js +18 -539
- package/bin/ts-loader.mjs +1 -0
- package/dist/api-runner.js +202 -0
- package/dist/app.js +102 -114
- package/dist/cli/banner.js +81 -0
- package/dist/cli/check-for-updates.js +45 -0
- package/dist/cli/run.js +304 -0
- package/dist/cli/telemetry.js +50 -0
- package/dist/migrate/paths-to-routes.js +1 -0
- package/dist/migrate/update-route-types.js +3 -3
- package/dist/msw.js +78 -0
- package/dist/repl/raw-http-client.js +22 -1
- package/dist/repl/repl.js +250 -63
- package/dist/repl/route-builder.js +68 -0
- package/dist/server/constants.js +8 -0
- package/dist/server/context-registry.js +54 -1
- package/dist/server/determine-module-kind.js +14 -0
- package/dist/server/dispatcher.js +46 -0
- package/dist/server/file-discovery.js +21 -9
- package/dist/server/is-proxy-enabled-for-path.js +12 -0
- package/dist/server/json-to-xml.js +10 -0
- package/dist/server/load-openapi-document.js +4 -11
- package/dist/server/module-dependency-graph.js +25 -0
- package/dist/server/module-loader.js +52 -21
- package/dist/server/module-tree.js +36 -0
- package/dist/server/openapi-document.js +69 -0
- package/dist/server/registry.js +89 -0
- package/dist/server/response-builder.js +15 -0
- package/dist/server/scenario-registry.js +26 -0
- package/dist/server/tools.js +27 -0
- package/dist/server/transpiler.js +24 -9
- package/dist/server/{admin-api-middleware.js → web-server/admin-api-middleware.js} +19 -9
- package/dist/server/web-server/create-koa-app.js +68 -0
- package/dist/server/web-server/openapi-middleware.js +34 -0
- package/dist/server/{koa-middleware.js → web-server/routes-middleware.js} +26 -6
- package/dist/typescript-generator/code-generator.js +118 -4
- package/dist/typescript-generator/coder.js +76 -0
- package/dist/typescript-generator/operation-coder.js +12 -4
- package/dist/typescript-generator/operation-type-coder.js +39 -4
- package/dist/typescript-generator/parameters-type-coder.js +2 -4
- package/dist/typescript-generator/prune.js +3 -1
- package/dist/typescript-generator/repository.js +77 -20
- package/dist/typescript-generator/requirement.js +69 -0
- package/dist/typescript-generator/{generate.js → scenario-file-generator.js} +99 -81
- package/dist/typescript-generator/script.js +70 -7
- package/dist/typescript-generator/specification.js +27 -0
- package/dist/util/ensure-directory-exists.js +8 -0
- package/dist/util/forward-slash-path.js +63 -0
- package/dist/util/load-config-file.js +2 -2
- package/dist/util/read-file.js +27 -2
- package/dist/util/runtime-can-execute-erasable-ts.js +12 -0
- package/dist/util/windows-escape.js +18 -0
- package/package.json +5 -4
- package/dist/server/create-koa-app.js +0 -42
- package/dist/server/openapi-middleware.js +0 -19
package/README.md
CHANGED
|
@@ -4,174 +4,19 @@
|
|
|
4
4
|
|
|
5
5
|
<br>
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
**Counterfact turns your OpenAPI spec into a live, stateful API you can program in TypeScript.**
|
|
10
|
-
|
|
11
|
-
<br>
|
|
12
|
-
|
|
13
|
-
 [](https://github.com/ellerbrock/typescript-badges/) [](https://coveralls.io/github/pmcelhaney/counterfact)
|
|
7
|
+
 [](https://github.com/ellerbrock/typescript-badges/) [](https://coveralls.io/github/pmcelhaney/counterfact)
|
|
14
8
|
|
|
15
9
|
</div>
|
|
16
10
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Built for frontend developers, test engineers, and AI agents that need a predictable API to work against.
|
|
11
|
+
You've used mock servers. You know where they stop being useful: static responses, no shared state, no way to inject a failure mid-run, no control without restarting. Counterfact picks up where they leave off.
|
|
20
12
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
## Minute 1 — Start the server
|
|
13
|
+
Point it at an OpenAPI spec and it generates TypeScript handlers for every endpoint—type-safe, hot-reloading, sharing state across routes. A built-in REPL gives you a live control surface: seed data, trigger error conditions, proxy individual routes to a real backend, all on a running server. Whether you're a frontend developer waiting on a backend, a test engineer who needs clean reproducible state, or an AI agent that needs a stable API to work against, Counterfact is the simulator that doesn't plateau.
|
|
24
14
|
|
|
25
15
|
```sh
|
|
26
16
|
npx counterfact@latest https://petstore3.swagger.io/api/v3/openapi.json api
|
|
27
17
|
```
|
|
28
18
|
|
|
29
|
-
>
|
|
30
|
-
|
|
31
|
-
That’s it.
|
|
32
|
-
|
|
33
|
-
Counterfact reads your spec, generates a TypeScript handler for every endpoint, and starts a server at `http://localhost:3100`.
|
|
34
|
-
|
|
35
|
-
Open `http://localhost:3100/counterfact/swagger/`.
|
|
36
|
-
|
|
37
|
-
Every endpoint is already live, returning random, schema-valid responses. No code written yet.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
## Minute 2 — Make a route return real data
|
|
42
|
-
|
|
43
|
-
Open the generated file for `GET /pet/{petId}`:
|
|
44
|
-
|
|
45
|
-
```ts
|
|
46
|
-
import type { HTTP_GET } from "../../types/paths/pet/{petId}.types.js";
|
|
47
|
-
|
|
48
|
-
export const GET: HTTP_GET = ($) => $.response[200].random();
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
Replace `.random()` with your own logic:
|
|
52
|
-
|
|
53
|
-
```ts
|
|
54
|
-
export const GET: HTTP_GET = ($) => {
|
|
55
|
-
if ($.path.petId === 99) {
|
|
56
|
-
return $.response[404].text("Pet not found");
|
|
57
|
-
}
|
|
58
|
-
return $.response[200].json({
|
|
59
|
-
id: $.path.petId,
|
|
60
|
-
name: "Fluffy",
|
|
61
|
-
status: "available",
|
|
62
|
-
photoUrls: []
|
|
63
|
-
});
|
|
64
|
-
};
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
Save the file. The server reloads instantly—no restart, no lost state.
|
|
68
|
-
|
|
69
|
-
TypeScript enforces the contract. If your response doesn’t match the spec, you’ll know before you make the request.
|
|
70
|
-
|
|
71
|
-
## Minute 3 — Add state that survives across requests
|
|
72
|
-
|
|
73
|
-
Real APIs have memory. Yours should too.
|
|
74
|
-
|
|
75
|
-
Create `api/routes/_.context.ts`:
|
|
76
|
-
|
|
77
|
-
```ts
|
|
78
|
-
import type { Pet } from "../types/components/pet.types.js";
|
|
79
|
-
|
|
80
|
-
export class Context {
|
|
81
|
-
private pets = new Map<number, Pet>();
|
|
82
|
-
private nextId = 1;
|
|
83
|
-
|
|
84
|
-
add(data: Omit<Pet, "id">): Pet {
|
|
85
|
-
const pet = { ...data, id: this.nextId++ };
|
|
86
|
-
this.pets.set(pet.id, pet);
|
|
87
|
-
return pet;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
get(id: number): Pet | undefined { return this.pets.get(id); }
|
|
91
|
-
list(): Pet[] { return [...this.pets.values()]; }
|
|
92
|
-
remove(id: number): void { this.pets.delete(id); }
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
Use it in your routes:
|
|
97
|
-
|
|
98
|
-
```ts
|
|
99
|
-
export const GET: HTTP_GET = ($) => $.response[200].json($.context.list());
|
|
100
|
-
export const POST: HTTP_POST = ($) => $.response[200].json($.context.add($.body));
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
Now your API behaves like a real system:
|
|
104
|
-
- POST creates data
|
|
105
|
-
- GET returns it
|
|
106
|
-
- DELETE removes it
|
|
107
|
-
|
|
108
|
-
State survives hot reloads. Restarting resets everything—perfect for clean test runs.
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
## Minute 4 — Control the system at runtime (REPL)
|
|
113
|
-
|
|
114
|
-
This is where Counterfact becomes more than a mock.
|
|
115
|
-
|
|
116
|
-
The built-in REPL lets you inspect and control the system while it’s running.
|
|
117
|
-
|
|
118
|
-
Seed data:
|
|
119
|
-
|
|
120
|
-
```
|
|
121
|
-
⬣> context.add({ name: "Fluffy", status: "available", photoUrls: [] })
|
|
122
|
-
⬣> context.add({ name: "Rex", status: "pending", photoUrls: [] })
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
Make requests:
|
|
126
|
-
|
|
127
|
-
```
|
|
128
|
-
⬣> client.get("/pet/1")
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
Simulate failures instantly:
|
|
132
|
-
|
|
133
|
-
```
|
|
134
|
-
⬣> context.rateLimitExceeded = true
|
|
135
|
-
⬣> client.get("/pet/1")
|
|
136
|
-
{ status: 429, body: "Too Many Requests" }
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
No HTTP scripts. No restarts. Just direct control.
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
## Minute 5 — Proxy to the real backend
|
|
144
|
-
|
|
145
|
-
When parts of your backend are ready, forward them through.
|
|
146
|
-
|
|
147
|
-
Everything else stays simulated.
|
|
148
|
-
|
|
149
|
-
```sh
|
|
150
|
-
npx counterfact@latest openapi.yaml api --proxy-url https://api.example.com
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
Toggle paths live:
|
|
154
|
-
|
|
155
|
-
```
|
|
156
|
-
⬣> .proxy on /payments
|
|
157
|
-
⬣> .proxy on /auth
|
|
158
|
-
⬣> .proxy off
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
## What you just built
|
|
164
|
-
|
|
165
|
-
In five minutes, you turned a static spec into a working system:
|
|
166
|
-
|
|
167
|
-
- **Schema-valid responses** from the moment it starts
|
|
168
|
-
- **Type-safe handlers** generated from your spec
|
|
169
|
-
- **Shared state** across all routes
|
|
170
|
-
- **Hot reloading** without losing that state
|
|
171
|
-
- A **live control surface (REPL)** for runtime behavior
|
|
172
|
-
- **Selective proxying** to real services
|
|
173
|
-
|
|
174
|
-
|
|
19
|
+
> Requires Node ≥ 22.0.0
|
|
175
20
|
|
|
176
21
|
## Go deeper
|
|
177
22
|
|
|
@@ -189,4 +34,4 @@ In five minutes, you turned a static spec into a working system:
|
|
|
189
34
|
|
|
190
35
|
[Changelog](./CHANGELOG.md) · [Contributing](./CONTRIBUTING.md)
|
|
191
36
|
|
|
192
|
-
</div>
|
|
37
|
+
</div>
|
package/bin/README.md
CHANGED
|
@@ -6,7 +6,19 @@ This directory contains the executable script that is run when a developer invok
|
|
|
6
6
|
|
|
7
7
|
| File | Description |
|
|
8
8
|
|---|---|
|
|
9
|
-
| `counterfact.js` |
|
|
9
|
+
| `counterfact.js` | Thin bootstrap: enforces minimum Node version, probes for native TypeScript execution, then delegates to `src/cli/run.ts` (or `dist/cli/run.js`) |
|
|
10
|
+
| `taglines.txt` | One-per-line list of random taglines shown in the startup banner |
|
|
11
|
+
|
|
12
|
+
## Architecture
|
|
13
|
+
|
|
14
|
+
Most of the CLI logic lives in **`src/cli/`** as TypeScript:
|
|
15
|
+
|
|
16
|
+
| Module | Description |
|
|
17
|
+
|---|---|
|
|
18
|
+
| `src/cli/run.ts` | Commander program setup, `main()` action handler, and the `runCli()` entry point |
|
|
19
|
+
| `src/cli/banner.ts` | Startup banner utilities: `padTagLine`, `createWatchMessage`, `createIntroduction` |
|
|
20
|
+
| `src/cli/check-for-updates.ts` | npm update check: `isOutdated`, `checkForUpdates` |
|
|
21
|
+
| `src/cli/telemetry.ts` | PostHog telemetry: `isTelemetryEnabled`, `sendTelemetry` |
|
|
10
22
|
|
|
11
23
|
## How It Works
|
|
12
24
|
|
|
@@ -14,19 +26,32 @@ This directory contains the executable script that is run when a developer invok
|
|
|
14
26
|
npx counterfact@latest openapi.yaml ./api [options]
|
|
15
27
|
│
|
|
16
28
|
▼
|
|
17
|
-
|
|
18
|
-
│
|
|
19
|
-
│
|
|
20
|
-
│ 1.
|
|
21
|
-
│ 2.
|
|
22
|
-
│ 3.
|
|
23
|
-
│
|
|
24
|
-
│
|
|
25
|
-
|
|
26
|
-
│
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
┌────────────────────────────────────────────────┐
|
|
30
|
+
│ bin/counterfact.js (thin bootstrap) │
|
|
31
|
+
│ │
|
|
32
|
+
│ 1. Enforce minimum Node.js version │
|
|
33
|
+
│ 2. Probe native TypeScript execution │
|
|
34
|
+
│ 3. Import runCli() from src/cli/run.ts │
|
|
35
|
+
│ (or dist/cli/run.js when compiled) │
|
|
36
|
+
│ 4. Call runCli(process.argv) │
|
|
37
|
+
└────────────────────────────────────────────────┘
|
|
38
|
+
│
|
|
39
|
+
▼
|
|
40
|
+
┌────────────────────────────────────────────────┐
|
|
41
|
+
│ src/cli/run.ts (all CLI logic) │
|
|
42
|
+
│ │
|
|
43
|
+
│ 1. Read version from package.json │
|
|
44
|
+
│ 2. Read taglines from bin/taglines.txt │
|
|
45
|
+
│ 3. Fire telemetry (if enabled) │
|
|
46
|
+
│ 4. Parse args (Commander) │
|
|
47
|
+
│ 5. Load counterfact.yaml │
|
|
48
|
+
│ 6. Merge config + args │
|
|
49
|
+
│ 7. Resolve paths │
|
|
50
|
+
│ 8. Build Config object │
|
|
51
|
+
│ 9. Run migrations if old layout detected │
|
|
52
|
+
│ 10. Print startup banner │
|
|
53
|
+
│ 11. Call start(config) from src/app.ts │
|
|
54
|
+
└────────────────────────────────────────────────┘
|
|
30
55
|
```
|
|
31
56
|
|
|
32
57
|
### Key CLI Options
|