@crvouga/mockingbird-service-junction 1.9.0 → 2.0.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 +25 -1
- package/DISCOVERY.md +55 -0
- package/README.md +4 -4
- package/SUPPORT.md +50 -0
- package/dist/{chunk-S4CJ5QWE.js → chunk-7LPCTLIJ.js} +43 -23
- package/dist/chunk-7LPCTLIJ.js.map +7 -0
- package/dist/{chunk-WL4WPDHG.js → chunk-FZVFIPML.js} +623 -236
- package/dist/chunk-FZVFIPML.js.map +7 -0
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1 -1
- package/dist/server.d.ts +4 -1
- package/dist/server.js +2 -2
- package/openapi.yaml +3707 -0
- package/package.json +29 -4
- package/dist/chunk-S4CJ5QWE.js.map +0 -7
- package/dist/chunk-WL4WPDHG.js.map +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,30 @@
|
|
|
1
1
|
# Changelog — @crvouga/mockingbird-service-junction
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 2.0.0 (2026-10-04)
|
|
4
|
+
|
|
5
|
+
### ⚠️ Breaking changes
|
|
6
|
+
|
|
7
|
+
- isolate internal routes ([5e19b21](https://github.com/crvouga/mockingbird/commit/5e19b21d403acc74b04778a8b545e80bcbdf8d51))
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
- add route filtering ([4e59b1d](https://github.com/crvouga/mockingbird/commit/4e59b1d42a76550f844b744f8431a637433a0781))
|
|
12
|
+
- publish agent package indexes ([eca61d3](https://github.com/crvouga/mockingbird/commit/eca61d358b86982cf0b777ae8bd7feaa3663aaa6))
|
|
13
|
+
|
|
14
|
+
### Fixes and improvements
|
|
15
|
+
|
|
16
|
+
- clarify runtime prefix options ([f899a78](https://github.com/crvouga/mockingbird/commit/f899a7891f29413e4f08e9534d0c977f16acf7d7))
|
|
17
|
+
- honor configured prefixes ([4f569d7](https://github.com/crvouga/mockingbird/commit/4f569d74ca8089f2ed5e33a1abf32b90973f41dd))
|
|
18
|
+
- explain configurable internal paths ([21b47ae](https://github.com/crvouga/mockingbird/commit/21b47ae4d4a096cdf63189aaeaf721ccb369bcf3))
|
|
19
|
+
- parse ISO journal timestamps ([20b39a2](https://github.com/crvouga/mockingbird/commit/20b39a2c738e278533d610dfc91f1cb3ae9b3f1e))
|
|
20
|
+
- scope collector controls ([af9ee8f](https://github.com/crvouga/mockingbird/commit/af9ee8f4ccd98695831cd04eb0655ebd0280ecf6))
|
|
21
|
+
- harden shared controls ([7822614](https://github.com/crvouga/mockingbird/commit/7822614f6cba0387aeb60ba7320b0379aa1ef690))
|
|
22
|
+
|
|
23
|
+
### Dependencies
|
|
24
|
+
|
|
25
|
+
- `@crvouga/mockingbird-service-sqlite`
|
|
26
|
+
|
|
27
|
+
## 1.9.0 (2026-10-01)
|
|
4
28
|
|
|
5
29
|
### Features
|
|
6
30
|
|
package/DISCOVERY.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# @crvouga/mockingbird-service-junction discovery
|
|
2
|
+
|
|
3
|
+
This is the installed-package index for coding agents and tooling. All relative links resolve
|
|
4
|
+
inside `node_modules/@crvouga/mockingbird-service-junction/`; no repository checkout is needed to discover the mock's
|
|
5
|
+
supported surface or documented behavior.
|
|
6
|
+
|
|
7
|
+
## Capability and behavior sources
|
|
8
|
+
|
|
9
|
+
| Question | Authoritative file | What it contains |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| Behaviour and integration | [`README.md`](README.md) | Routes, state transitions, auth, webhooks, controls, presets and deliberate omissions. |
|
|
12
|
+
| Exact capabilities | [`SUPPORT.md`](SUPPORT.md) | Supported, unsupported and parity-covered operations or commands, including reasons for gaps. |
|
|
13
|
+
| Wire contract | [`openapi.yaml`](openapi.yaml) | Machine-readable paths, methods, schemas, responses and parity annotations. |
|
|
14
|
+
| Public API | [`dist/index.d.ts`](dist/index.d.ts) | The installed package's exact TypeScript exports and signatures. |
|
|
15
|
+
| Package metadata | [`package.json`](package.json) | Runtime/entry-point claims, vendor links, parity scope/tier and `mockingbird.discovery`. |
|
|
16
|
+
|
|
17
|
+
Read these together: the contract/capability matrix says *what* is available, while the README
|
|
18
|
+
defines stateful behavior, lifecycle rules, test controls, and intentional oracle differences.
|
|
19
|
+
If prose and an executable surface disagree, report a parity mismatch instead of adding a
|
|
20
|
+
consumer-side workaround.
|
|
21
|
+
|
|
22
|
+
## Parity and oracle
|
|
23
|
+
|
|
24
|
+
- Declared parity surface: **Users, orders, and lab results**.
|
|
25
|
+
- Parity tier: **cold** (the repository controls when live checks run).
|
|
26
|
+
- Oracle: **Live vendor API or sandbox**.
|
|
27
|
+
- Repository command: `bun run parity:service -- junction`.
|
|
28
|
+
- Evidence model: Run from a Mockingbird checkout; credentials come only from .env.local or GitHub Actions secrets. Missing credentials exit 2.
|
|
29
|
+
|
|
30
|
+
The npm package contains evidence summaries and the exact contract, not credentials or the
|
|
31
|
+
repository-only parity harness. Self-parity/property and acceptance tests run in the Mockingbird
|
|
32
|
+
repository; live parity is an additional oracle check, not a substitute for the packaged matrix.
|
|
33
|
+
|
|
34
|
+
## Runtime introspection
|
|
35
|
+
|
|
36
|
+
- `GET /__admin/health`
|
|
37
|
+
- `GET /__admin`
|
|
38
|
+
- `GET /__admin/state`
|
|
39
|
+
- `GET /__admin/requests`
|
|
40
|
+
- `GET /__admin/metrics`
|
|
41
|
+
- `GET /__admin/faults/presets`
|
|
42
|
+
- `GET /__admin/ui`
|
|
43
|
+
|
|
44
|
+
For HTTP services, use `x-mockingbird-namespace` (or the documented credential/path carrier) so
|
|
45
|
+
parallel tests do not share state. Admin state, journal, metrics and fault-preset endpoints are
|
|
46
|
+
designed for assertions and diagnosis by consuming test suites.
|
|
47
|
+
|
|
48
|
+
## Report a mismatch or missing capability
|
|
49
|
+
|
|
50
|
+
Follow the [agent reporting contract](https://github.com/crvouga/mockingbird/blob/main/docs/REPORTING_ISSUES.md). Include package version,
|
|
51
|
+
operation/command, a minimal redacted request, actual mock result, expected oracle result or vendor
|
|
52
|
+
documentation, and whether the mismatch appears in the matrix. Never include keys, tokens,
|
|
53
|
+
customer data, prompts, PHI, card data, or unredacted recordings.
|
|
54
|
+
|
|
55
|
+
Service key: `junction`.
|
package/README.md
CHANGED
|
@@ -111,7 +111,7 @@ npx mockingbird-junction serve --config mockingbird.json
|
|
|
111
111
|
import { createServer } from "@crvouga/mockingbird-service-junction/server"
|
|
112
112
|
|
|
113
113
|
const server = await createServer() // shipped corpus, any free port
|
|
114
|
-
const health = await fetch(`${server.url}/health`)
|
|
114
|
+
const health = await fetch(`${server.url}/__admin/health`)
|
|
115
115
|
console.log(health.status) // 200
|
|
116
116
|
|
|
117
117
|
// Point the Vital SDK (or your backend's Junction base URL) at server.url, then:
|
|
@@ -226,7 +226,7 @@ while keeping the production and sandbox guards intact.
|
|
|
226
226
|
|
|
227
227
|
Every Mockingbird service answers the same control surface, outside the vendor's auth gate:
|
|
228
228
|
|
|
229
|
-
- `GET /health` — unauthenticated readiness probe:
|
|
229
|
+
- `GET /__admin/health` — unauthenticated readiness probe:
|
|
230
230
|
`{ "status": "ok", "service": "junction", "corpus": "<label>", "geo": "corpus", … }`.
|
|
231
231
|
- `/__admin/*` — the control plane. Open by default; with `--admin-key` / `adminKey` it requires
|
|
232
232
|
`x-mockingbird-admin-key`, which is separate from any vendor key. Admin errors have one shape,
|
|
@@ -696,7 +696,7 @@ With a fixed clock (`clock` / `POST /__admin/clock {"set": …, "freeze": true}`
|
|
|
696
696
|
replays exactly. Stable across runs: user ids, order ids, event ids, sample ids, booking keys and
|
|
697
697
|
webhook message ids (derived from sequence numbers), timestamps (from the clock), generated
|
|
698
698
|
availability, and which requests a partial-`rate` fault hits. Wall-clock by design: webhook
|
|
699
|
-
`svix-timestamp`, `/health` uptime, and request log durations.
|
|
699
|
+
`svix-timestamp`, `/__admin/health` uptime, and request log durations.
|
|
700
700
|
|
|
701
701
|
## What is and is not modelled
|
|
702
702
|
|
|
@@ -739,7 +739,7 @@ Main entry (`@crvouga/mockingbird-service-junction`, runtime-neutral):
|
|
|
739
739
|
| `pullCorpus` | `(options: PullCorpusOptions) => Promise<SealedCorpus>` — record a corpus from a real team (GETs only). |
|
|
740
740
|
| `diffCorpus` | `(before, after) => CorpusDiff` — ZIPs, lab tests, lab accounts and observations added / removed / changed. |
|
|
741
741
|
| `fingerprintCorpus` | `(corpus) => Promise<string>` — SHA-256 of a corpus's content. |
|
|
742
|
-
| `corpusLabel` | `(corpus) => string` — the short label `/health` and logs show, e.g. `v1-2026-09-18-HqFDuEAuhkwD`. |
|
|
742
|
+
| `corpusLabel` | `(corpus) => string` — the short label `/__admin/health` and logs show, e.g. `v1-2026-09-18-HqFDuEAuhkwD`. |
|
|
743
743
|
| `parseSealedCorpus` | `(value: unknown) => SealedCorpus`; throws on a non-object or unsupported `version`. |
|
|
744
744
|
| `SEALED_CORPUS_VERSION` | Current corpus format version (`2`: adds `teamId`). |
|
|
745
745
|
| `SUPPORTED_SEALED_CORPUS_VERSIONS` | Versions `parseSealedCorpus` loads (`[1, 2]`). |
|
package/SUPPORT.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Junction API (Mockingbird subset) — operation support
|
|
2
|
+
|
|
3
|
+
Generated from `openapi.yaml`; do not edit by hand.
|
|
4
|
+
|
|
5
|
+
- operations in spec: **40**
|
|
6
|
+
- supported by the mock: **40**
|
|
7
|
+
- parity enabled: **22**
|
|
8
|
+
|
|
9
|
+
| operationId | route | mock | parity | notes |
|
|
10
|
+
| --- | --- | --- | --- | --- |
|
|
11
|
+
| `get_teams_users_v2_user_get` | `GET /v2/user` | ✅ supported | ✅ | |
|
|
12
|
+
| `create_user_v2_user_post` | `POST /v2/user` | ✅ supported | ✅ | |
|
|
13
|
+
| `get_user_v2_user__user_id__get` | `GET /v2/user/{user_id}` | ✅ supported | ✅ | |
|
|
14
|
+
| `delete_user_v2_user__user_id__delete` | `DELETE /v2/user/{user_id}` | ✅ supported | ✅ | |
|
|
15
|
+
| `patch_user_v2_user__user_id__patch` | `PATCH /v2/user/{user_id}` | ✅ supported | ✅ | |
|
|
16
|
+
| `get_user_by_client_user_id_v2_user_resolve__client_user_id__get` | `GET /v2/user/resolve/{client_user_id}` | ✅ supported | ✅ | |
|
|
17
|
+
| `patch_user_info_v2_user__user_id__info_patch` | `PATCH /v2/user/{user_id}/info` | ✅ supported | ✅ | |
|
|
18
|
+
| `get_latest_user_info_user_v2_user__user_id__info_latest_get` | `GET /v2/user/{user_id}/info/latest` | ✅ supported | ✅ | |
|
|
19
|
+
| `get_paginated_lab_tests_for_team_v3_lab_test_get` | `GET /v3/lab_test` | ✅ supported | ✅ | |
|
|
20
|
+
| `get_team_lab_accounts_v3_lab_test_lab_account_get` | `GET /v3/lab_test/lab_account` | ✅ supported | ❌ disabled | lab-account inventory is fixture-owned; the mock models the documented shape, filters and routing rules, not a live account inventory |
|
|
21
|
+
| `get_lab_tests_for_team_v3_lab_tests_get` | `GET /v3/lab_tests` | ✅ supported | ✅ | |
|
|
22
|
+
| `get_lab_test_for_team_v3_lab_tests__lab_test_id__get` | `GET /v3/lab_tests/{lab_test_id}` | ✅ supported | ✅ | |
|
|
23
|
+
| `get_labs_v3_lab_tests_labs_get` | `GET /v3/lab_tests/labs` | ✅ supported | ✅ | |
|
|
24
|
+
| `get_markers_for_lab_test_v3_lab_tests__lab_test_id__markers_get` | `GET /v3/lab_tests/{lab_test_id}/markers` | ✅ supported | ✅ | |
|
|
25
|
+
| `list_order_set_markers_v3_lab_tests_list_order_set_markers_post` | `POST /v3/lab_tests/list_order_set_markers` | ✅ supported | ✅ | |
|
|
26
|
+
| `create_order_v3_order_post` | `POST /v3/order` | ✅ supported | ✅ | |
|
|
27
|
+
| `get_area_info_v3_order_area_info_get` | `GET /v3/order/area/info` | ✅ supported | ❌ disabled | central_labs presence, within_radius counts and getlabs market coverage are provider-owned geo data that a mock cannot replicate per-zip; covered by the client-parity scenario shape checks instead |
|
|
28
|
+
| `get_psc_info_v3_order_psc_info_get` | `GET /v3/order/psc/info` | ✅ supported | ❌ disabled | patient_service_centers are real site inventories per zip (thousands of sites, result-capped at 30) that a fixture mock cannot replicate per-zip; covered by the client-parity scenario shape checks instead |
|
|
29
|
+
| `get_phlebotomy_appointment_availability_v3_order_phlebotomy_appointment_availability_post` | `POST /v3/order/phlebotomy/appointment/availability` | ✅ supported | ❌ disabled | availability slots are provider-side data whose values shift between sandbox calls; covered by the mock-internal scheduling property suite instead |
|
|
30
|
+
| `get_phlebotomy_appointment_cancellation_reason_v3_order_phlebotomy_appointment_cancellation_reasons_get` | `GET /v3/order/phlebotomy/appointment/cancellation-reasons` | ✅ supported | ✅ | |
|
|
31
|
+
| `get_psc_appointment_availability_v3_order_psc_appointment_availability_post` | `POST /v3/order/psc/appointment/availability` | ✅ supported | ❌ disabled | availability slots are provider-side data whose values shift between sandbox calls; covered by the mock-internal scheduling property suite instead |
|
|
32
|
+
| `get_psc_appointment_cancellation_reason_v3_order_psc_appointment_cancellation_reasons_get` | `GET /v3/order/psc/appointment/cancellation-reasons` | ✅ supported | ✅ | |
|
|
33
|
+
| `get_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_get` | `GET /v3/order/{order_id}/phlebotomy/appointment` | ✅ supported | ❌ disabled | appointment payloads embed provider-side slot data; covered by the mock-internal scheduling property suite instead |
|
|
34
|
+
| `book_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_book_post` | `POST /v3/order/{order_id}/phlebotomy/appointment/book` | ✅ supported | ❌ disabled | booking depends on live provider slot state; covered by the mock-internal scheduling property suite instead |
|
|
35
|
+
| `reschedule_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_reschedule_patch` | `PATCH /v3/order/{order_id}/phlebotomy/appointment/reschedule` | ✅ supported | ❌ disabled | rescheduling depends on live provider slot state; covered by the mock-internal scheduling property suite instead |
|
|
36
|
+
| `cancel_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_cancel_patch` | `PATCH /v3/order/{order_id}/phlebotomy/appointment/cancel` | ✅ supported | ❌ disabled | cancellation depends on live provider appointment state; covered by the mock-internal scheduling property suite instead |
|
|
37
|
+
| `get_psc_appointment_v3_order__order_id__psc_appointment_get` | `GET /v3/order/{order_id}/psc/appointment` | ✅ supported | ❌ disabled | appointment payloads embed provider-side slot data; covered by the mock-internal scheduling property suite instead |
|
|
38
|
+
| `book_psc_appointment_v3_order__order_id__psc_appointment_book_post` | `POST /v3/order/{order_id}/psc/appointment/book` | ✅ supported | ❌ disabled | booking depends on live provider slot state; covered by the mock-internal scheduling property suite instead |
|
|
39
|
+
| `reschedule_psc_appointment_v3_order__order_id__psc_appointment_reschedule_patch` | `PATCH /v3/order/{order_id}/psc/appointment/reschedule` | ✅ supported | ❌ disabled | rescheduling depends on live provider slot state; covered by the mock-internal scheduling property suite instead |
|
|
40
|
+
| `cancel_psc_appointment_v3_order__order_id__psc_appointment_cancel_patch` | `PATCH /v3/order/{order_id}/psc/appointment/cancel` | ✅ supported | ❌ disabled | cancellation depends on live provider appointment state; covered by the mock-internal scheduling property suite instead |
|
|
41
|
+
| `get_order_v3_order__order_id__get` | `GET /v3/order/{order_id}` | ✅ supported | ✅ | |
|
|
42
|
+
| `cancel_order_v3_order__order_id__cancel_post` | `POST /v3/order/{order_id}/cancel` | ✅ supported | ✅ | |
|
|
43
|
+
| `simulate_order_v3_order__order_id__test_post` | `POST /v3/order/{order_id}/test` | ✅ supported | ✅ | |
|
|
44
|
+
| `get_result_raw_v3_order__order_id__result_get` | `GET /v3/order/{order_id}/result` | ✅ supported | ❌ disabled | results carry provider-side specimen data; covered by the mock-internal results property suite instead |
|
|
45
|
+
| `get_result_metadata_v3_order__order_id__result_metadata_get` | `GET /v3/order/{order_id}/result/metadata` | ✅ supported | ✅ | |
|
|
46
|
+
| `get_result_pdf_v3_order__order_id__result_pdf_get` | `GET /v3/order/{order_id}/result/pdf` | ✅ supported | ❌ disabled | PDF bytes are provider-rendered; compared by shape (byteLength) only in the scenario script |
|
|
47
|
+
| `get_order_requisition_pdf_v3_order__order_id__requisition_pdf_get` | `GET /v3/order/{order_id}/requisition/pdf` | ✅ supported | ❌ disabled | PDF bytes are provider-rendered; compared by shape (byteLength) only in the scenario script |
|
|
48
|
+
| `get_orders_v3_orders_get` | `GET /v3/orders` | ✅ supported | ✅ | |
|
|
49
|
+
| `get_order_transaction_v3_order_transaction__transaction_id__get` | `GET /v3/order_transaction/{transaction_id}` | ✅ supported | ❌ disabled | order transactions are not available to the sandbox team (feature not available) |
|
|
50
|
+
| `get_order_transaction_result_v3_order_transaction__transaction_id__result_get` | `GET /v3/order_transaction/{transaction_id}/result` | ✅ supported | ❌ disabled | lab results are not available to the sandbox team (feature not available) |
|
|
@@ -4,8 +4,9 @@ import {
|
|
|
4
4
|
createRuntime,
|
|
5
5
|
defaultBillingTypesFrom,
|
|
6
6
|
parseDuration,
|
|
7
|
-
pullCorpus
|
|
8
|
-
|
|
7
|
+
pullCorpus,
|
|
8
|
+
resolveAdminPrefix
|
|
9
|
+
} from "./chunk-FZVFIPML.js";
|
|
9
10
|
import {
|
|
10
11
|
defaultCorpus
|
|
11
12
|
} from "./chunk-C2UGIPPM.js";
|
|
@@ -171,10 +172,12 @@ var removeOwned = async (path, id) => {
|
|
|
171
172
|
};
|
|
172
173
|
var httpChild = async (target, entry, options) => {
|
|
173
174
|
const runtime = await target.create(entry.options ?? {}, {
|
|
175
|
+
adminPrefix: resolveAdminPrefix(entry.adminPrefix),
|
|
174
176
|
adminKey: entry.adminKey,
|
|
175
177
|
seed: entry.seed,
|
|
176
178
|
onLog: options.onLog
|
|
177
179
|
});
|
|
180
|
+
const adminPrefix = resolveAdminPrefix(entry.adminPrefix);
|
|
178
181
|
runtime.isolateNamespaces();
|
|
179
182
|
const locked = /* @__PURE__ */ new Set();
|
|
180
183
|
const active = /* @__PURE__ */ new Map();
|
|
@@ -208,12 +211,12 @@ var httpChild = async (target, entry, options) => {
|
|
|
208
211
|
return {
|
|
209
212
|
protocol: "http",
|
|
210
213
|
url: server.url,
|
|
211
|
-
healthUrl: `${server.url}/health`,
|
|
212
|
-
adminUrl: `${server.url}
|
|
213
|
-
namespaces: { header: "x-mockingbird-namespace", path:
|
|
214
|
+
healthUrl: `${server.url}${adminPrefix}/health`,
|
|
215
|
+
adminUrl: `${server.url}${adminPrefix}`,
|
|
216
|
+
namespaces: { header: "x-mockingbird-namespace", path: `${adminPrefix}/ns/{name}` },
|
|
214
217
|
ready: async () => {
|
|
215
218
|
try {
|
|
216
|
-
return (await fetch(`${server.url}/health`, { signal: AbortSignal.timeout(2e3) })).ok;
|
|
219
|
+
return (await fetch(`${server.url}${adminPrefix}/health`, { signal: AbortSignal.timeout(2e3) })).ok;
|
|
217
220
|
} catch {
|
|
218
221
|
return false;
|
|
219
222
|
}
|
|
@@ -352,7 +355,9 @@ async function startFleet(config, options) {
|
|
|
352
355
|
const api = {
|
|
353
356
|
async fetch(request) {
|
|
354
357
|
const url = new URL(request.url);
|
|
355
|
-
|
|
358
|
+
const adminPrefix = resolveAdminPrefix(config.adminPrefix);
|
|
359
|
+
const path = url.pathname.startsWith(`${adminPrefix}/`) ? url.pathname.slice(adminPrefix.length) : "";
|
|
360
|
+
if (path === "/health" && request.method === "GET") {
|
|
356
361
|
const states = await Promise.all([...children].map(async ([name, child]) => {
|
|
357
362
|
let protocolReady = false;
|
|
358
363
|
try {
|
|
@@ -376,18 +381,18 @@ async function startFleet(config, options) {
|
|
|
376
381
|
services: Object.fromEntries(states)
|
|
377
382
|
});
|
|
378
383
|
}
|
|
379
|
-
if (!
|
|
384
|
+
if (!path.startsWith("/fleet/"))
|
|
380
385
|
return json(404, { error: "not found" });
|
|
381
386
|
const adminKey = config.adminKey ?? process.env.MOCKINGBIRD_ADMIN_KEY;
|
|
382
387
|
if (adminKey !== void 0 && request.headers.get("x-mockingbird-admin-key") !== adminKey)
|
|
383
388
|
return json(401, { error: "admin key required" });
|
|
384
|
-
const route = /^\/
|
|
389
|
+
const route = /^\/fleet\/namespaces\/([^/]+)\/(reset|snapshots)(?:\/([^/]+)\/restore)?$/.exec(path);
|
|
385
390
|
const namespace = route ? decodeURIComponent(route[1]) : url.searchParams.get("namespace") ?? request.headers.get("x-mockingbird-namespace") ?? config.namespace ?? "default";
|
|
386
391
|
if (!NS.test(namespace))
|
|
387
392
|
return json(400, { error: "invalid namespace" });
|
|
388
|
-
if (request.method === "GET" &&
|
|
393
|
+
if (request.method === "GET" && path === "/fleet/metrics")
|
|
389
394
|
return json(200, { namespace, services: diagnostics(namespace) });
|
|
390
|
-
if (request.method === "GET" &&
|
|
395
|
+
if (request.method === "GET" && path === "/fleet/clock")
|
|
391
396
|
return json(200, {
|
|
392
397
|
namespace,
|
|
393
398
|
...clock(namespace).state(),
|
|
@@ -411,12 +416,12 @@ async function startFleet(config, options) {
|
|
|
411
416
|
} catch (error) {
|
|
412
417
|
return json(400, { error: error instanceof Error ? error.message : "bad selection" });
|
|
413
418
|
}
|
|
414
|
-
if (
|
|
419
|
+
if (path === "/fleet/wait-until-idle") {
|
|
415
420
|
const services = diagnostics(namespace);
|
|
416
421
|
const idle = Object.values(services).every((d) => pending(d) === 0);
|
|
417
422
|
return json(idle ? 200 : 409, { status: idle ? "idle" : "busy", namespace, services });
|
|
418
423
|
}
|
|
419
|
-
if (
|
|
424
|
+
if (path === "/fleet/clock") {
|
|
420
425
|
const current = clock(namespace);
|
|
421
426
|
let target = current.now();
|
|
422
427
|
if (body.set !== void 0) {
|
|
@@ -492,6 +497,7 @@ async function startFleet(config, options) {
|
|
|
492
497
|
}
|
|
493
498
|
};
|
|
494
499
|
try {
|
|
500
|
+
const adminPrefix = resolveAdminPrefix(config.adminPrefix);
|
|
495
501
|
if (!isObject(config.services) || Object.keys(config.services).length === 0)
|
|
496
502
|
throw new Error("config must contain at least one service");
|
|
497
503
|
for (const [name, entry] of Object.entries(config.services)) {
|
|
@@ -502,7 +508,11 @@ async function startFleet(config, options) {
|
|
|
502
508
|
if (entry.protocol && entry.protocol !== ("protocol" in target ? target.protocol : "http"))
|
|
503
509
|
throw new Error("configured protocol does not match target");
|
|
504
510
|
const adminKey = entry.adminKey ?? config.adminKey ?? process.env.MOCKINGBIRD_ADMIN_KEY;
|
|
505
|
-
const child = "start" in target ? await target.start(entry) : await httpChild(target, {
|
|
511
|
+
const child = "start" in target ? await target.start(entry) : await httpChild(target, {
|
|
512
|
+
...entry,
|
|
513
|
+
adminPrefix: resolveAdminPrefix(entry.adminPrefix ?? adminPrefix),
|
|
514
|
+
...adminKey !== void 0 ? { adminKey } : {}
|
|
515
|
+
}, options);
|
|
506
516
|
children.set(name, child);
|
|
507
517
|
if (!await child.ready())
|
|
508
518
|
throw new Error("protocol readiness failed");
|
|
@@ -520,15 +530,15 @@ async function startFleet(config, options) {
|
|
|
520
530
|
pid: process.pid,
|
|
521
531
|
id,
|
|
522
532
|
startedAt,
|
|
523
|
-
adminBase: `${supervisor.url}/
|
|
524
|
-
healthUrl: `${supervisor.url}/health`,
|
|
533
|
+
adminBase: `${supervisor.url}${adminPrefix}/fleet`,
|
|
534
|
+
healthUrl: `${supervisor.url}${adminPrefix}/health`,
|
|
525
535
|
services: Object.fromEntries([...children].map(([name, child]) => [
|
|
526
536
|
name,
|
|
527
537
|
{
|
|
528
538
|
protocol: child.protocol,
|
|
529
539
|
url: publicUrl(child.url),
|
|
530
|
-
healthUrl: child.healthUrl ?? `${supervisor?.url}/health`,
|
|
531
|
-
adminUrl: child.adminUrl ?? `${supervisor?.url}/
|
|
540
|
+
healthUrl: child.healthUrl ?? `${supervisor?.url}${adminPrefix}/health`,
|
|
541
|
+
adminUrl: child.adminUrl ?? `${supervisor?.url}${adminPrefix}/fleet`,
|
|
532
542
|
namespaces: child.namespaces,
|
|
533
543
|
processReady: true,
|
|
534
544
|
protocolReady: true
|
|
@@ -624,6 +634,11 @@ ${commandHelp(spec, name, command)}`);
|
|
|
624
634
|
var COMMON_SERVE_OPTIONS = {
|
|
625
635
|
port: { type: "string", value: "<port>", description: "Port to listen on" },
|
|
626
636
|
host: { type: "string", value: "<host>", description: "Interface to bind", default: "127.0.0.1" },
|
|
637
|
+
"admin-prefix": {
|
|
638
|
+
type: "string",
|
|
639
|
+
value: "<path>",
|
|
640
|
+
description: "Internal API prefix (default /__admin; env MOCKINGBIRD_ADMIN_PREFIX)"
|
|
641
|
+
},
|
|
627
642
|
"admin-key": {
|
|
628
643
|
type: "string",
|
|
629
644
|
value: "<key>",
|
|
@@ -697,7 +712,9 @@ var loadTarget = async (name, own) => {
|
|
|
697
712
|
}
|
|
698
713
|
};
|
|
699
714
|
var start = async (target, values, config) => {
|
|
715
|
+
const adminPrefix = resolveAdminPrefix(config.adminPrefix);
|
|
700
716
|
const runtime = await target.create(values, {
|
|
717
|
+
adminPrefix,
|
|
701
718
|
adminKey: config.adminKey,
|
|
702
719
|
seed: config.seed,
|
|
703
720
|
onLog: formatLog(config.log)
|
|
@@ -705,11 +722,11 @@ var start = async (target, values, config) => {
|
|
|
705
722
|
const listening = await listen(runtime, { port: config.port, host: config.host });
|
|
706
723
|
target.listening?.(listening);
|
|
707
724
|
console.log(`${target.name} mock listening on ${listening.url}`);
|
|
708
|
-
console.log(`${target.name} health: GET ${listening.url}/health`);
|
|
709
|
-
console.log(`${target.name} admin: ${listening.url}
|
|
710
|
-
console.log(`${target.name} admin ui: ${listening.url}/
|
|
725
|
+
console.log(`${target.name} health: GET ${listening.url}${adminPrefix}/health`);
|
|
726
|
+
console.log(`${target.name} admin: ${listening.url}${adminPrefix} (${config.adminKey ? "x-mockingbird-admin-key required" : "open \u2014 pass --admin-key to lock"})`);
|
|
727
|
+
console.log(`${target.name} admin ui: ${listening.url}${adminPrefix}/ui`);
|
|
711
728
|
for (const line of target.banner?.(runtime) ?? [])
|
|
712
|
-
console.log(`${target.name} ${line}`);
|
|
729
|
+
console.log(`${target.name} ${line.replaceAll("/__admin", adminPrefix)}`);
|
|
713
730
|
return listening;
|
|
714
731
|
};
|
|
715
732
|
var untilSignal = async (servers) => new Promise((resolve2) => {
|
|
@@ -736,6 +753,7 @@ var serveCommand = (target) => ({
|
|
|
736
753
|
if (configPath !== void 0) {
|
|
737
754
|
try {
|
|
738
755
|
const config = JSON.parse(await readFile2(configPath, "utf8"));
|
|
756
|
+
config.adminPrefix = resolveAdminPrefix(config.adminPrefix ?? asString(values["admin-prefix"]) ?? process.env.MOCKINGBIRD_ADMIN_PREFIX);
|
|
739
757
|
const adminKey2 = config.adminKey ?? asString(values["admin-key"]) ?? process.env.MOCKINGBIRD_ADMIN_KEY;
|
|
740
758
|
if (adminKey2 !== void 0)
|
|
741
759
|
config.adminKey = adminKey2;
|
|
@@ -768,6 +786,7 @@ var serveCommand = (target) => ({
|
|
|
768
786
|
let listening;
|
|
769
787
|
try {
|
|
770
788
|
listening = await start(target, values, {
|
|
789
|
+
adminPrefix: resolveAdminPrefix(asString(values["admin-prefix"]) ?? process.env.MOCKINGBIRD_ADMIN_PREFIX),
|
|
771
790
|
port: port === void 0 ? target.defaultPort : Number.parseInt(port, 10),
|
|
772
791
|
host: asString(values.host) ?? "127.0.0.1",
|
|
773
792
|
...adminKey !== void 0 ? { adminKey } : {},
|
|
@@ -974,6 +993,7 @@ var serveTarget = {
|
|
|
974
993
|
...scope ? { headers: { "x-mockingbird-scope": scope } } : {}
|
|
975
994
|
}
|
|
976
995
|
} : {},
|
|
996
|
+
...common.adminPrefix !== void 0 ? { adminPrefix: common.adminPrefix } : {},
|
|
977
997
|
...common.adminKey !== void 0 ? { adminKey: common.adminKey } : {},
|
|
978
998
|
...common.seed !== void 0 ? { seed: common.seed } : {},
|
|
979
999
|
...common.onLog ? { onLog: common.onLog } : {}
|
|
@@ -1004,4 +1024,4 @@ export {
|
|
|
1004
1024
|
createServer2 as createServer,
|
|
1005
1025
|
serveTarget
|
|
1006
1026
|
};
|
|
1007
|
-
//# sourceMappingURL=chunk-
|
|
1027
|
+
//# sourceMappingURL=chunk-7LPCTLIJ.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/server.ts", "../../../adapters/node/src/cli.ts", "../../../adapters/node/src/fleet.ts", "../../../adapters/node/src/serve.ts", "../../../adapters/node/src/listen.ts"],
|
|
4
|
+
"sourcesContent": ["/// <reference types=\"node\" />\nimport { readFile } from \"node:fs/promises\"\nimport {\n type CliValues,\n type Listening,\n listen,\n type ServeTarget,\n} from \"@crvouga/mockingbird-adapter-node\"\nimport { defaultCorpus } from \"./corpus.js\"\nimport { pullCorpus } from \"./corpus-tools.js\"\nimport { IDENTITY_MODES, type IdentityMode, type JunctionFixtures } from \"./fixtures.js\"\nimport type { LabAccountLayout } from \"./lab-account-presets.js\"\nimport { type BillingType, defaultBillingTypesFrom } from \"./lab-accounts.js\"\nimport { createRuntime, type JunctionRuntime, type JunctionRuntimeOptions } from \"./runtime.js\"\nimport { parseSealedCorpus, type SealedCorpus } from \"./sealed-corpus.js\"\nimport type { GeoMode } from \"./state.js\"\n\n/** Port `mockingbird-junction serve` listens on when none is given. */\nexport const DEFAULT_PORT = 8787\n\n/** A corpus to serve: the shipped one, none (synthetic), a file path, or a loaded corpus. */\nexport type CorpusSource = \"default\" | \"none\" | (string & {}) | SealedCorpus\n\nexport type JunctionServerOptions = Omit<JunctionRuntimeOptions, \"corpus\"> & {\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 /** Default `\"default\"`: the corpus shipped with this package. */\n corpus?: CorpusSource\n}\n\nexport type JunctionServer = Listening & { runtime: JunctionRuntime }\n\n/** Resolve a {@link CorpusSource} to a corpus, or `undefined` for synthetic data. */\nexport const loadCorpus = async (source: CorpusSource): Promise<SealedCorpus | undefined> => {\n if (typeof source !== \"string\") return source\n if (source === \"none\") return undefined\n if (source === \"default\") return defaultCorpus\n const raw = await readFile(source, \"utf8\").catch(() => undefined)\n if (raw === undefined) throw new Error(`junction mock corpus not found: ${source}`)\n return parseSealedCorpus(JSON.parse(raw))\n}\n\n/**\n * Serve the Junction mock over `node:http`. Resolves once it is listening.\n *\n * const server = await createServer()\n * // point the Vital SDK at server.url; await server.close() when done\n */\nexport const createServer = async (\n options: JunctionServerOptions = {},\n): Promise<JunctionServer> => {\n const { port, host, corpus: source, ...rest } = options\n const corpus = await loadCorpus(source ?? \"default\")\n const runtime = createRuntime({ ...rest, ...(corpus ? { corpus } : {}) })\n const listening = await listen(runtime, {\n port: port ?? 0,\n ...(host !== undefined ? { host } : {}),\n })\n return { ...listening, runtime }\n}\n\nconst asString = (value: string | boolean | undefined): string | undefined =>\n typeof value === \"string\" && value !== \"\" ? value : undefined\n\nconst UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\n\nconst count = (value: string | undefined, flag: string): number | undefined => {\n if (value === undefined) return undefined\n if (!/^\\d+$/.test(value)) throw new Error(`${flag} must be a non-negative integer (got ${value})`)\n return Number.parseInt(value, 10)\n}\n\nconst readJson = async <T>(path: string): Promise<T> => {\n const raw = await readFile(path, \"utf8\").catch(() => undefined)\n if (raw === undefined) throw new Error(`junction mock: file not found: ${path}`)\n try {\n return JSON.parse(raw) as T\n } catch (error) {\n throw new Error(`junction mock: ${path} is not JSON (${(error as Error).message})`)\n }\n}\n\nconst retryDelays = (value: string | undefined): number[] | undefined => {\n if (value === undefined) return undefined\n const delays = value.split(\",\").map((part) => Number.parseInt(part.trim(), 10))\n if (delays.some((delay) => !Number.isFinite(delay) || delay < 0)) {\n throw new Error(`--webhook-retry-delays must be comma-separated milliseconds (got ${value})`)\n }\n return delays\n}\n\n/** `--default-billing-type bioreference=patient_bill_passthrough,quest=client_bill`. */\nconst billingDefaults = (value: string | undefined): Record<string, BillingType> | undefined => {\n if (value === undefined) return undefined\n const entries = value.split(\",\").map((part) => part.split(\"=\").map((side) => side.trim()))\n if (entries.some((entry) => entry.length !== 2 || !entry[0] || !entry[1])) {\n throw new Error(`--default-billing-type must be lab=billing_type pairs (got ${value})`)\n }\n try {\n return defaultBillingTypesFrom(Object.fromEntries(entries))\n } catch (error) {\n throw new Error(`--default-billing-type: ${(error as Error).message}`)\n }\n}\n\n/** How `serve` (and `serve --config`) builds the Junction mock from flags. */\nexport const serveTarget: ServeTarget = {\n name: \"junction\",\n defaultPort: DEFAULT_PORT,\n options: {\n corpus: {\n type: \"string\",\n value: \"<default|none|file>\",\n description: \"Corpus to serve: the shipped one, none (synthetic), or a pulled file\",\n default: \"default\",\n },\n geo: {\n type: \"string\",\n value: \"<corpus|synthetic>\",\n description: \"Unknown ZIPs: refuse (corpus) or invent coverage (synthetic)\",\n },\n \"lab-accounts\": {\n type: \"string\",\n value: \"<file>\",\n description:\n 'Lab accounts to route orders through: a JSON array, or { \"presets\": [...], \"accounts\": [...] }',\n },\n \"team-id\": {\n type: \"string\",\n value: \"<uuid>\",\n description: \"Team the mock answers as (default: the corpus's recorded team)\",\n },\n \"max-users\": {\n type: \"string\",\n value: \"<n>\",\n description: \"Enforce the sandbox's live-user cap (default: unlimited)\",\n },\n identity: {\n type: \"string\",\n value: \"<strict|adopt-users>\",\n description: \"Unknown user ids: 404 (strict) or create on first use\",\n default: \"strict\",\n },\n \"default-billing-type\": {\n type: \"string\",\n value: \"<lab=type,\u2026>\",\n description:\n \"billing_type an order for that lab gets when it omits one (default: client_bill), e.g. bioreference=patient_bill_passthrough\",\n },\n fixtures: {\n type: \"string\",\n value: \"<file>\",\n description:\n 'Users and orders every namespace starts with: { \"users\": [...], \"orders\": [...] }',\n },\n \"journal-size\": {\n type: \"string\",\n value: \"<n>\",\n description: \"Requests each namespace's journal keeps (GET /__admin/requests)\",\n default: \"1000\",\n },\n \"seed-url\": {\n type: \"string\",\n value: \"<url>\",\n description: \"Pull a corpus from this Junction team at boot (prefer a committed corpus)\",\n },\n \"seed-key\": {\n type: \"string\",\n value: \"<key>\",\n description: \"API key for --seed-url (env MOCKINGBIRD_JUNCTION_SEED_KEY)\",\n },\n \"webhook-url\": { type: \"string\", value: \"<url>\", description: \"Deliver signed webhooks here\" },\n \"webhook-secret\": {\n type: \"string\",\n value: \"<whsec_\u2026>\",\n description: \"Svix signing secret (env MOCKINGBIRD_JUNCTION_WEBHOOK_SECRET)\",\n },\n \"webhook-retry-delays\": {\n type: \"string\",\n value: \"<ms,ms,\u2026>\",\n description: \"Delay before each delivery attempt (default: Svix's schedule)\",\n },\n \"webhook-scope\": {\n type: \"string\",\n value: \"<scope>\",\n description: \"Sent as x-mockingbird-scope on every delivery\",\n },\n },\n async create(values: CliValues, common) {\n const seedUrl = asString(values[\"seed-url\"])\n const seedKey = asString(values[\"seed-key\"]) ?? process.env.MOCKINGBIRD_JUNCTION_SEED_KEY\n let corpus: SealedCorpus | undefined\n if (seedUrl !== undefined) {\n if (seedKey === undefined) throw new Error(\"--seed-url needs --seed-key\")\n console.log(\n `junction pulling a corpus from ${seedUrl} (commit one with \\`corpus pull\\` to skip this)`,\n )\n corpus = await pullCorpus({ baseUrl: seedUrl, apiKey: seedKey })\n } else {\n corpus = await loadCorpus(asString(values.corpus) ?? \"default\")\n }\n const geo = asString(values.geo)\n if (geo !== undefined && geo !== \"corpus\" && geo !== \"synthetic\") {\n throw new Error(`--geo must be corpus or synthetic (got ${geo})`)\n }\n const accountsFile = asString(values[\"lab-accounts\"])\n const labAccounts =\n accountsFile === undefined ? undefined : await readJson<LabAccountLayout>(accountsFile)\n const fixturesFile = asString(values.fixtures)\n const fixtures =\n fixturesFile === undefined ? undefined : await readJson<JunctionFixtures>(fixturesFile)\n const teamId = asString(values[\"team-id\"])\n if (teamId !== undefined && !UUID.test(teamId)) {\n throw new Error(`--team-id must be a UUID (got ${teamId})`)\n }\n const maxUsers = count(asString(values[\"max-users\"]), \"--max-users\")\n const journalSize = count(asString(values[\"journal-size\"]), \"--journal-size\")\n const identity = asString(values.identity)\n if (identity !== undefined && !IDENTITY_MODES.includes(identity as IdentityMode)) {\n throw new Error(`--identity must be one of ${IDENTITY_MODES.join(\", \")} (got ${identity})`)\n }\n const defaultBillingTypes = billingDefaults(asString(values[\"default-billing-type\"]))\n const webhookUrl = asString(values[\"webhook-url\"])\n const webhookSecret =\n asString(values[\"webhook-secret\"]) ?? process.env.MOCKINGBIRD_JUNCTION_WEBHOOK_SECRET\n if (webhookUrl !== undefined && webhookSecret === undefined) {\n throw new Error(\"--webhook-url needs --webhook-secret (the whsec_\u2026 your receiver verifies)\")\n }\n const delays = retryDelays(asString(values[\"webhook-retry-delays\"]))\n const scope = asString(values[\"webhook-scope\"])\n return createRuntime({\n ...(corpus ? { corpus } : {}),\n ...(geo ? { geo: geo as GeoMode } : {}),\n ...(labAccounts ? { labAccounts } : {}),\n ...(fixtures ? { fixtures } : {}),\n ...(teamId !== undefined ? { teamId } : {}),\n ...(maxUsers !== undefined ? { limits: { maxUsers } } : {}),\n ...(identity !== undefined ? { identity: identity as IdentityMode } : {}),\n ...(defaultBillingTypes ? { defaultBillingTypes } : {}),\n ...(journalSize !== undefined ? { journalSize } : {}),\n ...(webhookUrl !== undefined && webhookSecret !== undefined\n ? {\n webhooks: {\n url: webhookUrl,\n secret: webhookSecret,\n ...(delays ? { retryDelaysMs: delays } : {}),\n ...(scope ? { headers: { \"x-mockingbird-scope\": scope } } : {}),\n },\n }\n : {}),\n ...(common.adminPrefix !== undefined ? { adminPrefix: common.adminPrefix } : {}),\n ...(common.adminKey !== undefined ? { adminKey: common.adminKey } : {}),\n ...(common.seed !== undefined ? { seed: common.seed } : {}),\n ...(common.onLog ? { onLog: common.onLog } : {}),\n })\n },\n banner(runtime) {\n const junction = runtime as JunctionRuntime\n const api = junction.instance()\n const info = api.corpusInfo()\n return [\n info\n ? `corpus ${info.label}: ${info.observations} observations, ${info.zips} ZIPs, ${info.labTests} lab tests, ${info.labAccounts} lab accounts (recorded ${info.recordedAt} from ${info.source})`\n : \"corpus none: synthetic catalog and coverage\",\n `geo ${api.geoMode}${api.geoMode === \"corpus\" ? \" (unknown ZIPs answer 424 MOCKINGBIRD_UNKNOWN_ZIP)\" : \"\"}`,\n `team ${api.teamId}`,\n `lab accounts: ${api.labAccounts().length}`,\n `limits: ${\n Object.entries(api.limits)\n .filter(([, value]) => value !== null && value !== false)\n .map(([key, value]) => `${key}=${String(value)}`)\n .join(\", \") || \"none (sandbox caps off)\"\n }`,\n `identity ${api.identity}`,\n `webhooks: ${junction.webhooks ? \"signed delivery on\" : \"off\"}`,\n \"auth: any x-vital-api-key value (e.g. sk_us_mockingbird)\",\n ]\n },\n}\n", "import type { EventEmitter } from \"node:events\"\nimport { readFile } from \"node:fs/promises\"\nimport { createRequire } from \"node:module\"\nimport { resolve } from \"node:path\"\nimport { pathToFileURL } from \"node:url\"\nimport { type ParseArgsConfig, parseArgs } from \"node:util\"\nimport type { RequestLog, ServiceInstance, ServiceRuntime } from \"@crvouga/mockingbird-service\"\nimport { resolveAdminPrefix } from \"@crvouga/mockingbird-service\"\nimport { type FleetTarget, startFleet } from \"./fleet.js\"\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 adminPrefix?: string\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 /** After the HTTP server is bound. A service that speaks more than HTTP attaches it here. */\n listening?(server: Listening): void\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-prefix\": {\n type: \"string\",\n value: \"<path>\",\n description: \"Internal API prefix (default /__admin; env MOCKINGBIRD_ADMIN_PREFIX)\",\n },\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 \"ready-file\": {\n type: \"string\",\n description: \"Atomically publish fleet endpoint JSON\",\n value: \"<file>\",\n },\n \"connections-file\": {\n type: \"string\",\n description: \"Write private connection URLs with mode 0600\",\n value: \"<file>\",\n },\n \"ready-json\": {\n type: \"boolean\",\n description: \"Emit one public JSON record after fleet readiness\",\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 // A rejection says what arrived (never the body) and why the service refused it.\n const received = entry.request\n ? ` received=${entry.request.bodyBytes === null ? \"?\" : `${entry.request.bodyBytes}B`} ct=${entry.request.contentType ?? \"-\"}${\n entry.request.transferEncoding ? ` te=${entry.request.transferEncoding}` : \"\"\n }`\n : \"\"\n const issues = entry.issues?.length\n ? ` issues=${entry.issues\n .slice(0, 3)\n .map((issue) => `${issue.path || \"$\"}: ${issue.message}`)\n .join(\"; \")}${entry.issues.length > 3 ? ` (+${entry.issues.length - 3})` : \"\"}`\n : \"\"\n console.log(\n `${entry.service} ${entry.method} ${entry.path} ${entry.status} ${op} ${entry.durationMs}ms${ns}${fault}${adopted}${received}${issues}`,\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 protocol?: \"http\" | \"postgres\" | \"redis\"\n port?: number\n host?: string\n adminPrefix?: string\n adminKey?: string\n seed?: string\n password?: string\n user?: string\n database?: string\n /** Protocol namespace selectors: database names for Postgres, logical DB indexes for Redis. */\n namespaces?: Record<string, string | number>\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 adminPrefix?: string\n adminKey?: string\n namespace?: string\n control?: { host?: string; port?: number }\n}\n\nconst loadTarget = async (name: string, own: FleetTarget): Promise<FleetTarget> => {\n if (name === own.name) return own\n const specifier = `@crvouga/mockingbird-service-${name}/server`\n try {\n // A CLI run with npx may live outside the consumer project. Discover its locally\n // installed services as well as siblings of the bundled CLI.\n let mod: { serveTarget?: FleetTarget }\n try {\n mod = (await import(specifier)) as { serveTarget?: FleetTarget }\n } catch {\n const fromProject = createRequire(resolve(process.cwd(), \"package.json\"))\n mod = (await import(pathToFileURL(fromProject.resolve(specifier)).href)) as {\n serveTarget?: FleetTarget\n }\n }\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: {\n port: number\n host: string\n adminPrefix?: string\n adminKey?: string\n seed?: string\n log: LogFormat\n },\n): Promise<Listening> => {\n const adminPrefix = resolveAdminPrefix(config.adminPrefix)\n const runtime = await target.create(values, {\n adminPrefix,\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 target.listening?.(listening)\n console.log(`${target.name} mock listening on ${listening.url}`)\n console.log(`${target.name} health: GET ${listening.url}${adminPrefix}/health`)\n console.log(\n `${target.name} admin: ${listening.url}${adminPrefix} (${config.adminKey ? \"x-mockingbird-admin-key required\" : \"open \u2014 pass --admin-key to lock\"})`,\n )\n console.log(`${target.name} admin ui: ${listening.url}${adminPrefix}/ui`)\n for (const line of target.banner?.(runtime) ?? [])\n console.log(`${target.name} ${line.replaceAll(\"/__admin\", adminPrefix)}`)\n return listening\n}\n\nconst untilSignal = async (servers: { close(): Promise<void> }[]): Promise<number> =>\n new Promise((resolve) => {\n const stop = async () => {\n ;(process as EventEmitter).removeListener(\"SIGINT\", stop)\n ;(process as EventEmitter).removeListener(\"SIGTERM\", stop)\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: FleetTarget): CliCommand => ({\n summary: `Serve the ${target.name} mock or a configured fleet`,\n options: { ...COMMON_SERVE_OPTIONS, ...(\"options\" in target ? 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 try {\n const config = JSON.parse(await readFile(configPath, \"utf8\")) as MockingbirdConfig\n config.adminPrefix = resolveAdminPrefix(\n config.adminPrefix ??\n asString(values[\"admin-prefix\"]) ??\n process.env.MOCKINGBIRD_ADMIN_PREFIX,\n )\n const adminKey =\n config.adminKey ?? asString(values[\"admin-key\"]) ?? process.env.MOCKINGBIRD_ADMIN_KEY\n if (adminKey !== undefined) config.adminKey = adminKey\n const fleet = await startFleet(config, {\n load: (name) => loadTarget(name, target),\n onLog: formatLog(config.log ?? log),\n ...(asString(values[\"ready-file\"]) ? { readyFile: asString(values[\"ready-file\"]) } : {}),\n ...(asString(values[\"connections-file\"])\n ? { connectionsFile: asString(values[\"connections-file\"]) }\n : {}),\n onReady: (manifest) => {\n if (values[\"ready-json\"]) console.log(JSON.stringify(manifest))\n else\n for (const [name, endpoint] of Object.entries(manifest.services))\n console.log(`${name} mock listening on ${endpoint.url}`)\n },\n })\n return untilSignal([fleet])\n } catch (error) {\n console.error(error instanceof Error ? error.message : String(error))\n return 1\n }\n }\n if (\"start\" in target) {\n console.error(\"Use --config to supervise protocol services with this command\")\n return 2\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 adminPrefix: resolveAdminPrefix(\n asString(values[\"admin-prefix\"]) ?? process.env.MOCKINGBIRD_ADMIN_PREFIX,\n ),\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 { randomUUID } from \"node:crypto\"\nimport { chmod, readFile, rename, rm, writeFile } from \"node:fs/promises\"\nimport type { FetchAPI } from \"@crvouga/mockingbird-core\"\nimport type { Clock, ServiceInstance, ServiceRuntime } from \"@crvouga/mockingbird-service\"\nimport { createClock, parseDuration, resolveAdminPrefix } from \"@crvouga/mockingbird-service\"\nimport type { CommonServeOptions, ConfigService, MockingbirdConfig, ServeTarget } from \"./cli.js\"\nimport type { EndpointManifest } from \"./fleet-manifest.js\"\nimport { type Listening, listen } from \"./listen.js\"\n\nexport type { EndpointManifest } from \"./fleet-manifest.js\"\n\nexport type FleetDiagnostics = {\n activeRequests: number\n activeConnections: number\n blockedCommands: number\n pendingJobs: number\n activeJobs?: number\n pendingWebhooks: number\n unmatchedRequests: number\n}\n\n/** Protocol packages own their state, listeners, credentials and namespace selection. */\nexport type FleetChild = {\n protocol: \"http\" | \"postgres\" | \"redis\"\n url: string\n connection?: string\n connections?: Record<string, string>\n healthUrl?: string\n adminUrl?: string\n namespaces: Record<string, unknown>\n ready(): Promise<boolean>\n close(): Promise<void>\n /** Fence new work synchronously; diagnostics must also account for work already in flight. */\n lock(namespace: string): () => void\n diagnostics(namespace: string): FleetDiagnostics\n checkpoint(namespace: string): Promise<unknown>\n restore(namespace: string, checkpoint: unknown): Promise<void>\n reset(namespace: string): Promise<void>\n clock(namespace: string): Clock\n settle?(namespace: string): Promise<void>\n}\n\nexport type ProtocolTarget = {\n name: string\n protocol: \"postgres\" | \"redis\"\n defaultPort: number\n start(entry: ConfigService): Promise<FleetChild>\n}\nexport type FleetTarget = ServeTarget | ProtocolTarget\n\nexport type FleetOptions = {\n load(name: string): Promise<FleetTarget>\n onLog?: CommonServeOptions[\"onLog\"]\n readyFile?: string | undefined\n connectionsFile?: string | undefined\n onReady?(manifest: EndpointManifest): void\n}\n\nconst EMPTY: FleetDiagnostics = {\n activeRequests: 0,\n activeConnections: 0,\n blockedCommands: 0,\n pendingJobs: 0,\n pendingWebhooks: 0,\n unmatchedRequests: 0,\n}\nconst NS = /^[A-Za-z0-9_.-]{1,64}$/\nconst json = (status: number, value: unknown) => Response.json(value, { status })\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value)\nconst pending = (d: FleetDiagnostics) =>\n d.activeRequests + d.blockedCommands + d.pendingJobs + d.pendingWebhooks\n\nconst publicUrl = (raw: string): string => {\n const url = new URL(raw)\n url.password = \"\"\n return url.href\n}\n\n/** Atomic publication; credentials only go in an explicitly requested 0600 file. */\nconst atomicWrite = async (path: string, value: unknown) => {\n const temp = `${path}.${randomUUID()}.tmp`\n try {\n await writeFile(temp, `${JSON.stringify(value, null, 2)}\\n`, { mode: 0o600, flag: \"wx\" })\n await chmod(temp, 0o600)\n await rename(temp, path)\n } finally {\n await rm(temp, { force: true })\n }\n}\n\nconst removeOwned = async (path: string | undefined, id: string) => {\n if (!path) return\n try {\n const value: unknown = JSON.parse(await readFile(path, \"utf8\"))\n if (isObject(value) && value.id === id) await rm(path, { force: true })\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error\n }\n}\n\nconst httpChild = async (\n target: ServeTarget,\n entry: ConfigService,\n options: FleetOptions,\n): Promise<FleetChild> => {\n const runtime: ServiceRuntime<ServiceInstance> = await target.create(entry.options ?? {}, {\n adminPrefix: resolveAdminPrefix(entry.adminPrefix),\n adminKey: entry.adminKey,\n seed: entry.seed,\n onLog: options.onLog,\n })\n const adminPrefix = resolveAdminPrefix(entry.adminPrefix)\n runtime.isolateNamespaces()\n const locked = new Set<string>()\n const active = new Map<string, number>()\n const api: FetchAPI = {\n async fetch(request) {\n const namespace = runtime.namespaceOf(request)\n if (locked.has(namespace)) return json(409, { error: \"fleet control in progress\", namespace })\n active.set(namespace, (active.get(namespace) ?? 0) + 1)\n try {\n return await runtime.fetch(request)\n } finally {\n active.set(namespace, (active.get(namespace) ?? 1) - 1)\n }\n },\n }\n let server: Listening | undefined\n try {\n server = await listen(api, {\n port: entry.port ?? target.defaultPort,\n host: entry.host ?? \"127.0.0.1\",\n })\n target.listening?.(server)\n } catch (error) {\n runtime.stop?.()\n await server?.close()\n runtime.webhooks?.clear()\n await runtime.webhooks?.idle()\n throw error\n }\n return {\n protocol: \"http\",\n url: server.url,\n healthUrl: `${server.url}${adminPrefix}/health`,\n adminUrl: `${server.url}${adminPrefix}`,\n namespaces: { header: \"x-mockingbird-namespace\", path: `${adminPrefix}/ns/{name}` },\n ready: async () => {\n try {\n return (\n await fetch(`${server.url}${adminPrefix}/health`, { signal: AbortSignal.timeout(2000) })\n ).ok\n } catch {\n return false\n }\n },\n async close() {\n runtime.stop?.()\n runtime.webhooks?.clear()\n await server.close()\n await runtime.webhooks?.idle()\n },\n lock(namespace) {\n if (locked.has(namespace)) throw new Error(\"namespace already locked\")\n locked.add(namespace)\n return () => locked.delete(namespace)\n },\n diagnostics(namespace) {\n return {\n ...EMPTY,\n activeRequests: active.get(namespace) ?? 0,\n pendingWebhooks: runtime.webhooks?.pending(namespace) ?? 0,\n unmatchedRequests: runtime.metrics\n .report(namespace)\n .unmatched.reduce((n, r) => n + r.count, 0),\n }\n },\n async checkpoint(namespace) {\n return runtime.fleetSnapshot(namespace)\n },\n async restore(namespace, checkpoint) {\n runtime.fleetRestore(checkpoint, namespace)\n },\n reset: (namespace) => runtime.reset(namespace),\n clock: (namespace) => runtime.namespaceClock(namespace),\n async settle(namespace) {\n const instance = runtime.instance(namespace) as ServiceInstance & { tick?(): unknown }\n instance.tick?.()\n await runtime.webhooks?.idle()\n },\n }\n}\n\nexport type Fleet = {\n readonly manifest: EndpointManifest\n readonly children: ReadonlyMap<string, FleetChild>\n fetch(request: Request): Promise<Response>\n close(): Promise<void>\n}\n\n/** Resolves only after every child and the aggregate control listener are healthy. */\nexport async function startFleet(config: MockingbirdConfig, options: FleetOptions): Promise<Fleet> {\n const id = randomUUID()\n const startedAt = new Date().toISOString()\n const children = new Map<string, FleetChild>()\n const clocks = new Map<string, Clock>()\n const checkpoints = new Map<\n string,\n { namespace: string; values: Map<string, unknown>; clock: ReturnType<Clock[\"state\"]> }\n >()\n let supervisor: Listening | undefined\n let stopped = false\n let controlling = false\n const close = async () => {\n if (stopped) return\n stopped = true\n await Promise.allSettled([...children.values()].map((child) => child.close()))\n await supervisor?.close()\n await removeOwned(options.readyFile, id)\n await removeOwned(options.connectionsFile, id)\n }\n // Invalidate a previous process's artifacts before attempting startup.\n if (options.readyFile) await rm(options.readyFile, { force: true })\n if (options.connectionsFile) await rm(options.connectionsFile, { force: true })\n\n const clock = (namespace: string) => {\n let value = clocks.get(namespace)\n if (!value) {\n value = createClock()\n clocks.set(namespace, value)\n }\n return value\n }\n const select = (body: Record<string, unknown>): Map<string, FleetChild> => {\n if (body.services === undefined) return children\n if (!Array.isArray(body.services) || body.services.length === 0)\n throw new Error(\"services must be a nonempty list\")\n const selected = new Map<string, FleetChild>()\n for (const name of body.services) {\n if (typeof name !== \"string\" || !children.has(name))\n throw new Error(\"unknown service in selection\")\n selected.set(name, children.get(name) as FleetChild)\n }\n return selected\n }\n const diagnostics = (namespace: string) =>\n Object.fromEntries([...children].map(([name, child]) => [name, child.diagnostics(namespace)]))\n const transaction = async (\n namespace: string,\n selected: Map<string, FleetChild>,\n run: (name: string, child: FleetChild) => Promise<unknown>,\n ): Promise<Response> => {\n if (controlling) return json(409, { error: \"another fleet operation is in progress\" })\n controlling = true\n const release: (() => void)[] = []\n const before = new Map<string, unknown>()\n const results: Record<string, unknown> = {}\n let failure: string | undefined\n try {\n for (const [name, child] of selected) {\n failure = name\n release.push(child.lock(namespace))\n }\n const busy = Object.fromEntries(\n [...selected]\n .filter(([, child]) => {\n const state = child.diagnostics(namespace)\n return (\n state.activeRequests +\n state.blockedCommands +\n state.pendingWebhooks +\n (state.activeJobs ?? 0) >\n 0\n )\n })\n .map(([name, child]) => [name, child.diagnostics(namespace)]),\n )\n if (Object.keys(busy).length)\n return json(409, { error: \"namespace is not quiescent\", services: busy })\n for (const [name, child] of selected) {\n failure = name\n before.set(name, await child.checkpoint(namespace))\n }\n for (const [name, child] of selected) {\n failure = name\n results[name] = { status: \"ok\", result: await run(name, child) }\n }\n return json(200, { status: \"ok\", namespace, services: results })\n } catch {\n const rollback: Record<string, string> = {}\n // Roll back even the child whose mutation failed; it may have partially changed state.\n for (const [name, point] of before) {\n try {\n await selected.get(name)?.restore(namespace, point)\n rollback[name] = \"restored\"\n } catch {\n rollback[name] = \"failed\"\n }\n }\n return json(500, {\n status: \"failed\",\n namespace,\n failedService: failure,\n services: results,\n rollback,\n rolledBack:\n before.size > 0 && Object.values(rollback).every((value) => value === \"restored\"),\n })\n } finally {\n for (const unlock of release.reverse()) unlock()\n controlling = false\n }\n }\n\n const api: FetchAPI = {\n async fetch(request) {\n const url = new URL(request.url)\n const adminPrefix = resolveAdminPrefix(config.adminPrefix)\n const path = url.pathname.startsWith(`${adminPrefix}/`)\n ? url.pathname.slice(adminPrefix.length)\n : \"\"\n if (path === \"/health\" && request.method === \"GET\") {\n const states = await Promise.all(\n [...children].map(async ([name, child]) => {\n let protocolReady = false\n try {\n protocolReady = await child.ready()\n } catch {\n /* reported as failed */\n }\n return [\n name,\n {\n processReady: !stopped,\n protocolReady,\n status: protocolReady ? \"ready\" : \"failed\",\n url: publicUrl(child.url),\n },\n ]\n }),\n )\n const ready =\n !stopped &&\n states.every(([, state]) => (state as { protocolReady: boolean }).protocolReady)\n return json(ready ? 200 : 503, {\n status: ready ? \"ready\" : \"failed\",\n id,\n services: Object.fromEntries(states),\n })\n }\n if (!path.startsWith(\"/fleet/\")) return json(404, { error: \"not found\" })\n const adminKey = config.adminKey ?? process.env.MOCKINGBIRD_ADMIN_KEY\n if (adminKey !== undefined && request.headers.get(\"x-mockingbird-admin-key\") !== adminKey)\n return json(401, { error: \"admin key required\" })\n const route = /^\\/fleet\\/namespaces\\/([^/]+)\\/(reset|snapshots)(?:\\/([^/]+)\\/restore)?$/.exec(\n path,\n )\n const namespace = route\n ? decodeURIComponent(route[1] as string)\n : (url.searchParams.get(\"namespace\") ??\n request.headers.get(\"x-mockingbird-namespace\") ??\n config.namespace ??\n \"default\")\n if (!NS.test(namespace)) return json(400, { error: \"invalid namespace\" })\n if (request.method === \"GET\" && path === \"/fleet/metrics\")\n return json(200, { namespace, services: diagnostics(namespace) })\n if (request.method === \"GET\" && path === \"/fleet/clock\")\n return json(200, {\n namespace,\n ...clock(namespace).state(),\n services: Object.fromEntries(\n [...children].map(([name, child]) => [name, child.clock(namespace).state()]),\n ),\n })\n if (request.method !== \"POST\") return json(405, { error: \"method not allowed\" })\n let body: Record<string, unknown>\n try {\n const text = await request.text()\n const value: unknown = text ? JSON.parse(text) : {}\n if (!isObject(value)) throw new Error(\"expected object\")\n body = value\n } catch {\n return json(400, { error: \"expected JSON object\" })\n }\n let selected: Map<string, FleetChild>\n try {\n selected = select(body)\n } catch (error) {\n return json(400, { error: error instanceof Error ? error.message : \"bad selection\" })\n }\n if (path === \"/fleet/wait-until-idle\") {\n const services = diagnostics(namespace)\n const idle = Object.values(services).every((d) => pending(d) === 0)\n return json(idle ? 200 : 409, { status: idle ? \"idle\" : \"busy\", namespace, services })\n }\n if (path === \"/fleet/clock\") {\n const current = clock(namespace)\n let target = current.now()\n if (body.set !== undefined) {\n target =\n typeof body.set === \"number\"\n ? body.set\n : typeof body.set === \"string\"\n ? Date.parse(body.set)\n : NaN\n if (!Number.isFinite(target))\n return json(400, { error: \"set must be epoch ms or ISO-8601\" })\n }\n if (body.advance !== undefined) {\n const delta = parseDuration(body.advance)\n if (delta === undefined) return json(400, { error: \"invalid advance\" })\n target += delta\n }\n const frozen = body.freeze === undefined ? current.state().frozen : body.freeze\n if (typeof frozen !== \"boolean\") return json(400, { error: \"freeze must be boolean\" })\n const response = await transaction(namespace, selected, async (_name, child) => {\n const childClock = child.clock(namespace)\n childClock.freeze()\n childClock.set(target)\n if (!frozen) childClock.unfreeze()\n await child.settle?.(namespace)\n return childClock.state()\n })\n if (response.ok) {\n current.freeze()\n current.set(target)\n if (!frozen) current.unfreeze()\n }\n return response\n }\n if (!route) return json(404, { error: \"not found\" })\n if (route[2] === \"reset\") {\n if (route[3]) return json(404, { error: \"not found\" })\n const response = await transaction(namespace, selected, async (_name, child) =>\n child.reset(namespace),\n )\n if (response.ok && selected.size === children.size) clock(namespace).reset()\n return response\n }\n if (route[3]) {\n const point = checkpoints.get(route[3])\n if (!point || point.namespace !== namespace)\n return json(404, { error: \"no snapshot in this namespace\" })\n const restored = new Map(\n [...point.values].map(([name]) => [name, children.get(name) as FleetChild]),\n )\n const response = await transaction(namespace, restored, async (name, child) =>\n child.restore(namespace, point.values.get(name)),\n )\n if (response.ok) {\n const current = clock(namespace)\n current.freeze()\n current.set(point.clock.now)\n if (!point.clock.frozen) current.unfreeze()\n }\n return response\n }\n const snapshotId = randomUUID()\n const values = new Map<string, unknown>()\n const response = await transaction(namespace, selected, async (name, child) => {\n values.set(name, await child.checkpoint(namespace))\n return { checkpoint: `${snapshotId}:${name}` }\n })\n if (!response.ok) return response\n checkpoints.set(snapshotId, { namespace, values, clock: clock(namespace).state() })\n return json(201, {\n ...((await response.json()) as Record<string, unknown>),\n id: snapshotId,\n label: body.label,\n })\n },\n }\n try {\n const adminPrefix = resolveAdminPrefix(config.adminPrefix)\n if (!isObject(config.services) || Object.keys(config.services).length === 0)\n throw new Error(\"config must contain at least one service\")\n for (const [name, entry] of Object.entries(config.services)) {\n if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(name)) throw new Error(\"invalid service name\")\n try {\n const target = await options.load(name)\n if (entry.protocol && entry.protocol !== (\"protocol\" in target ? target.protocol : \"http\"))\n throw new Error(\"configured protocol does not match target\")\n const adminKey = entry.adminKey ?? config.adminKey ?? process.env.MOCKINGBIRD_ADMIN_KEY\n const child =\n \"start\" in target\n ? await target.start(entry)\n : await httpChild(\n target,\n {\n ...entry,\n adminPrefix: resolveAdminPrefix(entry.adminPrefix ?? adminPrefix),\n ...(adminKey !== undefined ? { adminKey } : {}),\n },\n options,\n )\n children.set(name, child)\n if (!(await child.ready())) throw new Error(\"protocol readiness failed\")\n } catch {\n throw new Error(`service ${name} failed to start; all started listeners were closed`)\n }\n }\n supervisor = await listen(api, {\n port: config.control?.port ?? 0,\n host: config.control?.host ?? \"127.0.0.1\",\n })\n const manifest: EndpointManifest = {\n version: 1,\n state: \"ready\",\n pid: process.pid,\n id,\n startedAt,\n adminBase: `${supervisor.url}${adminPrefix}/fleet`,\n healthUrl: `${supervisor.url}${adminPrefix}/health`,\n services: Object.fromEntries(\n [...children].map(([name, child]) => [\n name,\n {\n protocol: child.protocol,\n url: publicUrl(child.url),\n healthUrl: child.healthUrl ?? `${supervisor?.url}${adminPrefix}/health`,\n adminUrl: child.adminUrl ?? `${supervisor?.url}${adminPrefix}/fleet`,\n namespaces: child.namespaces,\n processReady: true,\n protocolReady: true,\n },\n ]),\n ),\n }\n if (options.connectionsFile)\n await atomicWrite(options.connectionsFile, {\n version: 1,\n id,\n pid: process.pid,\n services: Object.fromEntries(\n [...children].map(([name, child]) => [\n name,\n { url: child.connection ?? child.url, namespaces: child.connections },\n ]),\n ),\n })\n if (options.readyFile) await atomicWrite(options.readyFile, manifest)\n options.onReady?.(manifest)\n return { manifest, children, fetch: api.fetch, close }\n } catch (error) {\n await close()\n throw error\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 aborted = new AbortController()\n res.once(\"close\", () => {\n if (!res.writableFinished) aborted.abort()\n })\n init.signal = aborted.signal\n const request = new Request(url, init)\n let response: Response\n try {\n response = await api.fetch(request)\n } catch (error) {\n // A `drop` fault: destroy the socket so the client sees the connection die.\n if ((error as { code?: string }).code === \"MOCKINGBIRD_DROP\") {\n req.socket.destroy()\n return\n }\n res.writeHead(500, { \"content-type\": \"application/json\" })\n res.end(\n JSON.stringify({\n error: {\n type: \"mockingbird_internal\",\n message: error instanceof Error ? error.message : String(error),\n },\n }),\n )\n return\n }\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 if (!response.body) {\n res.writeHead(response.status, headers)\n res.end()\n return\n }\n // Stream the body chunk by chunk: event streams and long-polls must not be buffered.\n res.writeHead(response.status, headers)\n res.flushHeaders()\n const reader = response.body.getReader()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n if (!res.write(value)) await new Promise<void>((resolve) => res.once(\"drain\", resolve))\n }\n res.end()\n } catch {\n res.destroy()\n } finally {\n reader.releaseLock()\n }\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"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["readFile", "readFile", "resolve", "resolve", "response", "resolve", "readFile", "adminKey", "readFile", "createServer", "asString"]
|
|
7
|
+
}
|