@crvouga/mockingbird-service-junction 3.6.1 → 3.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.d.ts CHANGED
@@ -133,6 +133,12 @@ interface SqliteClient$2 {
133
133
  transaction<T>(fn: () => T): T;
134
134
  }
135
135
 
136
+ /**
137
+ * What names an id base: a non-negative safe integer (or its decimal string) or `"boot"`,
138
+ * which derives the base from the wall clock when the runtime is created.
139
+ */
140
+ type IdBase$1 = number | string;
141
+
136
142
  /**
137
143
  * The single source of time for a service.
138
144
  *
@@ -215,6 +221,15 @@ type FaultRule$1 = {
215
221
  requestHeaders?: Record<string, string>;
216
222
  /** Fault only requests carrying these query parameters. `"*"` matches any value. */
217
223
  query?: Record<string, string>;
224
+ /**
225
+ * Fault only requests whose JSON body carries these fields. Each key is a dotted path into
226
+ * the parsed body (`"patient_details.email"`; a number steps into an array, `"items.0.sku"`)
227
+ * and each value is what the field must equal: a string, number, boolean or `null`, compared
228
+ * strictly (`3` is not `"3"`). `"*"` matches any value that is present. A request whose body
229
+ * is missing, is not JSON, or is not a JSON object never matches. Not `body`, which is the
230
+ * response a rule injects.
231
+ */
232
+ requestBody?: Record<string, RequestBodyValue$1>;
218
233
  /**
219
234
  * Fault only this namespace. Omit (or `"*"`) to fault every namespace — which is what
220
235
  * an in-process caller usually wants, and what a parallel worker usually does not:
@@ -281,6 +296,8 @@ type FaultRule$1 = {
281
296
  /** The preset this rule was expanded from, if any. */
282
297
  fromPreset?: string;
283
298
  };
299
+ /** What a field of the request body must equal in {@link FaultRule.requestBody}. */
300
+ type RequestBodyValue$1 = string | number | boolean | null;
284
301
  /** A fault that fired for one request. */
