@crvouga/mockingbird-service-junction 2.3.1 → 3.1.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 -0
- package/DISCOVERY.md +2 -2
- package/README.md +42 -42
- package/SUPPORT.md +16 -16
- package/dist/{chunk-UHZKTYBX.js → chunk-DBNCTIW4.js} +34 -4
- package/dist/chunk-DBNCTIW4.js.map +7 -0
- package/dist/{chunk-RLSHRM7U.js → chunk-SENEZJTT.js} +5 -5
- package/dist/{chunk-RLSHRM7U.js.map → chunk-SENEZJTT.js.map} +2 -2
- package/dist/cli.js +2 -2
- package/dist/index.js +1 -1
- package/dist/server.js +2 -2
- package/openapi.yaml +15 -15
- package/package.json +6 -3
- package/dist/chunk-UHZKTYBX.js.map +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# Changelog — @crvouga/mockingbird-service-junction
|
|
2
2
|
|
|
3
|
+
## 3.1.0 (2026-10-08)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- redesign emulator experience ([d6038c2](https://github.com/crvouga/mockingbird/commit/d6038c27eebbaa1751f02bc9305002a5b1304779))
|
|
8
|
+
|
|
9
|
+
### Dependencies
|
|
10
|
+
|
|
11
|
+
- `@crvouga/mockingbird-service-sqlite`
|
|
12
|
+
|
|
13
|
+
## 3.0.0 (2026-10-07)
|
|
14
|
+
|
|
15
|
+
### ⚠️ Breaking changes
|
|
16
|
+
|
|
17
|
+
- point the repo at crvouga/mockingbird ([1bf35a4](https://github.com/crvouga/mockingbird/commit/1bf35a422b84a85b50b09b72bd7cc7093082a86e))
|
|
18
|
+
- point the repo at crvouga/emulates ([cdb5e53](https://github.com/crvouga/mockingbird/commit/cdb5e536ed8c1f52345e3984f089001c25fdb08a))
|
|
19
|
+
- rename Emulators to Emulates ([2e10d9c](https://github.com/crvouga/mockingbird/commit/2e10d9cff84c54ac37768fc9a19d1aefd3943744))
|
|
20
|
+
- rebrand Mockingbird to Emulators ([1adca65](https://github.com/crvouga/mockingbird/commit/1adca65ce28242f11cff98eac05d2be88f680cbe))
|
|
21
|
+
|
|
22
|
+
### Fixes and improvements
|
|
23
|
+
|
|
24
|
+
- typecheck the brand gate before builds ([fc36095](https://github.com/crvouga/mockingbird/commit/fc3609514de70ffe3170a5d216fb8a49f9ce7cbb))
|
|
25
|
+
- format the emulates records query ([8698872](https://github.com/crvouga/mockingbird/commit/8698872509d06002be5a8fcdc85d79f8462320c3))
|
|
26
|
+
- preserve JSON prototype keys ([fba8e4d](https://github.com/crvouga/mockingbird/commit/fba8e4d2e4219d825f1ca705cabc44b5dbbb8f02))
|
|
27
|
+
|
|
3
28
|
## 2.3.1 (2026-10-05)
|
|
4
29
|
|
|
5
30
|
### Fixes and improvements
|
package/DISCOVERY.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @crvouga/mockingbird-service-junction discovery
|
|
2
2
|
|
|
3
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
|
|
4
|
+
inside `node_modules/@crvouga/mockingbird-service-junction/`; no repository checkout is needed to discover the emulator's
|
|
5
5
|
supported surface or documented behavior.
|
|
6
6
|
|
|
7
7
|
## Capability and behavior sources
|
|
@@ -48,7 +48,7 @@ designed for assertions and diagnosis by consuming test suites.
|
|
|
48
48
|
## Report a mismatch or missing capability
|
|
49
49
|
|
|
50
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
|
|
51
|
+
operation/command, a minimal redacted request, actual emulator result, expected oracle result or vendor
|
|
52
52
|
documentation, and whether the mismatch appears in the matrix. Never include keys, tokens,
|
|
53
53
|
customer data, prompts, PHI, card data, or unredacted recordings.
|
|
54
54
|
|
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @crvouga/mockingbird-service-junction
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Local emulators. Real API contracts. Part of [Mockingbird](https://github.com/crvouga/mockingbird).
|
|
4
4
|
|
|
5
|
-
Stateful
|
|
5
|
+
Stateful emulator of the [Junction (formerly Vital) API](https://docs.junction.com/): users
|
|
6
6
|
(`/v2/user`), the lab-testing catalog, lab orders (create, cancel, simulate, results,
|
|
7
7
|
requisitions), at-home phlebotomy and patient-service-center (PSC) scheduling, and the
|
|
8
8
|
`labtest.order.*` / `labtest.appointment.updated` webhooks. All 40 operations in the vendored
|
|
@@ -10,7 +10,7 @@ OpenAPI subset are served, and behaviour is checked by differential property tes
|
|
|
10
10
|
Junction sandbox.
|
|
11
11
|
|
|
12
12
|
Use it to take Junction off your suite's critical path: no sandbox key, no shared 50-user sandbox
|
|
13
|
-
cap (the
|
|
13
|
+
cap (the emulator enforces no sandbox limit unless a test [asks for one](#sandbox-limits)), no
|
|
14
14
|
cross-suite interference. Serve it as a local origin with one command, or run it in-process.
|
|
15
15
|
|
|
16
16
|
```bash
|
|
@@ -18,10 +18,10 @@ npx mockingbird-junction serve # http://127.0.0.1:8787, recorded sandbox corpu
|
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
- Operation coverage: [SUPPORT.md](https://github.com/crvouga/mockingbird/blob/main/packages/service/junction/SUPPORT.md)
|
|
21
|
-
- Drop-in readiness and the sandbox quirks the
|
|
21
|
+
- Drop-in readiness and the sandbox quirks the emulator mirrors:
|
|
22
22
|
[docs/drop-in.md](https://github.com/crvouga/mockingbird/blob/main/packages/service/junction/docs/drop-in.md)
|
|
23
23
|
- Behaviour notes: [docs/behavior.md](https://github.com/crvouga/mockingbird/blob/main/packages/service/junction/docs/behavior.md)
|
|
24
|
-
- **What the
|
|
24
|
+
- **What the emulator does not model:** [below](#what-is-and-is-not-modelled). Read it before trusting a
|
|
25
25
|
green suite.
|
|
26
26
|
|
|
27
27
|
## Install
|
|
@@ -37,7 +37,7 @@ native dependencies: state lives in an in-memory SQLite engine written in TypeSc
|
|
|
37
37
|
| --- | --- | --- |
|
|
38
38
|
| `@crvouga/mockingbird-service-junction` | any (Node, Bun, Workers, browsers) | `JunctionAPI`, `createRuntime`, corpus and verify tools |
|
|
39
39
|
| `@crvouga/mockingbird-service-junction/server` | Node | `createServer()` — a listening HTTP server |
|
|
40
|
-
| `@crvouga/mockingbird-service-junction/corpus` | any | `defaultCorpus` — the recording shipped in the package (a separate entry, so importing the
|
|
40
|
+
| `@crvouga/mockingbird-service-junction/corpus` | any | `defaultCorpus` — the recording shipped in the package (a separate entry, so importing the emulator never parses it) |
|
|
41
41
|
| `mockingbird-junction` (bin) | Node | `serve`, `corpus pull`, `corpus diff`, `verify` |
|
|
42
42
|
|
|
43
43
|
## Usage
|
|
@@ -58,12 +58,12 @@ npx mockingbird-junction serve --help
|
|
|
58
58
|
| `--corpus <default\|none\|file>` | `default` | The shipped corpus, no corpus (synthetic data), or a file from `corpus pull` |
|
|
59
59
|
| `--geo <corpus\|synthetic>` | `corpus` with a corpus | How unknown ZIPs are answered; see [Geo](#geo-corpus-or-synthetic) |
|
|
60
60
|
| `--lab-accounts <file>` | built-in fixtures | [Lab accounts](#lab-accounts): a JSON array, or `{ "presets": [...], "accounts": [...] }` |
|
|
61
|
-
| `--team-id <uuid>` | the corpus's team | The [team](#team-identity) the
|
|
61
|
+
| `--team-id <uuid>` | the corpus's team | The [team](#team-identity) the emulator answers as |
|
|
62
62
|
| `--max-users <n>` | unlimited | Enforce the sandbox's [live-user cap](#sandbox-limits) |
|
|
63
63
|
| `--identity <strict\|adopt-users>` | `strict` | Unknown `user_id`s: 404, or [create on first use](#fixtures-and-identity) |
|
|
64
64
|
| `--default-billing-type <lab=type,…>` | `client_bill` | The `billing_type` an order for that lab gets when it omits one ([billing](#default-billing-type)) |
|
|
65
65
|
| `--fixtures <file>` | — | [Users and orders](#fixtures-and-identity) every namespace starts with |
|
|
66
|
-
| `--journal-size <n>` | `1000` | Requests each namespace's [journal](#is-this-the-
|
|
66
|
+
| `--journal-size <n>` | `1000` | Requests each namespace's [journal](#is-this-the-emulator) keeps |
|
|
67
67
|
| `--webhook-url <url>` / `--webhook-secret <whsec_…>` | off | Deliver [signed webhooks](#webhooks) (secret also from `MOCKINGBIRD_JUNCTION_WEBHOOK_SECRET`) |
|
|
68
68
|
| `--webhook-retry-delays <ms,…>` | Svix's schedule | Delay before each delivery attempt, e.g. `0,1000,5000` in tests |
|
|
69
69
|
| `--webhook-scope <scope>` | — | Sent as `x-mockingbird-scope` on every delivery |
|
|
@@ -124,7 +124,7 @@ or a loaded corpus). The result has `url`, `port`, `runtime` and `close()`.
|
|
|
124
124
|
|
|
125
125
|
### `createRuntime` (any Fetch server)
|
|
126
126
|
|
|
127
|
-
`createRuntime` is the whole served
|
|
127
|
+
`createRuntime` is the whole served emulator — health, admin, namespaces, clock, faults, metrics — as a
|
|
128
128
|
single runtime-neutral `fetch(request)`. Hand it to `Bun.serve`, a Worker, or call it directly:
|
|
129
129
|
|
|
130
130
|
```ts
|
|
@@ -199,7 +199,7 @@ const order = await call("POST", "/v3/order", {
|
|
|
199
199
|
})
|
|
200
200
|
console.log(order.status, (order.json.order as { id: string }).id) // 200 "<uuid>"
|
|
201
201
|
|
|
202
|
-
// Every event the
|
|
202
|
+
// Every event the emulator published, oldest first:
|
|
203
203
|
console.log(junction.webhookEvents().map((event) => event.event_type)) // ["labtest.order.created"]
|
|
204
204
|
```
|
|
205
205
|
|
|
@@ -239,8 +239,8 @@ Every Mockingbird service answers the same control surface, outside the vendor's
|
|
|
239
239
|
through the admin API (lab accounts, limits, identity, geo) belongs to one namespace and survives
|
|
240
240
|
that namespace's `POST /__admin/reset`; data does not.
|
|
241
241
|
- `x-mockingbird: junction@<version>; ns=<namespace>` — on **every** response: vendor answers,
|
|
242
|
-
errors, faults, admin and health. Junction never sends it, so it tells the
|
|
243
|
-
(see [Is this the
|
|
242
|
+
errors, faults, admin and health. Junction never sends it, so it tells the emulator from the vendor
|
|
243
|
+
(see [Is this the emulator?](#is-this-the-emulator)).
|
|
244
244
|
|
|
245
245
|
| Route | Does |
|
|
246
246
|
| --- | --- |
|
|
@@ -270,7 +270,7 @@ Every Mockingbird service answers the same control surface, outside the vendor's
|
|
|
270
270
|
| `DELETE /__admin/users/{id}` | Remove a user outright, leaving no deletion tombstone |
|
|
271
271
|
| `POST /__admin/orders` | Insert an order, optionally already in a `status`, through `create_order`'s record builder |
|
|
272
272
|
| `POST /__admin/import` | `{ "users": [...], "orders": [...] }` in one call |
|
|
273
|
-
| `GET` / `DELETE /__admin/requests` | The namespace's [request journal](#is-this-the-
|
|
273
|
+
| `GET` / `DELETE /__admin/requests` | The namespace's [request journal](#is-this-the-emulator) (`?operationId=`, `?status=`, `?since=`, `?limit=`, `?all=1`) / clear it |
|
|
274
274
|
| `GET /__admin/corpus`, `PUT /__admin/geo` | The loaded corpus; switch [geo mode](#geo-corpus-or-synthetic) |
|
|
275
275
|
| `GET /__admin/webhooks` | [Deliveries](#webhooks) with every attempt |
|
|
276
276
|
| `POST /__admin/webhooks/{id}/replay`, `POST /__admin/webhooks/flush` | Redeliver one message; run pending retries now |
|
|
@@ -283,7 +283,7 @@ a new SDK call shows up — as a count — before it fails a suite as a 404.
|
|
|
283
283
|
|
|
284
284
|
Provider-owned inventory — area serviceability, PSC site lists, the lab catalog, labs, lab
|
|
285
285
|
accounts — cannot be synthesized faithfully. A corpus is an exact recording of those
|
|
286
|
-
parameter-stable reads, and the
|
|
286
|
+
parameter-stable reads, and the emulator answers them byte for byte.
|
|
287
287
|
|
|
288
288
|
**The shipped corpus** (`defaultCorpus`, and what `serve` loads unless told otherwise) was recorded
|
|
289
289
|
from the Junction sandbox. It covers area and PSC serviceability for 57 ZIPs across the US, the PSC
|
|
@@ -344,7 +344,7 @@ one active account for the lab is selected, several select the first listed, and
|
|
|
344
344
|
falls back to Junction's platform account. The billing type must be allowed in the patient's
|
|
345
345
|
state by the account's `allowed_billing`.
|
|
346
346
|
|
|
347
|
-
Two of Junction's documented rules are **not** enforced by the sandbox, so the
|
|
347
|
+
Two of Junction's documented rules are **not** enforced by the sandbox, so the emulator does not
|
|
348
348
|
enforce them either. An id naming another lab's account is accepted and the order is placed with
|
|
349
349
|
that account (the guide says it must be "associated with the lab selected for the order"):
|
|
350
350
|
recorded in `corpus/lab-account-probes.json`, where a Labcorp test ordered through Junction's
|
|
@@ -354,9 +354,9 @@ accounts are linked for the lab places the order (the guide says it "may be reje
|
|
|
354
354
|
live by a consumer's team ([#136](https://github.com/crvouga/mockingbird/issues/136)); the
|
|
355
355
|
sandbox team the parity run uses has one account per lab, so `verify --orders` checks it whenever
|
|
356
356
|
a corpus has such a lab. Which of the several accounts the sandbox bills through is not visible
|
|
357
|
-
from outside; the
|
|
357
|
+
from outside; the emulator uses the first listed.
|
|
358
358
|
|
|
359
|
-
Junction's order (`ClientFacingOrder`) has no `lab_account_id`, so neither does the
|
|
359
|
+
Junction's order (`ClientFacingOrder`) has no `lab_account_id`, so neither does the emulator's: not on
|
|
360
360
|
the create response, `GET /v3/order/{id}`, `GET /v3/orders` or webhooks. The account an order was
|
|
361
361
|
placed with is reported only by `GET /__admin/orders` and `instance().orderLabAccount(orderId)`.
|
|
362
362
|
|
|
@@ -455,7 +455,7 @@ works and keeps its own default id (`presetAccountId("bioreference_customer_mult
|
|
|
455
455
|
|
|
456
456
|
### Team identity
|
|
457
457
|
|
|
458
|
-
The
|
|
458
|
+
The emulator answers as one team: `team_id` on users, orders and webhooks, and the team that
|
|
459
459
|
`team_id_allowlist` is checked against. It is, in order: `teamId` / `--team-id`, the team a
|
|
460
460
|
version-2 corpus recorded (`corpus pull` reads it from a listed user, else from the accounts'
|
|
461
461
|
allowlists), else the fixed `MOCK_TEAM_ID`. `GET /__admin/team` reports it.
|
|
@@ -463,18 +463,18 @@ allowlists), else the fixed `MOCK_TEAM_ID`. `GET /__admin/team` reports it.
|
|
|
463
463
|
A version-2 corpus keeps each account's allowlist **verbatim**, so an account the real team is not
|
|
464
464
|
linked to answers `400 {"detail": "Lab account is not linked to your team"}` exactly as it does
|
|
465
465
|
live. A version-1 corpus (no `teamId`) still loads and behaves as 0.2.0 did: every recorded account
|
|
466
|
-
is also linked to the
|
|
466
|
+
is also linked to the emulator team.
|
|
467
467
|
|
|
468
468
|
**Empty allowlists.** Junction's own Quest, Labcorp and BioReference accounts carry
|
|
469
|
-
`team_id_allowlist: []`, and a real team's listing returns them, so the
|
|
469
|
+
`team_id_allowlist: []`, and a real team's listing returns them, so the emulator lists them and treats
|
|
470
470
|
them as linked. Ordering through one by explicit id, and with the id omitted when it is the lab's
|
|
471
471
|
only active account, places the order on the sandbox (`corpus/lab-account-probes.json`, recorded
|
|
472
|
-
by the parity run), as the
|
|
472
|
+
by the parity run), as the emulator does. `verify --orders` re-checks it whenever the corpus has such
|
|
473
473
|
an account.
|
|
474
474
|
|
|
475
475
|
## Sandbox limits
|
|
476
476
|
|
|
477
|
-
The
|
|
477
|
+
The emulator exists to escape the sandbox's restrictions, so it enforces none of them unless a test
|
|
478
478
|
asks — this is a tested guarantee (500 users in a loop all succeed), not an accident.
|
|
479
479
|
|
|
480
480
|
| Sandbox limit | Modelled | Default | Turn it on |
|
|
@@ -508,7 +508,7 @@ curl -X POST localhost:8787/__admin/import -d @test/junction-fixtures.json
|
|
|
508
508
|
user and lab test must exist (404 otherwise).
|
|
509
509
|
- Inserted records go through the same builders as `create_user` / `create_order`, so every read
|
|
510
510
|
path (`GET /v2/user/{id}`, resolve by `client_user_id`, `GET /v3/order/{id}`,
|
|
511
|
-
`GET /v3/orders?user_id=`) sees them as API-created. Default timestamps read the
|
|
511
|
+
`GET /v3/orders?user_id=`) sees them as API-created. Default timestamps read the emulator clock.
|
|
512
512
|
- **No webhook fires** unless the body has `"emitWebhooks": true`: fixtures should not trigger
|
|
513
513
|
backend side effects.
|
|
514
514
|
- `fixtures` / `--fixtures <file>` loads `{ "users": [...], "orders": [...] }` into every namespace
|
|
@@ -521,9 +521,9 @@ and the request proceeds. The journal marks the request `adopted: true`. **Order
|
|
|
521
521
|
adopted**: an unknown order id always 404s, because inventing an order hides real bugs. The default,
|
|
522
522
|
`strict`, is Junction's own behaviour.
|
|
523
523
|
|
|
524
|
-
## Is this the
|
|
524
|
+
## Is this the emulator?
|
|
525
525
|
|
|
526
|
-
|
|
526
|
+
An emulator 404 and a sandbox 404 are byte-identical, which is how a backend half-pointed at the sandbox
|
|
527
527
|
goes unnoticed. Three things make it visible:
|
|
528
528
|
|
|
529
529
|
- **`x-mockingbird` on every response.** Assert on it in a test helper:
|
|
@@ -531,12 +531,12 @@ goes unnoticed. Three things make it visible:
|
|
|
531
531
|
```ts
|
|
532
532
|
import { expect } from "vitest"
|
|
533
533
|
|
|
534
|
-
/** Wrap the fetch your Junction client uses; fails any call that did not reach the
|
|
534
|
+
/** Wrap the fetch your Junction client uses; fails any call that did not reach the emulator. */
|
|
535
535
|
export const mockOnlyFetch =
|
|
536
536
|
(inner: typeof fetch = fetch): typeof fetch =>
|
|
537
537
|
async (input, init) => {
|
|
538
538
|
const response = await inner(input, init)
|
|
539
|
-
expect(response.headers.get("x-mockingbird"), `${String(input)} did not reach the Junction
|
|
539
|
+
expect(response.headers.get("x-mockingbird"), `${String(input)} did not reach the Junction emulator`).toMatch(
|
|
540
540
|
/^junction@/,
|
|
541
541
|
)
|
|
542
542
|
return response
|
|
@@ -545,7 +545,7 @@ goes unnoticed. Three things make it visible:
|
|
|
545
545
|
|
|
546
546
|
- **The request journal.** Each namespace keeps its last 1000 requests (`--journal-size`,
|
|
547
547
|
`journalSize`): operation id, method, path, status, duration, fault id, the user / order /
|
|
548
|
-
lab-account ids it touched, and when (
|
|
548
|
+
lab-account ids it touched, and when (emulator clock). `GET /__admin/requests?operationId=create_order_v3_order_post`
|
|
549
549
|
proves an order was placed here; an empty answer proves it was not. Never bodies.
|
|
550
550
|
- **Miss headers on 404s.** A missing user or order keeps Junction's body byte for byte and adds
|
|
551
551
|
`x-mockingbird-miss: order <id>` (or `user <id>`, `user client:<client_user_id>`) and
|
|
@@ -592,7 +592,7 @@ delayed simulations (`?delay=<seconds>`) due and moves appointment windows, with
|
|
|
592
592
|
|
|
593
593
|
## Faults and error shapes
|
|
594
594
|
|
|
595
|
-
Error bodies the
|
|
595
|
+
Error bodies the emulator reproduces byte for byte, checked against the sandbox by `verify` and the
|
|
596
596
|
parity suite (`ORDER_NOT_FOUND` holds the unknown-order text per operation id):
|
|
597
597
|
|
|
598
598
|
| Case | Status | Body |
|
|
@@ -639,7 +639,7 @@ With `webhooks` / `--webhook-url`, every event is delivered signed, with retries
|
|
|
639
639
|
official `svix` verifier, and a receiver written for real Junction, accept it unchanged. (Signing
|
|
640
640
|
`"<timestamp>.<body>"` without the message id, as this package's own server script did before,
|
|
641
641
|
is not Svix-compatible.)
|
|
642
|
-
- Timestamps are wall-clock even when the
|
|
642
|
+
- Timestamps are wall-clock even when the emulator clock is moved, because receivers reject timestamps
|
|
643
643
|
outside a few minutes of their own clock.
|
|
644
644
|
- Any 2xx is delivered; anything else is retried on Svix's schedule (immediately, 5 s, 5 min,
|
|
645
645
|
30 min, 2 h, 5 h, 10 h, 10 h) or `retryDelaysMs`. `POST /__admin/webhooks/flush` runs pending
|
|
@@ -669,7 +669,7 @@ console.log(typeof accept, junction.webhooks?.deliveries().length) // "function"
|
|
|
669
669
|
|
|
670
670
|
## Verify
|
|
671
671
|
|
|
672
|
-
`verify` is the fidelity guarantee: it runs the same requests against real Junction and the
|
|
672
|
+
`verify` is the fidelity guarantee: it runs the same requests against real Junction and the emulator
|
|
673
673
|
and reports every divergence.
|
|
674
674
|
|
|
675
675
|
```bash
|
|
@@ -687,7 +687,7 @@ npx mockingbird-junction verify --real-key "$JUNCTION_SANDBOX_KEY" --orders --sa
|
|
|
687
687
|
bodies must match in shape, and byte for byte for the documented error bodies.
|
|
688
688
|
|
|
689
689
|
It exits 1 on any divergence. The scenario always deletes its user (and cancels its order), because
|
|
690
|
-
it runs against the same capped sandbox the
|
|
690
|
+
it runs against the same capped sandbox the emulator exists to relieve. `verifyAgainstReal` is the same
|
|
691
691
|
check as a function. This repo runs it in CI against the Junction sandbox.
|
|
692
692
|
|
|
693
693
|
## Determinism
|
|
@@ -700,7 +700,7 @@ availability, and which requests a partial-`rate` fault hits. Wall-clock by desi
|
|
|
700
700
|
|
|
701
701
|
## What is and is not modelled
|
|
702
702
|
|
|
703
|
-
|
|
703
|
+
An emulator that is silent about its gaps is how a green suite starts lying. Specifically:
|
|
704
704
|
|
|
705
705
|
- **Corpus-backed** (byte-exact): area and PSC serviceability for covered ZIPs; the catalog, labs,
|
|
706
706
|
expected results and lab accounts of the team the corpus was recorded from.
|
|
@@ -714,11 +714,11 @@ A mock that is silent about its gaps is how a green suite starts lying. Specific
|
|
|
714
714
|
- Rate limits and outages, except when injected as faults or switched on as
|
|
715
715
|
[limits](#sandbox-limits).
|
|
716
716
|
- Which of several active accounts for a lab the sandbox bills an order through when
|
|
717
|
-
`lab_account_id` is omitted (see [Lab accounts](#lab-accounts)); the
|
|
717
|
+
`lab_account_id` is omitted (see [Lab accounts](#lab-accounts)); the emulator uses the first listed.
|
|
718
718
|
- Adopted users (`adopt-users`) have `client_user_id` equal to their `user_id`; nothing in
|
|
719
719
|
Junction corresponds to adoption.
|
|
720
720
|
- Real 429 / 5xx bodies: the presets are plausible, not recorded.
|
|
721
|
-
- Phlebotomy availability breadth: the sandbox serves it only for `85004`; the
|
|
721
|
+
- Phlebotomy availability breadth: the sandbox serves it only for `85004`; the emulator generates slots
|
|
722
722
|
for any covered ZIP.
|
|
723
723
|
- Webhook retry jitter across a snapshot restore (the jitter stream is not part of a snapshot).
|
|
724
724
|
- Operations outside the vendored OpenAPI subset: they return 404 and are counted as
|
|
@@ -730,12 +730,12 @@ Main entry (`@crvouga/mockingbird-service-junction`, runtime-neutral):
|
|
|
730
730
|
|
|
731
731
|
| Export | Description |
|
|
732
732
|
| --- | --- |
|
|
733
|
-
| `createRuntime` | `(options?: JunctionRuntimeOptions) => JunctionRuntime` — the served
|
|
734
|
-
| `JunctionAPI` | Class. `new JunctionAPI(options?)`: one namespace's
|
|
733
|
+
| `createRuntime` | `(options?: JunctionRuntimeOptions) => JunctionRuntime` — the served emulator (health, admin, namespaces, clock, faults, metrics, journal, webhooks) as one `fetch`. Options: `corpus`, `geo`, `labAccounts`, `teamId`, `limits`, `identity`, `defaultBillingTypes`, `fixtures`, `journalSize`, `webhooks`, `onWebhook`, `sqlite`, `clock`, `seed`, `adminKey`, `onLog`. |
|
|
734
|
+
| `JunctionAPI` | Class. `new JunctionAPI(options?)`: one namespace's emulator, implementing `fetch(request: Request): Promise<Response>`. |
|
|
735
735
|
| `JUNCTION_NAMESPACE` | `"junction"` — the default namespace's storage key when sharing a `sqlite` client. |
|
|
736
736
|
| `document` | The vendored Junction OpenAPI document (Mockingbird subset) that drives routing. |
|
|
737
737
|
| `operationIds` | Every `operationId` in `document`. |
|
|
738
|
-
| `supportedOperationIds` | The `operationId`s the
|
|
738
|
+
| `supportedOperationIds` | The `operationId`s the emulator implements (all of them). |
|
|
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. |
|
|
@@ -744,7 +744,7 @@ Main entry (`@crvouga/mockingbird-service-junction`, runtime-neutral):
|
|
|
744
744
|
| `SEALED_CORPUS_VERSION` | Current corpus format version (`2`: adds `teamId`). |
|
|
745
745
|
| `SUPPORTED_SEALED_CORPUS_VERSIONS` | Versions `parseSealedCorpus` loads (`[1, 2]`). |
|
|
746
746
|
| `MOCK_TEAM_ID` | The team id used when neither `teamId` nor the corpus gives one. |
|
|
747
|
-
| `OTHER_TEAM_ID` | A team that is not the
|
|
747
|
+
| `OTHER_TEAM_ID` | A team that is not the emulator's, for fixtures modelling another team's account. |
|
|
748
748
|
| `isLinkedToTeam` | `(account, teamId) => boolean` — the allowlist rule (`[]` counts as linked). |
|
|
749
749
|
| `LAB_ACCOUNT_PRESETS` | The [lab-account presets](#lab-account-presets), without ids. |
|
|
750
750
|
| `LAB_ACCOUNT_PRESET_ALIASES` | Deprecated preset names → the preset each stands for (`bioreference_customer_multi_state` → `bioreference_platform`). |
|
|
@@ -875,9 +875,9 @@ For contributors to the mockingbird repo only.
|
|
|
875
875
|
```bash
|
|
876
876
|
bun test # offline suites, incl. scheduling state space
|
|
877
877
|
bun test junction.runtime.property.test.ts # service contract, corpus, lab accounts, faults, webhooks, verify
|
|
878
|
-
bun test junction.sdk.property.test.ts # drives the served
|
|
878
|
+
bun test junction.sdk.property.test.ts # drives the served emulator through @tryvital/vital-node
|
|
879
879
|
|
|
880
|
-
bun run
|
|
880
|
+
bun run emulator:serve # env-configured `serve`: HOST, PORT, MOCKINGBIRD_JUNCTION_CORPUS,
|
|
881
881
|
# MOCKINGBIRD_JUNCTION_WEBHOOK_URL / _SECRET / _SCOPE
|
|
882
882
|
bun run corpus:record -- --force # re-record the shipped corpus/sandbox-sealed.json (JUNCTION_API_KEY)
|
|
883
883
|
bun run verify -- --real-key "$KEY" # `mockingbird-junction verify` from source
|
|
@@ -898,7 +898,7 @@ Webhook parity needs a public receiver; see
|
|
|
898
898
|
|
|
899
899
|
A completion-target simulation on an active testkit advances through delivery and queues
|
|
900
900
|
completion for the next millisecond of the injected `now` clock. This is a deterministic
|
|
901
|
-
|
|
901
|
+
emulator scheduling boundary, not a claim about Junction's processing latency. Order, result,
|
|
902
902
|
transaction, and order-list reads apply due work to its owning order. A second simulation
|
|
903
903
|
is not required. Results remain unavailable while the testkit is `delivered_to_lab`.
|
|
904
904
|
Cancelled orders never complete from queued simulation work.
|
package/SUPPORT.md
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
Generated from `openapi.yaml`; do not edit by hand.
|
|
4
4
|
|
|
5
5
|
- operations in spec: **40**
|
|
6
|
-
- supported by the
|
|
6
|
+
- supported by the emulator: **40**
|
|
7
7
|
- parity enabled: **22**
|
|
8
8
|
|
|
9
|
-
| operationId | route |
|
|
9
|
+
| operationId | route | emulator | parity | notes |
|
|
10
10
|
| --- | --- | --- | --- | --- |
|
|
11
11
|
| `get_teams_users_v2_user_get` | `GET /v2/user` | ✅ supported | ✅ | |
|
|
12
12
|
| `create_user_v2_user_post` | `POST /v2/user` | ✅ supported | ✅ | |
|
|
@@ -17,31 +17,31 @@ Generated from `openapi.yaml`; do not edit by hand.
|
|
|
17
17
|
| `patch_user_info_v2_user__user_id__info_patch` | `PATCH /v2/user/{user_id}/info` | ✅ supported | ✅ | |
|
|
18
18
|
| `get_latest_user_info_user_v2_user__user_id__info_latest_get` | `GET /v2/user/{user_id}/info/latest` | ✅ supported | ✅ | |
|
|
19
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
|
|
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 emulator models the documented shape, filters and routing rules, not a live account inventory |
|
|
21
21
|
| `get_lab_tests_for_team_v3_lab_tests_get` | `GET /v3/lab_tests` | ✅ supported | ✅ | |
|
|
22
22
|
| `get_lab_test_for_team_v3_lab_tests__lab_test_id__get` | `GET /v3/lab_tests/{lab_test_id}` | ✅ supported | ✅ | |
|
|
23
23
|
| `get_labs_v3_lab_tests_labs_get` | `GET /v3/lab_tests/labs` | ✅ supported | ✅ | |
|
|
24
24
|
| `get_markers_for_lab_test_v3_lab_tests__lab_test_id__markers_get` | `GET /v3/lab_tests/{lab_test_id}/markers` | ✅ supported | ✅ | |
|
|
25
25
|
| `list_order_set_markers_v3_lab_tests_list_order_set_markers_post` | `POST /v3/lab_tests/list_order_set_markers` | ✅ supported | ✅ | |
|
|
26
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
|
|
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
|
|
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
|
|
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 an emulator 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 emulator 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 emulator-internal scheduling property suite instead |
|
|
30
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
|
|
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 emulator-internal scheduling property suite instead |
|
|
32
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 emulator-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 emulator-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 emulator-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 emulator-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 emulator-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 emulator-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 emulator-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 emulator-internal scheduling property suite instead |
|
|
41
41
|
| `get_order_v3_order__order_id__get` | `GET /v3/order/{order_id}` | ✅ supported | ✅ | |
|
|
42
42
|
| `cancel_order_v3_order__order_id__cancel_post` | `POST /v3/order/{order_id}/cancel` | ✅ supported | ✅ | |
|
|
43
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
|
|
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 emulator-internal results property suite instead |
|
|
45
45
|
| `get_result_metadata_v3_order__order_id__result_metadata_get` | `GET /v3/order/{order_id}/result/metadata` | ✅ supported | ✅ | |
|
|
46
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
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 |
|