@crvouga/mockingbird-service-stripe 0.1.2 → 0.3.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/CHANGELOG.md +34 -0
- package/README.md +52 -14
- package/dist/chunk-DGGBNO2M.js +292 -0
- package/dist/chunk-DGGBNO2M.js.map +7 -0
- package/dist/chunk-QSKI7ZTR.js +5906 -0
- package/dist/chunk-QSKI7ZTR.js.map +7 -0
- package/dist/cli.js +19 -0
- package/dist/cli.js.map +7 -0
- package/dist/index.d.ts +250 -2
- package/dist/index.js +20 -5250
- package/dist/index.js.map +4 -4
- package/dist/server.d.ts +675 -0
- package/dist/server.js +12 -0
- package/dist/server.js.map +7 -0
- package/package.json +19 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Changelog — @crvouga/mockingbird-service-stripe
|
|
2
|
+
|
|
3
|
+
## 0.3.0 (2026-09-21)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- team identity, lab-account admin, sandbox limits, fixtures and request journal ([6cb1be3](https://github.com/crvouga/mockingbird/commit/6cb1be324a048ac9fe832061632c0ee9c9d01f8b))
|
|
8
|
+
|
|
9
|
+
## 0.2.0 (2026-09-20)
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
- serve command and the shared service contract ([44b100d](https://github.com/crvouga/mockingbird/commit/44b100daa132da262b0098bdfbaadb5d739de41a))
|
|
14
|
+
- one service contract — health, admin, namespaces, clock, faults, metrics ([fea7dd1](https://github.com/crvouga/mockingbird/commit/fea7dd169cc16d11baebba38dced7f630f725714))
|
|
15
|
+
|
|
16
|
+
### Fixes and improvements
|
|
17
|
+
|
|
18
|
+
- scope admin-injected faults to the calling namespace ([3c1d573](https://github.com/crvouga/mockingbird/commit/3c1d573ac0c404324bbd20855a5ac7a2cd50f738))
|
|
19
|
+
- take the admin namespace override only on admin routes ([37836a5](https://github.com/crvouga/mockingbird/commit/37836a5b0c51d17dd24e7b01c12dd6d8049646da))
|
|
20
|
+
- state what each mock does not model ([ee84a7d](https://github.com/crvouga/mockingbird/commit/ee84a7d7acc1944a3b3534d33288279ca990cbe3))
|
|
21
|
+
|
|
22
|
+
## 0.1.2 (2026-09-19)
|
|
23
|
+
|
|
24
|
+
### Fixes and improvements
|
|
25
|
+
|
|
26
|
+
- publish only mock services and bundle their private helpers ([f13120b](https://github.com/crvouga/mockingbird/commit/f13120b70596feb4341f1b5822060882a629952c))
|
|
27
|
+
|
|
28
|
+
## 0.1.1 (2026-09-19)
|
|
29
|
+
|
|
30
|
+
Dependency updates only.
|
|
31
|
+
|
|
32
|
+
## 0.1.0 (2026-09-19)
|
|
33
|
+
|
|
34
|
+
Initial release.
|
package/README.md
CHANGED
|
@@ -25,8 +25,8 @@ npm install -D @crvouga/mockingbird-service-stripe
|
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
ESM only. Requires Node >= 22 or Bun >= 1.2. No native dependencies: state lives in an in-memory
|
|
28
|
-
SQLite engine (pure TypeScript, bundled in). To serve it over HTTP
|
|
29
|
-
|
|
28
|
+
SQLite engine (pure TypeScript, bundled in). To serve it over HTTP run `npx mockingbird-stripe serve`, or
|
|
29
|
+
use `createServer` from `./server` (Node) or `createRuntime` with any Fetch server.
|
|
30
30
|
|
|
31
31
|
## Usage
|
|
32
32
|
|
|
@@ -44,6 +44,38 @@ Behaviour the examples rely on (all from the source):
|
|
|
44
44
|
- `Idempotency-Key` on POSTs is honoured: a replay returns the cached response, a replay with
|
|
45
45
|
different parameters returns 400.
|
|
46
46
|
|
|
47
|
+
### Serve it: `mockingbird-stripe serve` or `createServer`
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npx mockingbird-stripe serve # http://127.0.0.1:12111
|
|
51
|
+
npx mockingbird-stripe serve --port 0 --log json --admin-key local-admin
|
|
52
|
+
npx mockingbird-stripe serve --config mockingbird.json # every service in one config
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { createServer } from "@crvouga/mockingbird-service-stripe/server"
|
|
57
|
+
|
|
58
|
+
const server = await createServer() // any free port; server.url, server.port
|
|
59
|
+
const response = await fetch(`${server.url}/v1/products?limit=3`, { headers: { authorization: "Bearer sk_test_mockingbird" } })
|
|
60
|
+
console.log(response.status) // 200
|
|
61
|
+
await server.close()
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Served this way — or through `createRuntime()`, the same thing as one runtime-neutral `fetch` —
|
|
65
|
+
the mock also answers Mockingbird's service contract, outside Stripe's bearer-key check:
|
|
66
|
+
|
|
67
|
+
- `GET /health` — unauthenticated readiness probe.
|
|
68
|
+
- `/__admin/*` — reset (`POST /__admin/reset`), snapshots (`POST /__admin/snapshots`,
|
|
69
|
+
`POST /__admin/snapshots/{id}/restore`), clock (`POST /__admin/clock {"advance": "2h"}`), fault
|
|
70
|
+
injection (`POST /__admin/faults {"operationId": …, "status": 503, "count": 1}`), and metrics with
|
|
71
|
+
unmatched-route counts (`GET /__admin/metrics`). `GET /__admin` lists every route; `--admin-key`
|
|
72
|
+
locks them behind `x-mockingbird-admin-key`.
|
|
73
|
+
- `x-mockingbird-namespace: <name>` — isolates a request's data, so parallel workers share one
|
|
74
|
+
process without seeing each other.
|
|
75
|
+
|
|
76
|
+
The [Junction README](https://github.com/crvouga/mockingbird/tree/main/packages/service/junction#the-service-contract)
|
|
77
|
+
documents the contract in full.
|
|
78
|
+
|
|
47
79
|
### In-process (inject `fetch`)
|
|
48
80
|
|
|
49
81
|
```ts
|
|
@@ -93,17 +125,8 @@ console.log(response.status) // 200
|
|
|
93
125
|
server.stop()
|
|
94
126
|
```
|
|
95
127
|
|
|
96
|
-
On Node
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
```js
|
|
100
|
-
import { serve } from "@hono/node-server"
|
|
101
|
-
const server = serve(
|
|
102
|
-
{ fetch: (request) => stripe.fetch(request), port: 0, hostname: "127.0.0.1" },
|
|
103
|
-
(info) => console.log(`http://127.0.0.1:${info.port}`),
|
|
104
|
-
)
|
|
105
|
-
// ... later: server.close()
|
|
106
|
-
```
|
|
128
|
+
On Node, `createServer` (above) is the listener; any Fetch-style server also works with
|
|
129
|
+
`StripeAPI#fetch` or `createRuntime().fetch`.
|
|
107
130
|
|
|
108
131
|
### Pointing stripe-node at it
|
|
109
132
|
|
|
@@ -122,7 +145,8 @@ const client = new Stripe("sk_test_mockingbird", {
|
|
|
122
145
|
await client.customers.create({ email: "qa@example.com" })
|
|
123
146
|
```
|
|
124
147
|
|
|
125
|
-
|
|
148
|
+
With `mockingbird-stripe serve` on port 12111, host, port and protocol are the only wiring. Add a
|
|
149
|
+
base-URL override (e.g. `STRIPE_API_BASE_URL=http://127.0.0.1:12111`) at every place your app
|
|
126
150
|
constructs a Stripe client; a client built with `new Stripe(key)` and no options cannot be
|
|
127
151
|
redirected. Test payment methods and tokens such as `pm_card_visa`, `pm_card_authenticationRequired`
|
|
128
152
|
and `tok_chargeDeclinedInsufficientFunds` behave like their Stripe counterparts
|
|
@@ -182,6 +206,19 @@ test("starts empty", async () => {
|
|
|
182
206
|
})
|
|
183
207
|
```
|
|
184
208
|
|
|
209
|
+
## What is and is not modelled
|
|
210
|
+
|
|
211
|
+
- **Modelled**: the 88 operations in [SUPPORT.md](https://github.com/crvouga/mockingbird/blob/main/packages/service/stripe/SUPPORT.md),
|
|
212
|
+
whose behaviour is checked by live parity against Stripe test mode; state partitioned per API key;
|
|
213
|
+
the test payment methods and card tokens listed above.
|
|
214
|
+
- **Not modelled**: the 20 operations SUPPORT.md marks unsupported, each with its reason; Stripe.js
|
|
215
|
+
and hosted checkout (`js.stripe.com`, `checkout.stripe.com`); real rate-limit and 5xx bodies —
|
|
216
|
+
`POST /__admin/faults` injects Mockingbird's own, which are shape-plausible, not recorded;
|
|
217
|
+
anything outside the vendored spec, which 404s and is counted in `GET /__admin/metrics` under
|
|
218
|
+
`unmatched`.
|
|
219
|
+
- **Determinism**: with a fixed clock and `seed`, ids and timestamps replay exactly — two runtimes
|
|
220
|
+
given the same clock produce the same `cus_…` ids and `created` values.
|
|
221
|
+
|
|
185
222
|
## API
|
|
186
223
|
|
|
187
224
|
`StripeAPI` is the main export; the rest supports account scoping, contract introspection and the
|
|
@@ -189,6 +226,7 @@ QA corpus used by the parity suites.
|
|
|
189
226
|
|
|
190
227
|
| Export | Description |
|
|
191
228
|
| --- | --- |
|
|
229
|
+
| `createRuntime` | `(options?) => StripeRuntime` — the mock with the service contract (health, admin, namespaces, clock, faults, metrics) as one runtime-neutral `fetch`. Options: `sqlite`, `clock`, `seed`, `adminKey`, `onLog`, `onWebhook`. `./server` adds `createServer(options?)` (Node; `port`, `host`), `serveTarget` and `DEFAULT_PORT` (`12111`). |
|
|
192
230
|
| `StripeAPI` | Class. `new StripeAPI(options?)`; implements the Fetch contract `fetch(request: Request): Promise<Response>`. |
|
|
193
231
|
| `accountOfKey` | `(key: string) => string` — the opaque `acct_...` partition id for an API key (use it to filter `webhookEvents`). |
|
|
194
232
|
| `accountOf` | `(request: Request) => string` — the partition id for a request's bearer key. |
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createRuntime
|
|
3
|
+
} from "./chunk-QSKI7ZTR.js";
|
|
4
|
+
|
|
5
|
+
// ../../adapters/node/dist/cli.js
|
|
6
|
+
import { readFile } from "node:fs/promises";
|
|
7
|
+
import { parseArgs } from "node:util";
|
|
8
|
+
|
|
9
|
+
// ../../adapters/node/dist/serve.js
|
|
10
|
+
import { createServer } from "node:http";
|
|
11
|
+
var serve = async (api, options = {}) => {
|
|
12
|
+
const server = createServer(async (req, res) => {
|
|
13
|
+
const chunks = [];
|
|
14
|
+
for await (const chunk of req) {
|
|
15
|
+
chunks.push(Buffer.from(chunk));
|
|
16
|
+
}
|
|
17
|
+
const body = Buffer.concat(chunks);
|
|
18
|
+
const address = server.address();
|
|
19
|
+
const port = typeof address === "object" && address !== null ? address.port : void 0;
|
|
20
|
+
const base = `http://${req.headers.host ?? `localhost:${port ?? 80}`}`;
|
|
21
|
+
const raw = req.url ?? "/";
|
|
22
|
+
const url = new URL(raw.replace(/^\/+/, "/"), base);
|
|
23
|
+
const method = req.method ?? "GET";
|
|
24
|
+
const init = { method, headers: req.headers };
|
|
25
|
+
if (method !== "GET" && method !== "HEAD" && body.length > 0) {
|
|
26
|
+
init.body = body;
|
|
27
|
+
}
|
|
28
|
+
const request = new Request(url, init);
|
|
29
|
+
const response = await api.fetch(request);
|
|
30
|
+
const headers = Object.fromEntries(response.headers);
|
|
31
|
+
const cookies = response.headers.getSetCookie();
|
|
32
|
+
if (cookies.length > 0)
|
|
33
|
+
headers["set-cookie"] = cookies;
|
|
34
|
+
res.writeHead(response.status, headers);
|
|
35
|
+
res.end(Buffer.from(await response.arrayBuffer()));
|
|
36
|
+
});
|
|
37
|
+
await new Promise((resolve, reject) => {
|
|
38
|
+
server.once("error", reject);
|
|
39
|
+
server.listen(options.port ?? 0, options.host, resolve);
|
|
40
|
+
});
|
|
41
|
+
return server;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// ../../adapters/node/dist/listen.js
|
|
45
|
+
var listen = async (api, options = {}) => {
|
|
46
|
+
const host = options.host ?? "127.0.0.1";
|
|
47
|
+
const server = await serve(api, { port: options.port ?? 0, host });
|
|
48
|
+
const address = server.address();
|
|
49
|
+
const port = typeof address === "object" && address !== null ? address.port : options.port ?? 0;
|
|
50
|
+
const shown = host.includes(":") ? `[${host}]` : host;
|
|
51
|
+
return {
|
|
52
|
+
url: `http://${shown}:${port}`,
|
|
53
|
+
port,
|
|
54
|
+
host,
|
|
55
|
+
server,
|
|
56
|
+
close: () => new Promise((resolve, reject) => {
|
|
57
|
+
server.close((error) => {
|
|
58
|
+
if (error && error.code !== "ERR_SERVER_NOT_RUNNING")
|
|
59
|
+
reject(error);
|
|
60
|
+
else
|
|
61
|
+
resolve();
|
|
62
|
+
});
|
|
63
|
+
server.closeAllConnections?.();
|
|
64
|
+
})
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// ../../adapters/node/dist/cli.js
|
|
69
|
+
var optionHelp = (options) => Object.entries(options).map(([name, option]) => {
|
|
70
|
+
const flag = `--${name}${option.type === "string" ? ` ${option.value ?? "<value>"}` : ""}`;
|
|
71
|
+
const fallback = option.default !== void 0 ? ` (default: ${String(option.default)})` : "";
|
|
72
|
+
return ` ${flag.padEnd(30)} ${option.description}${fallback}`;
|
|
73
|
+
});
|
|
74
|
+
var help = (spec) => [
|
|
75
|
+
`${spec.bin} \u2014 ${spec.description}`,
|
|
76
|
+
"",
|
|
77
|
+
"Usage:",
|
|
78
|
+
` ${spec.bin} <command> [options]`,
|
|
79
|
+
"",
|
|
80
|
+
"Commands:",
|
|
81
|
+
...Object.entries(spec.commands).map(([name, c]) => ` ${name.padEnd(30)} ${c.summary}`),
|
|
82
|
+
"",
|
|
83
|
+
`Run \`${spec.bin} <command> --help\` for a command's options.`
|
|
84
|
+
].join("\n");
|
|
85
|
+
var commandHelp = (spec, name, command) => [
|
|
86
|
+
`${spec.bin} ${name} \u2014 ${command.summary}`,
|
|
87
|
+
"",
|
|
88
|
+
"Usage:",
|
|
89
|
+
` ${command.usage ?? `${spec.bin} ${name} [options]`}`,
|
|
90
|
+
...command.options ? ["", "Options:", ...optionHelp(command.options)] : []
|
|
91
|
+
].join("\n");
|
|
92
|
+
var runCli = async (spec, argv) => {
|
|
93
|
+
const pair = argv.length >= 2 ? `${argv[0]} ${argv[1]}` : void 0;
|
|
94
|
+
const words = pair !== void 0 && spec.commands[pair] ? 2 : 1;
|
|
95
|
+
const name = words === 2 ? pair : argv[0];
|
|
96
|
+
const rest = argv.slice(words);
|
|
97
|
+
if (name === void 0 || name === "--help" || name === "-h" || name === "help") {
|
|
98
|
+
console.log(help(spec));
|
|
99
|
+
return 0;
|
|
100
|
+
}
|
|
101
|
+
const command = spec.commands[name];
|
|
102
|
+
if (!command) {
|
|
103
|
+
console.error(`${spec.bin}: unknown command ${JSON.stringify(name)}
|
|
104
|
+
|
|
105
|
+
${help(spec)}`);
|
|
106
|
+
return 2;
|
|
107
|
+
}
|
|
108
|
+
if (rest.includes("--help") || rest.includes("-h")) {
|
|
109
|
+
console.log(commandHelp(spec, name, command));
|
|
110
|
+
return 0;
|
|
111
|
+
}
|
|
112
|
+
let parsed;
|
|
113
|
+
try {
|
|
114
|
+
parsed = parseArgs({
|
|
115
|
+
args: rest,
|
|
116
|
+
allowPositionals: true,
|
|
117
|
+
strict: true,
|
|
118
|
+
options: Object.fromEntries(Object.entries(command.options ?? {}).map(([key, option]) => [
|
|
119
|
+
key,
|
|
120
|
+
{
|
|
121
|
+
type: option.type,
|
|
122
|
+
...option.default !== void 0 ? { default: option.default } : {}
|
|
123
|
+
}
|
|
124
|
+
]))
|
|
125
|
+
});
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.error(`${spec.bin} ${name}: ${error instanceof Error ? error.message : String(error)}
|
|
128
|
+
|
|
129
|
+
${commandHelp(spec, name, command)}`);
|
|
130
|
+
return 2;
|
|
131
|
+
}
|
|
132
|
+
return command.run(parsed.values, parsed.positionals);
|
|
133
|
+
};
|
|
134
|
+
var COMMON_SERVE_OPTIONS = {
|
|
135
|
+
port: { type: "string", value: "<port>", description: "Port to listen on" },
|
|
136
|
+
host: { type: "string", value: "<host>", description: "Interface to bind", default: "127.0.0.1" },
|
|
137
|
+
"admin-key": {
|
|
138
|
+
type: "string",
|
|
139
|
+
value: "<key>",
|
|
140
|
+
description: "Require x-mockingbird-admin-key on /__admin/* (env MOCKINGBIRD_ADMIN_KEY)"
|
|
141
|
+
},
|
|
142
|
+
seed: { type: "string", value: "<seed>", description: "Seed for every random choice" },
|
|
143
|
+
log: {
|
|
144
|
+
type: "string",
|
|
145
|
+
value: "<pretty|json|off>",
|
|
146
|
+
description: "Request log format",
|
|
147
|
+
default: "pretty"
|
|
148
|
+
},
|
|
149
|
+
"log-requests": {
|
|
150
|
+
type: "boolean",
|
|
151
|
+
description: "One JSON line per request: namespace, operationId, status, ids touched (never bodies). Same as --log json"
|
|
152
|
+
},
|
|
153
|
+
config: {
|
|
154
|
+
type: "string",
|
|
155
|
+
value: "<file>",
|
|
156
|
+
description: "Serve every service in a mockingbird.json config instead"
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
var formatLog = (format) => {
|
|
160
|
+
if (format === "off")
|
|
161
|
+
return void 0;
|
|
162
|
+
if (format === "json")
|
|
163
|
+
return (entry) => console.log(JSON.stringify(entry));
|
|
164
|
+
return (entry) => {
|
|
165
|
+
const op = entry.operationId ?? (entry.unmatched ? "UNMATCHED" : "-");
|
|
166
|
+
const ns = entry.namespace === "default" ? "" : ` [${entry.namespace}]`;
|
|
167
|
+
const fault = entry.faultId ? ` fault=${entry.faultId}` : "";
|
|
168
|
+
const adopted = entry.adopted ? " adopted" : "";
|
|
169
|
+
console.log(`${entry.service} ${entry.method} ${entry.path} ${entry.status} ${op} ${entry.durationMs}ms${ns}${fault}${adopted}`);
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
var asString = (value) => typeof value === "string" ? value : void 0;
|
|
173
|
+
var loadTarget = async (name, own) => {
|
|
174
|
+
if (name === own.name)
|
|
175
|
+
return own;
|
|
176
|
+
const specifier = `@crvouga/mockingbird-service-${name}/server`;
|
|
177
|
+
try {
|
|
178
|
+
const mod = await import(specifier);
|
|
179
|
+
if (!mod.serveTarget)
|
|
180
|
+
throw new Error(`${specifier} exports no serveTarget`);
|
|
181
|
+
return mod.serveTarget;
|
|
182
|
+
} catch (error) {
|
|
183
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
184
|
+
throw new Error(`cannot load service "${name}": ${reason}. Install @crvouga/mockingbird-service-${name}.`);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
var start = async (target, values, config) => {
|
|
188
|
+
const runtime = await target.create(values, {
|
|
189
|
+
adminKey: config.adminKey,
|
|
190
|
+
seed: config.seed,
|
|
191
|
+
onLog: formatLog(config.log)
|
|
192
|
+
});
|
|
193
|
+
const listening = await listen(runtime, { port: config.port, host: config.host });
|
|
194
|
+
console.log(`${target.name} mock listening on ${listening.url}`);
|
|
195
|
+
console.log(`${target.name} health: GET ${listening.url}/health`);
|
|
196
|
+
console.log(`${target.name} admin: ${listening.url}/__admin (${config.adminKey ? "x-mockingbird-admin-key required" : "open \u2014 pass --admin-key to lock"})`);
|
|
197
|
+
for (const line of target.banner?.(runtime) ?? [])
|
|
198
|
+
console.log(`${target.name} ${line}`);
|
|
199
|
+
return listening;
|
|
200
|
+
};
|
|
201
|
+
var untilSignal = async (servers) => new Promise((resolve) => {
|
|
202
|
+
const stop = async () => {
|
|
203
|
+
await Promise.allSettled(servers.map((s) => s.close()));
|
|
204
|
+
resolve(0);
|
|
205
|
+
};
|
|
206
|
+
process.once("SIGINT", stop);
|
|
207
|
+
process.once("SIGTERM", stop);
|
|
208
|
+
});
|
|
209
|
+
var serveCommand = (target) => ({
|
|
210
|
+
summary: `Serve the ${target.name} mock over HTTP`,
|
|
211
|
+
options: { ...COMMON_SERVE_OPTIONS, ...target.options },
|
|
212
|
+
async run(values) {
|
|
213
|
+
const log = values["log-requests"] === true ? "json" : asString(values.log) ?? "pretty";
|
|
214
|
+
if (!["pretty", "json", "off"].includes(log)) {
|
|
215
|
+
console.error(`--log must be pretty, json or off (got ${log})`);
|
|
216
|
+
return 2;
|
|
217
|
+
}
|
|
218
|
+
const configPath = asString(values.config);
|
|
219
|
+
if (configPath !== void 0) {
|
|
220
|
+
const config = JSON.parse(await readFile(configPath, "utf8"));
|
|
221
|
+
const servers = [];
|
|
222
|
+
try {
|
|
223
|
+
for (const [name, entry] of Object.entries(config.services ?? {})) {
|
|
224
|
+
const each = await loadTarget(name, target);
|
|
225
|
+
servers.push(await start(each, entry.options ?? {}, {
|
|
226
|
+
port: entry.port ?? each.defaultPort,
|
|
227
|
+
host: entry.host ?? "127.0.0.1",
|
|
228
|
+
...entry.adminKey !== void 0 ? { adminKey: entry.adminKey } : {},
|
|
229
|
+
...entry.seed !== void 0 ? { seed: entry.seed } : {},
|
|
230
|
+
log: config.log ?? log
|
|
231
|
+
}));
|
|
232
|
+
}
|
|
233
|
+
} catch (error) {
|
|
234
|
+
await Promise.allSettled(servers.map((s) => s.close()));
|
|
235
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
236
|
+
return 1;
|
|
237
|
+
}
|
|
238
|
+
return untilSignal(servers);
|
|
239
|
+
}
|
|
240
|
+
const port = asString(values.port);
|
|
241
|
+
const adminKey = asString(values["admin-key"]) ?? process.env.MOCKINGBIRD_ADMIN_KEY;
|
|
242
|
+
const seed = asString(values.seed);
|
|
243
|
+
let listening;
|
|
244
|
+
try {
|
|
245
|
+
listening = await start(target, values, {
|
|
246
|
+
port: port === void 0 ? target.defaultPort : Number.parseInt(port, 10),
|
|
247
|
+
host: asString(values.host) ?? "127.0.0.1",
|
|
248
|
+
...adminKey !== void 0 ? { adminKey } : {},
|
|
249
|
+
...seed !== void 0 ? { seed } : {},
|
|
250
|
+
log
|
|
251
|
+
});
|
|
252
|
+
} catch (error) {
|
|
253
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
254
|
+
return 1;
|
|
255
|
+
}
|
|
256
|
+
return untilSignal([listening]);
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// src/server.ts
|
|
261
|
+
var DEFAULT_PORT = 12111;
|
|
262
|
+
var createServer2 = async (options = {}) => {
|
|
263
|
+
const { port, host, ...rest } = options;
|
|
264
|
+
const runtime = createRuntime(rest);
|
|
265
|
+
const listening = await listen(runtime, {
|
|
266
|
+
port: port ?? 0,
|
|
267
|
+
...host !== void 0 ? { host } : {}
|
|
268
|
+
});
|
|
269
|
+
return { ...listening, runtime };
|
|
270
|
+
};
|
|
271
|
+
var serveTarget = {
|
|
272
|
+
name: "stripe",
|
|
273
|
+
defaultPort: DEFAULT_PORT,
|
|
274
|
+
create: (_values, common) => createRuntime({
|
|
275
|
+
...common.adminKey !== void 0 ? { adminKey: common.adminKey } : {},
|
|
276
|
+
...common.seed !== void 0 ? { seed: common.seed } : {},
|
|
277
|
+
...common.onLog ? { onLog: common.onLog } : {}
|
|
278
|
+
}),
|
|
279
|
+
banner: () => [
|
|
280
|
+
"auth: Authorization: Bearer sk_test_<anything>; each key is its own account",
|
|
281
|
+
'stripe-node: new Stripe(key, { host: "127.0.0.1", port: <port>, protocol: "http" })'
|
|
282
|
+
]
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
export {
|
|
286
|
+
runCli,
|
|
287
|
+
serveCommand,
|
|
288
|
+
DEFAULT_PORT,
|
|
289
|
+
createServer2 as createServer,
|
|
290
|
+
serveTarget
|
|
291
|
+
};
|
|
292
|
+
//# sourceMappingURL=chunk-DGGBNO2M.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../adapters/node/src/cli.ts", "../../../adapters/node/src/serve.ts", "../../../adapters/node/src/listen.ts", "../src/server.ts"],
|
|
4
|
+
"sourcesContent": ["import { readFile } from \"node:fs/promises\"\nimport { type ParseArgsConfig, parseArgs } from \"node:util\"\nimport type { RequestLog, ServiceInstance, ServiceRuntime } from \"@crvouga/mockingbird-service\"\nimport { type Listening, listen } from \"./listen.js\"\n\nexport type CliOption = {\n type: \"string\" | \"boolean\"\n description: string\n /** Shown in help; the value placeholder, e.g. `<port>`. */\n value?: string\n default?: string | boolean\n}\n\nexport type CliValues = Record<string, string | boolean | undefined>\n\nexport type CliCommand = {\n summary: string\n usage?: string\n options?: Record<string, CliOption>\n /** Resolves to an exit code; a server command resolves only when it stops. */\n run(values: CliValues, positionals: string[]): Promise<number>\n}\n\nexport type CliSpec = {\n bin: string\n description: string\n commands: Record<string, CliCommand>\n}\n\nconst optionHelp = (options: Record<string, CliOption>): string[] =>\n Object.entries(options).map(([name, option]) => {\n const flag = `--${name}${option.type === \"string\" ? ` ${option.value ?? \"<value>\"}` : \"\"}`\n const fallback = option.default !== undefined ? ` (default: ${String(option.default)})` : \"\"\n return ` ${flag.padEnd(30)} ${option.description}${fallback}`\n })\n\nconst help = (spec: CliSpec): string =>\n [\n `${spec.bin} \u2014 ${spec.description}`,\n \"\",\n \"Usage:\",\n ` ${spec.bin} <command> [options]`,\n \"\",\n \"Commands:\",\n ...Object.entries(spec.commands).map(([name, c]) => ` ${name.padEnd(30)} ${c.summary}`),\n \"\",\n `Run \\`${spec.bin} <command> --help\\` for a command's options.`,\n ].join(\"\\n\")\n\nconst commandHelp = (spec: CliSpec, name: string, command: CliCommand): string =>\n [\n `${spec.bin} ${name} \u2014 ${command.summary}`,\n \"\",\n \"Usage:\",\n ` ${command.usage ?? `${spec.bin} ${name} [options]`}`,\n ...(command.options ? [\"\", \"Options:\", ...optionHelp(command.options)] : []),\n ].join(\"\\n\")\n\n/** Parse `argv` against `spec` and run the chosen command. Resolves to an exit code. */\nexport const runCli = async (spec: CliSpec, argv: string[]): Promise<number> => {\n // Two-word commands (`corpus pull`) win over one-word ones.\n const pair = argv.length >= 2 ? `${argv[0]} ${argv[1]}` : undefined\n const words = pair !== undefined && spec.commands[pair] ? 2 : 1\n const name = words === 2 ? pair : argv[0]\n const rest = argv.slice(words)\n if (name === undefined || name === \"--help\" || name === \"-h\" || name === \"help\") {\n console.log(help(spec))\n return 0\n }\n const command = spec.commands[name]\n if (!command) {\n console.error(`${spec.bin}: unknown command ${JSON.stringify(name)}\\n\\n${help(spec)}`)\n return 2\n }\n if (rest.includes(\"--help\") || rest.includes(\"-h\")) {\n console.log(commandHelp(spec, name, command))\n return 0\n }\n let parsed: { values: CliValues; positionals: string[] }\n try {\n parsed = parseArgs({\n args: rest,\n allowPositionals: true,\n strict: true,\n options: Object.fromEntries(\n Object.entries(command.options ?? {}).map(([key, option]) => [\n key,\n {\n type: option.type,\n ...(option.default !== undefined ? { default: option.default } : {}),\n },\n ]),\n ) as ParseArgsConfig[\"options\"],\n }) as { values: CliValues; positionals: string[] }\n } catch (error) {\n console.error(\n `${spec.bin} ${name}: ${error instanceof Error ? error.message : String(error)}\\n\\n${commandHelp(spec, name, command)}`,\n )\n return 2\n }\n return command.run(parsed.values, parsed.positionals)\n}\n\n// \u2500\u2500 serve \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type LogFormat = \"pretty\" | \"json\" | \"off\"\n\nexport type CommonServeOptions = {\n adminKey: string | undefined\n seed: string | undefined\n onLog: ((entry: RequestLog) => void) | undefined\n}\n\n/**\n * What a service contributes to `serve`: how to build its runtime from CLI flags,\n * and what to say at startup. Every service's `./server` entry exports one as\n * `serveTarget`, which is also how `serve --config` finds services by name.\n */\nexport type ServeTarget = {\n name: string\n defaultPort: number\n /** Serve flags beyond the common ones. */\n options?: Record<string, CliOption>\n create(\n values: CliValues,\n common: CommonServeOptions,\n ): Promise<ServiceRuntime<ServiceInstance>> | ServiceRuntime<ServiceInstance>\n /** Startup lines after the listen address, e.g. the loaded corpus version. */\n banner?(runtime: ServiceRuntime<ServiceInstance>): string[]\n}\n\nconst COMMON_SERVE_OPTIONS: Record<string, CliOption> = {\n port: { type: \"string\", value: \"<port>\", description: \"Port to listen on\" },\n host: { type: \"string\", value: \"<host>\", description: \"Interface to bind\", default: \"127.0.0.1\" },\n \"admin-key\": {\n type: \"string\",\n value: \"<key>\",\n description: \"Require x-mockingbird-admin-key on /__admin/* (env MOCKINGBIRD_ADMIN_KEY)\",\n },\n seed: { type: \"string\", value: \"<seed>\", description: \"Seed for every random choice\" },\n log: {\n type: \"string\",\n value: \"<pretty|json|off>\",\n description: \"Request log format\",\n default: \"pretty\",\n },\n \"log-requests\": {\n type: \"boolean\",\n description:\n \"One JSON line per request: namespace, operationId, status, ids touched (never bodies). Same as --log json\",\n },\n config: {\n type: \"string\",\n value: \"<file>\",\n description: \"Serve every service in a mockingbird.json config instead\",\n },\n}\n\nconst formatLog = (format: LogFormat) => {\n if (format === \"off\") return undefined\n if (format === \"json\") return (entry: RequestLog) => console.log(JSON.stringify(entry))\n return (entry: RequestLog) => {\n const op = entry.operationId ?? (entry.unmatched ? \"UNMATCHED\" : \"-\")\n const ns = entry.namespace === \"default\" ? \"\" : ` [${entry.namespace}]`\n const fault = entry.faultId ? ` fault=${entry.faultId}` : \"\"\n const adopted = entry.adopted ? \" adopted\" : \"\"\n console.log(\n `${entry.service} ${entry.method} ${entry.path} ${entry.status} ${op} ${entry.durationMs}ms${ns}${fault}${adopted}`,\n )\n }\n}\n\nconst asString = (value: string | boolean | undefined): string | undefined =>\n typeof value === \"string\" ? value : undefined\n\n/** A service entry in `mockingbird.json`. */\nexport type ConfigService = {\n port?: number\n host?: string\n adminKey?: string\n seed?: string\n /** Service-specific serve flags, by long name: `{ \"webhook-url\": \"\u2026\" }`. */\n options?: Record<string, string | boolean>\n}\n\nexport type MockingbirdConfig = {\n /** Keyed by service name: `junction` loads `@crvouga/mockingbird-service-junction`. */\n services: Record<string, ConfigService>\n log?: LogFormat\n}\n\nconst loadTarget = async (name: string, own: ServeTarget): Promise<ServeTarget> => {\n if (name === own.name) return own\n const specifier = `@crvouga/mockingbird-service-${name}/server`\n try {\n const mod = (await import(specifier)) as { serveTarget?: ServeTarget }\n if (!mod.serveTarget) throw new Error(`${specifier} exports no serveTarget`)\n return mod.serveTarget\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error)\n throw new Error(\n `cannot load service \"${name}\": ${reason}. Install @crvouga/mockingbird-service-${name}.`,\n )\n }\n}\n\nconst start = async (\n target: ServeTarget,\n values: CliValues,\n config: { port: number; host: string; adminKey?: string; seed?: string; log: LogFormat },\n): Promise<Listening> => {\n const runtime = await target.create(values, {\n adminKey: config.adminKey,\n seed: config.seed,\n onLog: formatLog(config.log),\n })\n const listening = await listen(runtime, { port: config.port, host: config.host })\n console.log(`${target.name} mock listening on ${listening.url}`)\n console.log(`${target.name} health: GET ${listening.url}/health`)\n console.log(\n `${target.name} admin: ${listening.url}/__admin (${config.adminKey ? \"x-mockingbird-admin-key required\" : \"open \u2014 pass --admin-key to lock\"})`,\n )\n for (const line of target.banner?.(runtime) ?? []) console.log(`${target.name} ${line}`)\n return listening\n}\n\nconst untilSignal = async (servers: Listening[]): Promise<number> =>\n new Promise((resolve) => {\n const stop = async () => {\n await Promise.allSettled(servers.map((s) => s.close()))\n resolve(0)\n }\n process.once(\"SIGINT\", stop)\n process.once(\"SIGTERM\", stop)\n })\n\n/** The standard `serve` command for a service, including multi-service `--config`. */\nexport const serveCommand = (target: ServeTarget): CliCommand => ({\n summary: `Serve the ${target.name} mock over HTTP`,\n options: { ...COMMON_SERVE_OPTIONS, ...target.options },\n async run(values) {\n const log = (\n values[\"log-requests\"] === true ? \"json\" : (asString(values.log) ?? \"pretty\")\n ) as LogFormat\n if (![\"pretty\", \"json\", \"off\"].includes(log)) {\n console.error(`--log must be pretty, json or off (got ${log})`)\n return 2\n }\n const configPath = asString(values.config)\n if (configPath !== undefined) {\n const config = JSON.parse(await readFile(configPath, \"utf8\")) as MockingbirdConfig\n const servers: Listening[] = []\n try {\n for (const [name, entry] of Object.entries(config.services ?? {})) {\n const each = await loadTarget(name, target)\n servers.push(\n await start(each, entry.options ?? {}, {\n port: entry.port ?? each.defaultPort,\n host: entry.host ?? \"127.0.0.1\",\n ...(entry.adminKey !== undefined ? { adminKey: entry.adminKey } : {}),\n ...(entry.seed !== undefined ? { seed: entry.seed } : {}),\n log: config.log ?? log,\n }),\n )\n }\n } catch (error) {\n await Promise.allSettled(servers.map((s) => s.close()))\n console.error(error instanceof Error ? error.message : String(error))\n return 1\n }\n return untilSignal(servers)\n }\n const port = asString(values.port)\n const adminKey = asString(values[\"admin-key\"]) ?? process.env.MOCKINGBIRD_ADMIN_KEY\n const seed = asString(values.seed)\n let listening: Listening\n try {\n listening = await start(target, values, {\n port: port === undefined ? target.defaultPort : Number.parseInt(port, 10),\n host: asString(values.host) ?? \"127.0.0.1\",\n ...(adminKey !== undefined ? { adminKey } : {}),\n ...(seed !== undefined ? { seed } : {}),\n log,\n })\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error))\n return 1\n }\n return untilSignal([listening])\n },\n})\n", "import { createServer } from \"node:http\"\nimport type { FetchAPI } from \"@crvouga/mockingbird-core\"\n\n/** Options for {@link serve}. */\nexport type NodeServeOptions = {\n port?: number\n host?: string\n}\n\n/**\n * Serve any Mockingbird {@link FetchAPI} over `node:http`.\n * Port defaults to `0`, so the OS assigns an ephemeral port (read from `server.address()`).\n */\nexport const serve = async (api: FetchAPI, options: NodeServeOptions = {}) => {\n const server = createServer(async (req, res) => {\n const chunks: Buffer[] = []\n for await (const chunk of req) {\n chunks.push(Buffer.from(chunk))\n }\n const body = Buffer.concat(chunks)\n const address = server.address()\n const port = typeof address === \"object\" && address !== null ? address.port : undefined\n const base = `http://${req.headers.host ?? `localhost:${port ?? 80}`}`\n const raw = req.url ?? \"/\"\n const url = new URL(raw.replace(/^\\/+/, \"/\"), base)\n const method = req.method ?? \"GET\"\n const init: RequestInit = { method, headers: req.headers as Record<string, string> }\n if (method !== \"GET\" && method !== \"HEAD\" && body.length > 0) {\n init.body = body\n }\n const request = new Request(url, init)\n const response = await api.fetch(request)\n // Headers#entries() joins repeated headers; Set-Cookie must stay one header per cookie.\n const headers: Record<string, string | string[]> = Object.fromEntries(response.headers)\n const cookies = response.headers.getSetCookie()\n if (cookies.length > 0) headers[\"set-cookie\"] = cookies\n res.writeHead(response.status, headers)\n res.end(Buffer.from(await response.arrayBuffer()))\n })\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject)\n server.listen(options.port ?? 0, options.host, resolve)\n })\n return server\n}\n", "import type { Server } from \"node:http\"\nimport type { FetchAPI } from \"@crvouga/mockingbird-core\"\nimport { serve } from \"./serve.js\"\n\nexport type ListenOptions = {\n /** Default `0`: the OS picks a free port. */\n port?: number\n /** Default `127.0.0.1`: a mock should not be reachable off the machine by accident. */\n host?: string\n}\n\n/** A running server, with the address it actually bound. */\nexport type Listening = {\n url: string\n port: number\n host: string\n server: Server\n close(): Promise<void>\n}\n\nexport const listen = async (api: FetchAPI, options: ListenOptions = {}): Promise<Listening> => {\n const host = options.host ?? \"127.0.0.1\"\n const server = await serve(api, { port: options.port ?? 0, host })\n const address = server.address()\n const port = typeof address === \"object\" && address !== null ? address.port : (options.port ?? 0)\n const shown = host.includes(\":\") ? `[${host}]` : host\n return {\n url: `http://${shown}:${port}`,\n port,\n host,\n server,\n close: () =>\n new Promise<void>((resolve, reject) => {\n // Stop accepting first, then drop keep-alive sockets so close() can finish.\n server.close((error) => {\n if (error && (error as { code?: string }).code !== \"ERR_SERVER_NOT_RUNNING\") reject(error)\n else resolve()\n })\n server.closeAllConnections?.()\n }),\n }\n}\n", "/// <reference types=\"node\" />\nimport { type Listening, listen, type ServeTarget } from \"@crvouga/mockingbird-adapter-node\"\nimport { createRuntime, type StripeRuntime, type StripeRuntimeOptions } from \"./runtime.js\"\n\n/** Port `mockingbird-stripe serve` listens on when none is given. */\nexport const DEFAULT_PORT = 12111\n\nexport type StripeServerOptions = StripeRuntimeOptions & {\n /** Default `0`: the OS picks a free port (read it from `url` / `port`). */\n port?: number\n /** Default `127.0.0.1`. */\n host?: string\n}\n\nexport type StripeServer = Listening & { runtime: StripeRuntime }\n\n/** Serve the Stripe mock over `node:http`. Resolves once it is listening. */\nexport const createServer = async (options: StripeServerOptions = {}): Promise<StripeServer> => {\n const { port, host, ...rest } = options\n const runtime = createRuntime(rest)\n const listening = await listen(runtime, {\n port: port ?? 0,\n ...(host !== undefined ? { host } : {}),\n })\n return { ...listening, runtime }\n}\n\n/** How `serve` (and `serve --config`) builds the Stripe mock from flags. */\nexport const serveTarget: ServeTarget = {\n name: \"stripe\",\n defaultPort: DEFAULT_PORT,\n create: (_values, common) =>\n createRuntime({\n ...(common.adminKey !== undefined ? { adminKey: common.adminKey } : {}),\n ...(common.seed !== undefined ? { seed: common.seed } : {}),\n ...(common.onLog ? { onLog: common.onLog } : {}),\n }),\n banner: () => [\n \"auth: Authorization: Bearer sk_test_<anything>; each key is its own account\",\n 'stripe-node: new Stripe(key, { host: \"127.0.0.1\", port: <port>, protocol: \"http\" })',\n ],\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["createServer"]
|
|
7
|
+
}
|