285
302
  type FaultHit$1 = {
286
303
  id: string;
@@ -305,6 +322,11 @@ type FaultCandidate$1 = {
305
322
  /** Request headers and query, for rules that match on them. */
306
323
  headers?: Headers;
307
324
  query?: URLSearchParams;
325
+ /**
326
+ * The request body parsed as JSON, read only when a rule matches on `requestBody`. Resolve
327
+ * `undefined` for a body that is missing or not JSON. It must leave the request readable.
328
+ */
329
+ readJson?: () => Promise<unknown>;
308
330
  /** The namespace clock, for `from` / `until`. Rules with a window are skipped without it. */
309
331
  now?: number;
310
332
  /** How to spend a delay for this request. Default: the registry's own sleep. */
@@ -827,6 +849,12 @@ type ServiceRuntime$1<T extends ServiceInstance$1> = FetchAPI$2 & {
827
849
  mount(prefix: string): MountedAPI$1;
828
850
  readonly sqlite: SqliteClient$2;
829
851
  readonly clock: Clock$1;
852
+ /**
853
+ * Change the id base ({@link RuntimeOptions.idBase}) for ids generated from now on, and
854
+ * return the number it resolved to. Set it before the first request so a boot's ids stay
855
+ * one run.
856
+ */
857
+ setIdBase(base: IdBase$1): number;
830
858
  readonly faults: FaultRegistry$1;
831
859
  /** Baseline response time per namespace. */
832
860
  readonly latency: LatencyRegistry$1;
@@ -932,6 +960,12 @@ type CommonServeOptions = {
932
960
  /** Synthetic provider fixture objects supplied by a fleet entry. */
933
961
  fixtures?: Record<string, unknown>;
934
962
  baseUrl?: string;
963
+ /**
964
+ * Boot settings from `--settings`, `MOCKINGBIRD_SETTINGS` or a fleet entry's `settings`,
965
+ * already checked by the target's {@link ServeTarget.parseSettings}. Pass them to the
966
+ * service's own `settings` option so they become every namespace's defaults.
967
+ */
968
+ settings?: Record<string, unknown>;
935
969
  };
936
970
  /**
937
971
  * What a service contributes to `serve`: how to build its runtime from CLI flags,
@@ -944,6 +978,13 @@ type ServeTarget = {
944
978
  defaultPort: number;
945
979
  /** Serve flags beyond the common ones. */
946
980
  options?: Record<string, CliOption>;
981
+ /**
982
+ * Check the boot settings a caller supplied (`--settings`, `MOCKINGBIRD_SETTINGS`, a fleet
983
+ * entry's `settings`) against the service's settings schema, returning them normalized
984
+ * or throwing a message naming the bad field. A target without one takes no boot settings,
985
+ * and supplying some is refused before a port is bound.
986
+ */
987
+ parseSettings?(settings: Record<string, unknown>): Record<string, unknown>;
947
988
  create(values: CliValues, common: CommonServeOptions): Promise<ServiceRuntime$1<ServiceInstance$1>> | ServiceRuntime$1<ServiceInstance$1>;
948
989
  /** Startup lines after the listen address, e.g. the loaded corpus version. */
949
990
  banner?(runtime: ServiceRuntime$1<ServiceInstance$1>): string[];
@@ -1083,6 +1124,12 @@ interface SqliteClient$1 {
1083
1124
  transaction<T>(fn: () => T): T;
1084
1125
  }
1085
1126
 
1127
+ /**
1128
+ * What names an id base: a non-negative safe integer (or its decimal string) or `"boot"`,
1129
+ * which derives the base from the wall clock when the runtime is created.
1130
+ */
1131
+ type IdBase = number | string;
1132
+
1086
1133
  /** Options every provider constructor accepts. */
1087
1134
  type APIOptions = {
1088
1135
  /** Sync SQLite client. Defaults to `@crvouga/mockingbird-service-sqlite`. */
@@ -1178,6 +1225,15 @@ type FaultRule = {
1178
1225
  requestHeaders?: Record<string, string>;
1179
1226
  /** Fault only requests carrying these query parameters. `"*"` matches any value. */
1180
1227
  query?: Record<string, string>;
1228
+ /**
1229
+ * Fault only requests whose JSON body carries these fields. Each key is a dotted path into
1230
+ * the parsed body (`"patient_details.email"`; a number steps into an array, `"items.0.sku"`)
1231
+ * and each value is what the field must equal: a string, number, boolean or `null`, compared
1232
+ * strictly (`3` is not `"3"`). `"*"` matches any value that is present. A request whose body
1233
+ * is missing, is not JSON, or is not a JSON object never matches. Not `body`, which is the
1234
+ * response a rule injects.
1235
+ */
1236
+ requestBody?: Record<string, RequestBodyValue>;
1181
1237
  /**
1182
1238
  * Fault only this namespace. Omit (or `"*"`) to fault every namespace — which is what
1183
1239
  * an in-process caller usually wants, and what a parallel worker usually does not:
@@ -1244,6 +1300,8 @@ type FaultRule = {
1244
1300
  /** The preset this rule was expanded from, if any. */
1245
1301
  fromPreset?: string;
1246
1302
  };
1303
+ /** What a field of the request body must equal in {@link FaultRule.requestBody}. */
1304
+ type RequestBodyValue = string | number | boolean | null;
1247
1305
  /** A fault that fired for one request. */
1248
1306
  type FaultHit = {
1249
1307
  id: string;
@@ -1268,6 +1326,11 @@ type FaultCandidate = {
1268
1326
  /** Request headers and query, for rules that match on them. */
1269
1327
  headers?: Headers;
1270
1328
  query?: URLSearchParams;
1329
+ /**
1330
+ * The request body parsed as JSON, read only when a rule matches on `requestBody`. Resolve
1331
+ * `undefined` for a body that is missing or not JSON. It must leave the request readable.
1332
+ */
1333
+ readJson?: () => Promise<unknown>;
1271
1334
  /** The namespace clock, for `from` / `until`. Rules with a window are skipped without it. */
1272
1335
  now?: number;
1273
1336
  /** How to spend a delay for this request. Default: the registry's own sleep. */
@@ -1790,6 +1853,12 @@ type ServiceRuntime<T extends ServiceInstance> = FetchAPI$1 & {
1790
1853
  mount(prefix: string): MountedAPI;
1791
1854
  readonly sqlite: SqliteClient$1;
1792
1855
  readonly clock: Clock;
1856
+ /**
1857
+ * Change the id base ({@link RuntimeOptions.idBase}) for ids generated from now on, and
1858
+ * return the number it resolved to. Set it before the first request so a boot's ids stay
1859
+ * one run.
1860
+ */
1861
+ setIdBase(base: IdBase): number;
1793
1862
  readonly faults: FaultRegistry;
1794
1863
  /** Baseline response time per namespace. */
1795
1864
  readonly latency: LatencyRegistry;
@@ -1897,48 +1966,6 @@ interface SqliteClient {
1897
1966
  transaction<T>(fn: () => T): T;
1898
1967
  }
1899
1968
 
1900
- type LabAccountStatus = "active" | "pending" | "suspended" | "ready_to_launch";
1901
- type LabAccountDelegatedFlow = "order_delegated" | "result_delegated" | "fully_delegated" | "not_delegated";
1902
- /** `billing_type` values the vendored create-order body accepts. */
1903
- declare const BILLING_TYPES: readonly ["client_bill", "commercial_insurance", "patient_bill_passthrough", "patient_bill", "upfront_payment"];
1904
- type BillingType = (typeof BILLING_TYPES)[number];
1905
- type LabAccountOmissionPolicy = "platform" | "reject";
1906
- /**
1907
- * A lab account as a consumer configures it. Mirrors `ClientFacingLabAccount`, with
1908
- * every field but `id` and `lab` optional, plus a `states` shorthand for the common
1909
- * case of an account that client-bills in a fixed set of states.
1910
- */
1911
- type LabAccountInput = {
1912
- id: string;
1913
- /** Lab slug, e.g. `"quest"`, `"labcorp"`, `"bioreference"`. */
1914
- lab: string;
1915
- status?: LabAccountStatus;
1916
- delegated_flow?: LabAccountDelegatedFlow;
1917
- account_name?: string | null;
1918
- provider_account_id?: string;
1919
- org_id?: string | null;
1920
- business_units?: string[] | null;
1921
- default_clinical_notes?: string | null;
1922
- /** Billing type → states it is allowed in. Takes precedence over `states`. */
1923
- allowed_billing?: Record<string, readonly string[]>;
1924
- /** Shorthand for `allowed_billing: { client_bill: states }`. Default: every state. */
1925
- states?: readonly string[];
1926
- /** Teams the account is linked to. Default: the configured team, so it is selectable. */
1927
- team_id_allowlist?: readonly string[];
1928
- };
1929
-
1930
- type LabAccountProfile = "native" | "expected-contract" | "sandbox-observed";
1931
- type LabAccountSandboxPolicy = {
1932
- /** Explicit billing refusals observed for this particular fixture/account. */
1933
- rejectBilling?: Partial<Record<BillingType, string>>;
1934
- /** Explicit billing/state exceptions observed for this particular fixture/account. */
1935
- allowBilling?: Partial<Record<BillingType, readonly string[]>>;
1936
- };
1937
- type LabAccountBehavior = {
1938
- profile: LabAccountProfile;
1939
- accounts: Record<string, LabAccountSandboxPolicy>;
1940
- };
1941
-
1942
1969
  /** Lab-test catalog mirrored from the Junction sandbox (`GET /v3/lab_test`). */
1943
1970
  type CatalogMarker = {
1944
1971
  id: number;
@@ -1991,6 +2018,204 @@ type LabTestRecord = {
1991
2018
  worst_case_tat_days: number | null;
1992
2019
  };
1993
2020
 
2021
+ /**
2022
+ * A-la-carte markers and order-set pricing.
2023
+ *
2024
+ * - `GET /v3/lab_tests/markers`: the markers a team can order one by one.
2025
+ * https://docs.junction.com/api-reference/lab-testing/biomarkers
2026
+ * - `POST /v3/lab_test/estimate_order_set_pricing`: what an order set costs.
2027
+ * https://docs.junction.com/api-reference/lab-testing/estimate-order-set-pricing
2028
+ *
2029
+ * Both follow the published contract. Nothing here is checked against the live sandbox (prices
2030
+ * are contract-owned), so the emulator prices from the catalog it holds: a lab test's `price`
2031
+ * and a marker's `price`, or the `pricing` of a configured {@link MarkerCatalogEntry}.
2032
+ */
2033
+
2034
+ /** Pricing the way Junction states it: minor units, or why it is not stated. */
2035
+ type MarkerPricing = {
2036
+ base_amount_minor: number;
2037
+ modifiers?: readonly Record<string, unknown>[] | null;
2038
+ } | {
2039
+ unspecified: "refer_to_contract" | "price_unavailable";
2040
+ };
2041
+ /**
2042
+ * A marker the mock offers on top of (or in place of) the ones embedded in catalog lab tests:
2043
+ * `createRuntime({ markerCatalog: [...] })`. Fields not given take the vendor's defaults.
2044
+ */
2045
+ type MarkerCatalogEntry = {
2046
+ id: number;
2047
+ name: string;
2048
+ slug?: string;
2049
+ description?: string | null;
2050
+ lab_id?: number | null;
2051
+ provider_id?: string | null;
2052
+ type?: "biomarker" | "panel" | null;
2053
+ unit?: string | null;
2054
+ /** Dollars, as the vendor prints them (`"12.50"`); a number is formatted to two decimals. */
2055
+ price?: string | number | null;
2056
+ /** Stated pricing, when `price` cannot say it (modifiers, `refer_to_contract`). */
2057
+ pricing?: MarkerPricing;
2058
+ /** Ask-on-order questions: `{ questions: [...] }`. */
2059
+ aoe?: unknown;
2060
+ /** Default `false`, as at the vendor. */
2061
+ a_la_carte_enabled?: boolean;
2062
+ common_tat_days?: number | null;
2063
+ worst_case_tat_days?: number | null;
2064
+ is_orderable?: boolean | null;
2065
+ /** What the marker reports. Default: none. */
2066
+ expected_results?: readonly ExpectedResult[];
2067
+ components?: readonly MarkerCatalogEntry[] | null;
2068
+ };
2069
+
2070
+ /**
2071
+ * ZIP overlays: aliases and per-ZIP overrides on top of whatever geo mode answers.
2072
+ *
2073
+ * `createRuntime({ zipOverlays: { aliases: { "07105": "85004" }, overrides: { "07105": {
2074
+ * phlebotomy_served: true, no_pscs: true } } } })`. An alias makes one ZIP answer as another
2075
+ * (coverage, recordings and the synthetic model all use the target); an override then edits the
2076
+ * answer for a ZIP: `phlebotomy.is_served` on `area/info`, and an empty PSC list.
2077
+ */
2078
+
2079
+ type ZipOverride = {
2080
+ /** `phlebotomy.is_served` on `GET /v3/order/area/info` (and its `providers`). */
2081
+ phlebotomy_served?: boolean;
2082
+ /** No patient service centers: `psc/info` lists none and `area/info` counts none. */
2083
+ no_pscs?: boolean;
2084
+ };
2085
+ type ZipOverlays = {
2086
+ /** ZIP → the ZIP it answers as. */
2087
+ aliases?: Record<string, string>;
2088
+ /** ZIP → what to change in its answers. Looked up by the requested ZIP, then by its alias. */
2089
+ overrides?: Record<string, ZipOverride>;
2090
+ };
2091
+
2092
+ type LabAccountStatus = "active" | "pending" | "suspended" | "ready_to_launch";
2093
+ type LabAccountDelegatedFlow = "order_delegated" | "result_delegated" | "fully_delegated" | "not_delegated";
2094
+ /** `billing_type` values the vendored create-order body accepts. */
2095
+ declare const BILLING_TYPES: readonly ["client_bill", "commercial_insurance", "patient_bill_passthrough", "patient_bill", "upfront_payment"];
2096
+ type BillingType = (typeof BILLING_TYPES)[number];
2097
+ type LabAccountOmissionPolicy = "platform" | "reject";
2098
+ /**
2099
+ * A lab account as a consumer configures it. Mirrors `ClientFacingLabAccount`, with
2100
+ * every field but `id` and `lab` optional, plus a `states` shorthand for the common
2101
+ * case of an account that client-bills in a fixed set of states.
2102
+ */
2103
+ type LabAccountInput = {
2104
+ id: string;
2105
+ /** Lab slug, e.g. `"quest"`, `"labcorp"`, `"bioreference"`. */
2106
+ lab: string;
2107
+ status?: LabAccountStatus;
2108
+ delegated_flow?: LabAccountDelegatedFlow;
2109
+ account_name?: string | null;
2110
+ provider_account_id?: string;
2111
+ org_id?: string | null;
2112
+ business_units?: string[] | null;
2113
+ default_clinical_notes?: string | null;
2114
+ /** Billing type → states it is allowed in. Takes precedence over `states`. */
2115
+ allowed_billing?: Record<string, readonly string[]>;
2116
+ /** Shorthand for `allowed_billing: { client_bill: states }`. Default: every state. */
2117
+ states?: readonly string[];
2118
+ /** Teams the account is linked to. Default: the configured team, so it is selectable. */
2119
+ team_id_allowlist?: readonly string[];
2120
+ };
2121
+
2122
+ type LabAccountProfile = "native" | "expected-contract" | "sandbox-observed" | "observed";
2123
+ /** Which vendor environment an `observed` configuration reproduces. */
2124
+ type LabAccountOracle = "sandbox" | "production";
2125
+ /**
2126
+ * How an order that omits `lab_account_id` and resolves to a Junction-owned (`org_id: null`)
2127
+ * account treats that account's listed `allowed_billing`: `listed` (default) enforces it,
2128
+ * `unchecked` skips the billing/state check (#467). Explicit account selection is unaffected.
2129
+ */
2130
+ type OmittedAccountBilling = "listed" | "unchecked";
2131
+ type LabAccountSandboxPolicy = {
2132
+ /** Explicit billing refusals observed for this particular fixture/account. */
2133
+ rejectBilling?: Partial<Record<BillingType, string>>;
2134
+ /** Explicit billing/state exceptions observed for this particular fixture/account. */
2135
+ allowBilling?: Partial<Record<BillingType, readonly string[]>>;
2136
+ };
2137
+ type LabAccountBehavior = {
2138
+ profile: LabAccountProfile;
2139
+ /**
2140
+ * The oracle the observations reproduce. `sandbox-observed` is the alias of `observed`
2141
+ * with `oracle: "sandbox"`; `native` and `expected-contract` have none.
2142
+ */
2143
+ oracle?: LabAccountOracle;
2144
+ accounts: Record<string, LabAccountSandboxPolicy>;
2145
+ /** Lab slug → omitted-account billing policy; unlisted labs are `listed`. */
2146
+ omittedAccountBilling?: Record<string, OmittedAccountBilling>;
2147
+ };
2148
+
2149
+ /**
2150
+ * Opt-in sandbox quirks: behaviors the vendor sandbox shows that a well-behaved client must
2151
+ * tolerate. Every quirk is off by default, so no existing suite changes.
2152
+ */
2153
+ type JunctionQuirks = {
2154
+ /**
2155
+ * #474: a `POST /v3/order/{id}/cancel` that lands in the same wall-clock second as the
2156
+ * order's creation records its `cancelled.<method>.cancelled` event, but the order's
2157
+ * `status`, `last_event` and `updated_at` do not move; a second cancel is a no-op. Reported
2158
+ * from the sandbox (production unverified).
2159
+ */
2160
+ sameSecondCancelStatus?: boolean;
2161
+ };
2162
+
2163
+ /**
2164
+ * The test backdoor: users and orders put straight into a namespace, with ids a suite
2165
+ * chooses — the Junction `user_id`s a database fixture already carries, or an order
2166
+ * already in some status — plus the lenient identity mode that adopts unknown users.
2167
+ *
2168
+ * Everything inserted here goes through the records `create_user` and `create_order`
2169
+ * build, so no read path can tell a fixture from an API-created resource.
2170
+ */
2171
+
2172
+ /** How requests referring to a user the namespace does not hold are answered. */
2173
+ type IdentityMode = "strict" | "adopt-users";
2174
+ type UserFixture = {
2175
+ /** Default: a fresh id, as `create_user` would mint. */
2176
+ user_id?: string;
2177
+ client_user_id: string;
2178
+ /** ISO-8601. Default: the mock clock's now. */
2179
+ created_on?: string;
2180
+ /** An IANA zone, or the full `{ id, source_slug, updated_at }` object. */
2181
+ fallback_time_zone?: string | UserRecord["fallback_time_zone"];
2182
+ /** `YYYY-MM-DD`, or the full `{ value, source_slug, updated_at }` object. */
2183
+ fallback_birth_date?: string | UserRecord["fallback_birth_date"];
2184
+ ingestion_start?: string | null;
2185
+ ingestion_end?: string | null;
2186
+ };
2187
+ type OrderFixture = {
2188
+ /** Default: a fresh id, as `create_order` would mint. */
2189
+ order_id?: string;
2190
+ user_id: string;
2191
+ lab_test_id: string;
2192
+ lab_account_id?: string;
2193
+ /** A transition target (`completed`, `at_lab`, or a full status). Default: just ordered. */
2194
+ status?: string;
2195
+ /** Default: the lab test's own method. */
2196
+ collection_method?: string;
2197
+ patient_details?: Record<string, unknown>;
2198
+ patient_address?: Record<string, unknown>;
2199
+ billing_type?: string;
2200
+ icd_codes?: string[] | null;
2201
+ passthrough?: string | null;
2202
+ clinical_notes?: string | null;
2203
+ /** ISO-8601. Default: the mock clock's now. */
2204
+ created_at?: string;
2205
+ /** Results served for the order, as `PUT /__admin/results/{id}` takes them. */
2206
+ result_fixture?: Omit<ResultFixture, "name"> & {
2207
+ name?: string;
2208
+ };
2209
+ };
2210
+ type JunctionFixtures = {
2211
+ users?: readonly UserFixture[];
2212
+ orders?: readonly OrderFixture[];
2213
+ };
2214
+ type InsertOptions = {
2215
+ /** Publish the webhooks the equivalent API calls would. Default `false`. */
2216
+ emitWebhooks?: boolean;
2217
+ };
2218
+
1994
2219
  type JunctionLimits = {
1995
2220
  /**
1996
2221
  * Live users a team may hold; creating one more answers the sandbox's
@@ -2139,8 +2364,10 @@ type ResultFixture = {
2139
2364
  * - `synthetic`: invent plausible coverage. Right for property tests that walk random ZIPs.
2140
2365
  * - `corpus`: refuse with a documented Mockingbird error. Right for a mock standing in for
2141
2366
  * the vendor, where invented coverage would silently disagree with production.
2367
+ * - `corpus+synthetic`: replay the recording for the ZIPs it covers (a read it cannot answer
2368
+ * still refuses), and invent coverage for every other ZIP.
2142
2369
  */
2143
- type GeoMode = "synthetic" | "corpus";
2370
+ type GeoMode = "synthetic" | "corpus" | "corpus+synthetic";
2144
2371
  type WebhookPublisher = (event: JunctionWebhookEvent) => void;
2145
2372
  type JunctionWebhookOptions = {
2146
2373
  seed?: number;
@@ -2148,60 +2375,27 @@ type JunctionWebhookOptions = {
2148
2375
  timeoutMs?: number;
2149
2376
  };
2150
2377
 
2151
- /**
2152
- * The test backdoor: users and orders put straight into a namespace, with ids a suite
2153
- * chooses — the Junction `user_id`s a database fixture already carries, or an order
2154
- * already in some status — plus the lenient identity mode that adopts unknown users.
2155
- *
2156
- * Everything inserted here goes through the records `create_user` and `create_order`
2157
- * build, so no read path can tell a fixture from an API-created resource.
2158
- */
2159
-
2160
- /** How requests referring to a user the namespace does not hold are answered. */
2161
- type IdentityMode = "strict" | "adopt-users";
2162
- type UserFixture = {
2163
- /** Default: a fresh id, as `create_user` would mint. */
2164
- user_id?: string;
2165
- client_user_id: string;
2166
- /** ISO-8601. Default: the mock clock's now. */
2167
- created_on?: string;
2168
- /** An IANA zone, or the full `{ id, source_slug, updated_at }` object. */
2169
- fallback_time_zone?: string | UserRecord["fallback_time_zone"];
2170
- /** `YYYY-MM-DD`, or the full `{ value, source_slug, updated_at }` object. */
2171
- fallback_birth_date?: string | UserRecord["fallback_birth_date"];
2172
- ingestion_start?: string | null;
2173
- ingestion_end?: string | null;
2174
- };
2175
- type OrderFixture = {
2176
- /** Default: a fresh id, as `create_order` would mint. */
2177
- order_id?: string;
2178
- user_id: string;
2179
- lab_test_id: string;
2180
- lab_account_id?: string;
2181
- /** A transition target (`completed`, `at_lab`, or a full status). Default: just ordered. */
2378
+ type CatalogOverlay = {
2379
+ /** The lab test to clone, by id or slug. It must be in the catalog the namespace boots with. */
2380
+ from: string;
2381
+ /** Id of the new lab test (a UUID, as `create_order` expects). */
2382
+ id: string;
2383
+ name?: string;
2384
+ slug?: string;
2385
+ /**
2386
+ * Move the clone to a lab: the slug of a lab the catalog lists, or a lab record
2387
+ * (`{ id, slug, name, ... }`), which is added to `GET /v3/lab_tests/labs` when new.
2388
+ * The clone's markers and expected results take that lab's id.
2389
+ */
2390
+ lab?: string | Record<string, unknown>;
2391
+ /** Drop the ask-on-order questions from every marker of the clone. */
2392
+ stripAoe?: boolean;
2393
+ /** Set `auto_generated` on the clone. Default: as the source. */
2394
+ autoGenerated?: boolean;
2395
+ method?: string;
2396
+ /** Dollars. */
2397
+ price?: number;
2182
2398
  status?: string;
2183
- /** Default: the lab test's own method. */
2184
- collection_method?: string;
2185
- patient_details?: Record<string, unknown>;
2186
- patient_address?: Record<string, unknown>;
2187
- billing_type?: string;
2188
- icd_codes?: string[] | null;
2189
- passthrough?: string | null;
2190
- clinical_notes?: string | null;
2191
- /** ISO-8601. Default: the mock clock's now. */
2192
- created_at?: string;
2193
- /** Results served for the order, as `PUT /__admin/results/{id}` takes them. */
2194
- result_fixture?: Omit<ResultFixture, "name"> & {
2195
- name?: string;
2196
- };
2197
- };
2198
- type JunctionFixtures = {
2199
- users?: readonly UserFixture[];
2200
- orders?: readonly OrderFixture[];
2201
- };
2202
- type InsertOptions = {
2203
- /** Publish the webhooks the equivalent API calls would. Default `false`. */
2204
- emitWebhooks?: boolean;
2205
2399
  };
2206
2400
 
2207
2401
  /**
@@ -2223,6 +2417,13 @@ interface FetchAPI {
2223
2417
  * NY/NJ client-bill shape a consumer asked for, kept because suites depend on it, and
2224
2418
  * listed in `SYNTHETIC_LAB_ACCOUNT_PRESETS`.
2225
2419
  *
2420
+ * The 2026-09-21 `bioreference_platform` preset lists `client_bill` in 47 states, but the
2421
+ * current house BioReference account lists only `patient_bill_passthrough` in NJ and NY, so
2422
+ * treat it as illustrative (#475). The `bioreference_current_platform`,
2423
+ * `quest_sandbox_platform` and `sonora_quest_production_platform` presets follow the listings
2424
+ * an agent reported from `GET /v3/lab_test/lab_account` on 2026-10-18 (a consumer-audit
2425
+ * report, not a repository probe); they are additions, so no existing preset changes.
2426
+ *
2226
2427
  * `*_platform` presets are Junction's own accounts (`org_id: null`, allowlist `[]`); every
2227
2428
  * other active preset is customer-owned (it belongs to an Org and is linked to the team).
2228
2429
  */
@@ -2364,6 +2565,27 @@ type JunctionAPIOptions = APIOptions & {
2364
2565
  * when a corpus is given (refuse, loudly), otherwise `synthetic` (invent coverage).
2365
2566
  */
2366
2567
  geo?: GeoMode;
2568
+ /**
2569
+ * ZIP aliases and per-ZIP overrides on serviceability answers, whatever the geo mode: an
2570
+ * alias makes a ZIP answer as another, an override sets `phlebotomy.is_served` or empties the
2571
+ * PSC list. Per namespace via `PUT /__admin/geo`.
2572
+ */
2573
+ zipOverlays?: ZipOverlays;
2574
+ /**
2575
+ * Lab tests derived from catalog ones (new id, name, slug, lab; AOE questions stripped;
2576
+ * `auto_generated`), added to every namespace after the catalog loads and again on `reset()`.
2577
+ */
2578
+ catalogOverlays?: readonly CatalogOverlay[];
2579
+ /**
2580
+ * Markers `GET /v3/lab_tests/markers` offers on top of those in catalog lab tests, with their
2581
+ * pricing, AOE questions and expected results.
2582
+ */
2583
+ markerCatalog?: readonly MarkerCatalogEntry[];
2584
+ /**
2585
+ * Name the markers behind each biomarker result line of an add-on order
2586
+ * (`source_markers[].marker_id`). Default off: the line then carries `source_markers: null`.
2587
+ */
2588
+ addOnSourceMarkers?: boolean;
2367
2589
  /**
2368
2590
  * The team's lab accounts, replacing the built-in fixtures (and any from the corpus):
2369
2591
  * a list of accounts, or `{ presets: [...], accounts: [...] }`. `create_order` routes,
@@ -2389,6 +2611,8 @@ type JunctionAPIOptions = APIOptions & {
2389
2611
  labAccountOmissionPolicies?: Record<string, LabAccountOmissionPolicy>;
2390
2612
  /** Named policy; native preserves legacy behavior. Sandbox exceptions are account-owned. */
2391
2613
  labAccountBehavior?: Partial<LabAccountBehavior>;
2614
+ /** Opt-in sandbox quirks (#474), every one off by default; see {@link JunctionQuirks}. */
2615
+ quirks?: JunctionQuirks;
2392
2616
  /** Users and orders to load into every namespace, re-applied on every `reset()`. */
2393
2617
  fixtures?: JunctionFixtures;
2394
2618
  };
@@ -2415,6 +2639,7 @@ declare class JunctionAPI implements FetchAPI {
2415
2639
  private readonly rateWindow;
2416
2640
  private corpus;
2417
2641
  private labAccountConfig;
2642
+ private readonly catalogOverlays;
2418
2643
  constructor(options?: JunctionAPIOptions);
2419
2644
  fetch(request: Request): Promise<Response>;
2420
2645
  reset(): Promise<void>;
@@ -2456,6 +2681,9 @@ declare class JunctionAPI implements FetchAPI {
2456
2681
  /** Effective account policy for this namespace; kept across reset. */
2457
2682
  get labAccountBehavior(): LabAccountBehavior;
2458
2683
  set labAccountBehavior(input: LabAccountBehavior);
2684
+ /** Opt-in sandbox quirks for this namespace; kept across reset. */
2685
+ get quirks(): JunctionQuirks;
2686
+ set quirks(input: JunctionQuirks);
2459
2687
  get defaultBillingTypes(): Record<string, BillingType>;
2460
2688
  /** Replace the per-lab default billing types (`{}` restores `client_bill` everywhere). */
2461
2689
  set defaultBillingTypes(input: Partial<Record<string, BillingType>>);
@@ -2473,6 +2701,9 @@ declare class JunctionAPI implements FetchAPI {
2473
2701
  orders: OrderRecord[];
2474
2702
  };
2475
2703
  corpusInfo(): CorpusInfo | undefined;
2704
+ /** ZIP aliases and overrides for this namespace; kept across reset. */
2705
+ get zipOverlays(): ZipOverlays;
2706
+ set zipOverlays(overlays: ZipOverlays);
2476
2707
  get geoMode(): GeoMode;
2477
2708
  set geoMode(mode: GeoMode);
2478
2709
  order(id: string): OrderRecord | undefined;
@@ -2483,6 +2714,16 @@ declare class JunctionAPI implements FetchAPI {
2483
2714
  * only place the mock reports it.
2484
2715
  */
2485
2716
  orderLabAccount(id: string): string | null | undefined;
2717
+ /**
2718
+ * Where `POST /v3/order` carried a lab account id: `labAccountId` at the root (which
2719
+ * selects the account) and `nestedLabAccountId` inside `order_set` (which Junction
2720
+ * ignores). `null` for an order that was not placed through the API (a fixture), and
2721
+ * `undefined` for an unknown order.
2722
+ */
2723
+ orderLabAccountRequest(id: string): {
2724
+ labAccountId: string | null;
2725
+ nestedLabAccountId: string | null;
2726
+ } | null | undefined;
2486
2727
  /** Frozen provider number used by the synthetic requisition; null means unknown. */
2487
2728
  requisitionFixture(id: string): {
2488
2729
  provider_account_id: string | null;
@@ -2516,11 +2757,21 @@ type JunctionRuntimeOptions = {
2516
2757
  corpus?: SealedCorpus;
2517
2758
  /** Default: `corpus` when a corpus is loaded, otherwise `synthetic`. */
2518
2759
  geo?: GeoMode;
2760
+ /** ZIP aliases and per-ZIP overrides on serviceability answers; see {@link JunctionAPIOptions.zipOverlays}. */
2761
+ zipOverlays?: ZipOverlays;
2762
+ /** Lab tests derived from catalog ones at boot; see {@link JunctionAPIOptions.catalogOverlays}. */
2763
+ catalogOverlays?: readonly CatalogOverlay[];
2764
+ /** Markers `GET /v3/lab_tests/markers` offers; see {@link JunctionAPIOptions.markerCatalog}. */
2765
+ markerCatalog?: readonly MarkerCatalogEntry[];
2766
+ /** Name the markers behind add-on result lines; see {@link JunctionAPIOptions.addOnSourceMarkers}. */
2767
+ addOnSourceMarkers?: boolean;
2519
2768
  /** The team's lab accounts, or `{ presets, accounts }`; see {@link JunctionAPIOptions.labAccounts}. */
2520
2769
  labAccounts?: LabAccountLayout;
2521
2770
  /** Per-lab multiple-account omission policy; default platform. */
2522
2771
  labAccountOmissionPolicies?: Record<string, LabAccountOmissionPolicy>;
2523
2772
  labAccountBehavior?: Partial<LabAccountBehavior>;
2773
+ /** Opt-in sandbox quirks, every one off by default (#474). */
2774
+ quirks?: JunctionQuirks;
2524
2775
  /** The team the mock answers as. Default: the corpus's recorded team, else a fixed id. */
2525
2776
  teamId?: string;
2526
2777
  /** Sandbox-only restrictions, every one off by default; per namespace via `PUT /__admin/limits`. */
package/dist/server.js CHANGED
@@ -3,8 +3,8 @@ import {
3
3
  createServer,
4
4
  loadCorpus,
5
5
  serveTarget
6
- } from "./chunk-HJJCEIVH.js";
7
- import "./chunk-VHVGQ3WX.js";
6
+ } from "./chunk-BGYGWODK.js";
7
+ import "./chunk-ZJCE4VM4.js";
8
8
  import "./chunk-2FZJPMTR.js";
9
9
  import "./chunk-ISDNA2TU.js";
10
10
  export {