@crvouga/mockingbird-service-junction 0.2.0 → 0.4.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/dist/index.d.ts CHANGED
@@ -98,7 +98,12 @@ type FaultRule = {
98
98
  * rules added through `POST /__admin/faults` default to the calling namespace.
99
99
  */
100
100
  namespace?: string;
101
- status: number;
101
+ /**
102
+ * Status of the injected response. Omit for a rule that only delays (`delayMs` /
103
+ * `latencyMs`), only drops the connection (`drop`), or only switches on an `effect`:
104
+ * the request then still reaches the service.
105
+ */
106
+ status?: number;
102
107
  /** Response body, serialized as JSON. A string is sent as-is. */
103
108
  body?: unknown;
104
109
  headers?: Record<string, string>;
@@ -108,6 +113,34 @@ type FaultRule = {
108
113
  rate?: number;
109
114
  /** Hold the response back this long, to exercise timeouts. */
110
115
  delayMs?: number;
116
+ /** Alias of `delayMs`. */
117
+ latencyMs?: number;
118
+ /**
119
+ * Drop the connection instead of answering: an in-process `fetch` rejects with a
120
+ * `TypeError`, and a served mock destroys the socket. Models "unknown outcome" failures.
121
+ */
122
+ drop?: boolean;
123
+ /**
124
+ * A named service behaviour to switch on for the matching request instead of (or
125
+ * before) a canned response, e.g. `created_but_500` or `numeric_tracking_id`. Services
126
+ * read it with `faultEffects(request)`.
127
+ */
128
+ effect?: string;
129
+ /** Parameters for `effect`. */
130
+ params?: Record<string, unknown>;
131
+ /** From the preset this rule was expanded from, if any. */
132
+ preset?: string;
133
+ };
134
+ /** A fault that fired for one request. */
135
+ type FaultHit = {
136
+ id: string;
137
+ /** The injected response; absent when the rule only delays, drops, or sets an effect. */
138
+ response?: Response;
139
+ drop?: boolean;
140
+ effect?: {
141
+ name: string;
142
+ params: Record<string, unknown>;
143
+ };
111
144
  };
112
145
  /** What a request looks like to the fault matcher. */
113
146
  type FaultCandidate = {
@@ -125,13 +158,11 @@ type FaultRegistry = {
125
158
  remove(id: string): boolean;
126
159
  clear(): void;
127
160
  /**
128
- * The fault this request should get, or `undefined` to let it through.
129
- * Consumes one of the matching rule's remaining uses.
161
+ * Every fault this request should get, in rule order, stopping at the first that answers
162
+ * or drops (effect-only and delay-only rules let later rules match too). Consumes one of
163
+ * each matching rule's remaining uses.
130
164
  */
131
- take(candidate: FaultCandidate): Promise<{
132
- id: string;
133
- response: Response;
134
- } | undefined>;
165
+ take(candidate: FaultCandidate): Promise<FaultHit[]>;
135
166
  };
136
167
 
137
168
  /** One handled request, as the structured log sees it. */
@@ -147,6 +178,10 @@ type RequestLog = {
147
178
  unmatched: boolean;
148
179
  /** Set when a fault rule produced the response. */
149
180
  faultId?: string;
181
+ /** Resource ids the handler touched (`userId`, `orderId`, …), when the service reports them. */
182
+ ids?: Record<string, string>;
183
+ /** Set when the service created a resource the request referred to but that did not exist. */
184
+ adopted?: boolean;
150
185
  };
151
186
  type MetricsReport = {
152
187
  requests: number;
@@ -172,6 +207,28 @@ type Metrics = {
172
207
  reset(): void;
173
208
  };
174
209
 
210
+ /** One journal entry: a request log stamped with when (on the mock clock) it was handled. */
211
+ type JournalEntry = RequestLog & {
212
+ at: string;
213
+ };
214
+ type JournalQuery = {
215
+ /** Only this namespace. Omit for every namespace, oldest first across all of them. */
216
+ namespace?: string;
217
+ operationId?: string;
218
+ status?: number;
219
+ /** Only entries at or after this instant (epoch ms). */
220
+ since?: number;
221
+ /** At most this many, the most recent kept. */
222
+ limit?: number;
223
+ };
224
+ type Journal = {
225
+ readonly size: number;
226
+ record(entry: JournalEntry): void;
227
+ list(query?: JournalQuery): JournalEntry[];
228
+ /** Forget one namespace's entries, or every namespace's. */
229
+ clear(namespace?: string): void;
230
+ };
231
+
175
232
  /**
176
233
  * A point-in-time copy of everything a service namespace holds.
177
234
  *
@@ -194,6 +251,18 @@ type NamespaceSnapshot = {
194
251
  }[];
195
252
  };
196
253
 
254
+ /** Credential → namespace mapping behind `PUT /__admin/credentials`. */
255
+ type CredentialRegistry = {
256
+ set(credential: string, namespace: string): void;
257
+ get(credential: string): string | undefined;
258
+ remove(credential: string): boolean;
259
+ clear(): void;
260
+ entries(): {
261
+ credential: string;
262
+ namespace: string;
263
+ }[];
264
+ };
265
+
197
266
  /**
198
267
  * Anything that can answer a Fetch `Request` with a `Response`.
199
268
  *
@@ -204,6 +273,82 @@ interface FetchAPI$1 {
204
273
  fetch(request: Request): Promise<Response>;
205
274
  }
206
275
 
276
+ type WebhookEndpoint$1 = {
277
+ /** Stable id; generated when omitted. */
278
+ id?: string;
279
+ url: string;
280
+ secret?: string;
281
+ /** Event types to deliver; omit or include `"*"` for every type. */
282
+ events?: string[];
283
+ /** Deliver only messages whose tags include all of these (e.g. `{ account: "mso" }`). */
284
+ tags?: Record<string, string>;
285
+ /** The public URL the receiver verifies signatures against (Twilio), when it differs. */
286
+ signUrl?: string;
287
+ headers?: Record<string, string>;
288
+ };
289
+ type WebhookMessage = {
290
+ id: string;
291
+ namespace: string;
292
+ type: string;
293
+ body: string;
294
+ contentType: string;
295
+ tags: Record<string, string>;
296
+ /** Wall-clock ISO-8601 time of publication. */
297
+ publishedAt: string;
298
+ };
299
+ type WebhookAttempt$1 = {
300
+ attempt: number;
301
+ at: string;
302
+ status: number | null;
303
+ error: string | null;
304
+ durationMs: number;
305
+ };
306
+ type WebhookDelivery$1 = {
307
+ id: string;
308
+ messageId: string;
309
+ namespace: string;
310
+ type: string;
311
+ endpointId: string;
312
+ url: string;
313
+ state: "pending" | "delivered" | "failed" | "dropped";
314
+ attempts: WebhookAttempt$1[];
315
+ };
316
+ /** A delivery-level fault: what happens to the next `count` messages in a namespace. */
317
+ type WebhookFault = {
318
+ mode: "duplicate" | "reorder" | "drop";
319
+ /** Messages affected; default 1. */
320
+ count?: number;
321
+ };
322
+ type PublishInput = {
323
+ namespace: string;
324
+ type: string;
325
+ /** Exact body; objects are JSON-encoded. */
326
+ body: string | Record<string, unknown> | unknown[];
327
+ /** Default `application/json`, or form-encoded when `form` is given. */
328
+ contentType?: string;
329
+ /** Form parameters, when the vendor posts `application/x-www-form-urlencoded`. */
330
+ form?: Record<string, string>;
331
+ tags?: Record<string, string>;
332
+ /** Message id; generated when omitted. */
333
+ id?: string;
334
+ };
335
+ type WebhookHub = {
336
+ publish(input: PublishInput): WebhookMessage;
337
+ /** Replace a namespace's own endpoints (`PUT /__admin/webhook-endpoints`). */
338
+ setEndpoints(namespace: string, endpoints: WebhookEndpoint$1[]): WebhookEndpoint$1[];
339
+ /** The endpoints a namespace delivers to: its own, plus the global ones. */
340
+ endpoints(namespace: string): WebhookEndpoint$1[];
341
+ messages(namespace?: string): WebhookMessage[];
342
+ deliveries(namespace?: string): WebhookDelivery$1[];
343
+ replay(deliveryId: string): Promise<WebhookDelivery$1 | undefined>;
344
+ /** Run every pending retry (and release held reordered messages) now. */
345
+ flush(): Promise<void>;
346
+ /** Resolve once nothing is in flight. */
347
+ idle(): Promise<void>;
348
+ fault(namespace: string, fault: WebhookFault): void;
349
+ clear(namespace?: string): void;
350
+ };
351
+
207
352
  /** What the runtime needs from a service: a Fetch handler it can reset. */
208
353
  type ServiceInstance = FetchAPI$1 & {
209
354
  reset(): Promise<void>;
@@ -214,7 +359,13 @@ type ServiceRuntime<T extends ServiceInstance> = FetchAPI$1 & {
214
359
  readonly clock: Clock;
215
360
  readonly faults: FaultRegistry;
216
361
  readonly metrics: Metrics;
362
+ readonly journal: Journal;
217
363
  readonly rng: Rng;
364
+ readonly credentials: CredentialRegistry;
365
+ /** The webhook hub, when the service has outbound webhooks. */
366
+ readonly webhooks: WebhookHub | undefined;
367
+ /** Expand a named preset into fault rules (and webhook faults) for `namespace`. */
368
+ applyPreset(name: string, namespace?: string, overrides?: Partial<FaultRule>): FaultRule[];
218
369
  /** The instance behind `namespace` (the default one when omitted), created on first use. */
219
370
  instance(namespace?: string): T;
220
371
  /** Public names of every namespace created so far. */
@@ -319,6 +470,95 @@ type LabTestRecord = {
319
470
  worst_case_tat_days: number | null;
320
471
  };
321
472
 
473
+ /**
474
+ * The test backdoor: users and orders put straight into a namespace, with ids a suite
475
+ * chooses — the Junction `user_id`s a database fixture already carries, or an order
476
+ * already in some status — plus the lenient identity mode that adopts unknown users.
477
+ *
478
+ * Everything inserted here goes through the records `create_user` and `create_order`
479
+ * build, so no read path can tell a fixture from an API-created resource.
480
+ */
481
+
482
+ /** How requests referring to a user the namespace does not hold are answered. */
483
+ type IdentityMode = "strict" | "adopt-users";
484
+ declare const IDENTITY_MODES: readonly IdentityMode[];
485
+ type UserFixture = {
486
+ /** Default: a fresh id, as `create_user` would mint. */
487
+ user_id?: string;
488
+ client_user_id: string;
489
+ /** ISO-8601. Default: the mock clock's now. */
490
+ created_on?: string;
491
+ /** An IANA zone, or the full `{ id, source_slug, updated_at }` object. */
492
+ fallback_time_zone?: string | UserRecord["fallback_time_zone"];
493
+ /** `YYYY-MM-DD`, or the full `{ value, source_slug, updated_at }` object. */
494
+ fallback_birth_date?: string | UserRecord["fallback_birth_date"];
495
+ ingestion_start?: string | null;
496
+ ingestion_end?: string | null;
497
+ };
498
+ type OrderFixture = {
499
+ /** Default: a fresh id, as `create_order` would mint. */
500
+ order_id?: string;
501
+ user_id: string;
502
+ lab_test_id: string;
503
+ lab_account_id?: string;
504
+ /** A transition target (`completed`, `at_lab`, or a full status). Default: just ordered. */
505
+ status?: string;
506
+ /** Default: the lab test's own method. */
507
+ collection_method?: string;
508
+ patient_details?: Record<string, unknown>;
509
+ patient_address?: Record<string, unknown>;
510
+ billing_type?: string;
511
+ icd_codes?: string[] | null;
512
+ passthrough?: string | null;
513
+ clinical_notes?: string | null;
514
+ /** ISO-8601. Default: the mock clock's now. */
515
+ created_at?: string;
516
+ /** Results served for the order, as `PUT /__admin/results/{id}` takes them. */
517
+ result_fixture?: Omit<ResultFixture, "name"> & {
518
+ name?: string;
519
+ };
520
+ };
521
+ type JunctionFixtures = {
522
+ users?: readonly UserFixture[];
523
+ orders?: readonly OrderFixture[];
524
+ };
525
+ type InsertOptions = {
526
+ /** Publish the webhooks the equivalent API calls would. Default `false`. */
527
+ emitWebhooks?: boolean;
528
+ };
529
+ /** A backdoor failure: `status` 400 for a bad fixture, 404 for a missing reference, 409 for a clash. */
530
+ declare class FixtureError extends Error {
531
+ readonly status: 400 | 404 | 409;
532
+ constructor(status: 400 | 404 | 409, message: string);
533
+ }
534
+
535
+ /** Key prefixes of sandbox team keys. `corpus pull` and `verify` refuse any other key. */
536
+ declare const SANDBOX_KEY_PREFIXES: readonly ["sk_us_", "sk_eu_"];
537
+ declare const isSandboxKey: (key: string) => boolean;
538
+ type JunctionLimits = {
539
+ /**
540
+ * Live users a team may hold; creating one more answers the sandbox's
541
+ * "maximum of 50 Sandbox users" 400. Deleted users free their slot. `null`: unlimited.
542
+ */
543
+ maxUsers: number | null;
544
+ /** Refuse `POST /v3/order/{id}/test` unless the API key is a sandbox key (`sk_us_…`/`sk_eu_…`). */
545
+ simulateRequiresSandbox: boolean;
546
+ /** Vendor requests per second per namespace before a 429. `null`: unlimited. */
547
+ rateLimitPerSecond: number | null;
548
+ };
549
+ type JunctionLimitsInput = {
550
+ [K in keyof JunctionLimits]?: JunctionLimits[K] | undefined;
551
+ };
552
+ /** Every limit off: what a default instance enforces. */
553
+ declare const DEFAULT_LIMITS: Readonly<JunctionLimits>;
554
+ /** The 400 the sandbox answers once a team holds its 50th user, byte for byte. */
555
+ declare const sandboxUserQuotaBody: (max: number) => {
556
+ detail: {
557
+ error_type: string;
558
+ error_message: string;
559
+ };
560
+ };
561
+
322
562
  type GetCacheEntry = {
323
563
  status: number;
324
564
  headers: Record<string, string>;
@@ -340,6 +580,27 @@ type WebhookDeliveryAttempt = {
340
580
  timeout_ms: number;
341
581
  acknowledged: boolean;
342
582
  };
583
+ type UserRecord = {
584
+ user_id: string;
585
+ team_id: string;
586
+ client_user_id: string;
587
+ created_on: string;
588
+ connected_sources: unknown[];
589
+ fallback_time_zone: {
590
+ id: string;
591
+ source_slug: string;
592
+ updated_at: string;
593
+ } | null;
594
+ fallback_birth_date: {
595
+ value: string;
596
+ source_slug: string;
597
+ updated_at: string;
598
+ } | null;
599
+ ingestion_start: string | null;
600
+ ingestion_end: string | null;
601
+ };
602
+ /** Fixed mock team id — volatile on the real side, stable in the mock. */
603
+ declare const MOCK_TEAM_ID = "11111111-1111-4111-8111-111111111111";
343
604
  type OrderEventRecord = {
344
605
  id: number;
345
606
  created_at: string;
@@ -472,7 +733,16 @@ type LabAccountRecord = {
472
733
  };
473
734
  /** The 50 `USState` values from the docs, alphabetical by state name. */
474
735
  declare const US_STATES: readonly string[];
736
+ /** A team the mock is not, for fixtures that model another team's account. */
737
+ declare const OTHER_TEAM_ID: string;
475
738
  declare const TEAM_LAB_ACCOUNTS: readonly LabAccountRecord[];
739
+ /**
740
+ * Whether `teamId` may use an account. An empty `team_id_allowlist` counts as linked:
741
+ * a real team's listing returns such accounts (observed — Junction's own Quest, Labcorp
742
+ * and BioReference accounts carry `[]`), so the mock treats them as the team's. Whether
743
+ * ordering through one by explicit id behaves the same is unverified; SUPPORT.md tracks it.
744
+ */
745
+ declare const isLinkedToTeam: (entry: LabAccountRecord, teamId: string) => boolean;
476
746
  /**
477
747
  * A lab account as a consumer configures it. Mirrors `ClientFacingLabAccount`, with
478
748
  * every field but `id` and `lab` optional, plus a `states` shorthand for the common
@@ -493,17 +763,58 @@ type LabAccountInput = {
493
763
  allowed_billing?: Record<string, readonly string[]>;
494
764
  /** Shorthand for `allowed_billing: { client_bill: states }`. Default: every state. */
495
765
  states?: readonly string[];
496
- /** Teams the account is linked to. Default: the mock team, so it is selectable. */
766
+ /** Teams the account is linked to. Default: the configured team, so it is selectable. */
497
767
  team_id_allowlist?: readonly string[];
498
768
  };
499
- /** Normalize a consumer's configuration into the record the ordering rules read. */
500
- declare const labAccountFromInput: (input: LabAccountInput) => LabAccountRecord;
769
+ /**
770
+ * Normalize a consumer's configuration into the record the ordering rules read.
771
+ * `teamId` is the default allowlist, so an account is selectable unless told otherwise.
772
+ */
773
+ declare const labAccountFromInput: (input: LabAccountInput, teamId?: string) => LabAccountRecord;
774
+
775
+ /**
776
+ * Named lab accounts a suite can add in one call, modelled on a real team's recorded
777
+ * listing (a BioReference-linked team, recorded 2026-09-21 from the Junction sandbox).
778
+ *
779
+ * Where a preset copies a recorded account, its states and billing types are the
780
+ * recording's. `bioreference_ny_nj_delegated` is not a recorded account: it is the
781
+ * NY/NJ client-bill shape a consumer asked for, kept because suites depend on it.
782
+ */
783
+
784
+ /** Junction's own Quest, Labcorp and BioReference accounts client-bill in these 47 states. */
785
+ declare const PLATFORM_ACCOUNT_STATES: readonly string[];
786
+ /** The recorded order-delegated BioReference account: every state but New York and New Jersey. */
787
+ declare const DELEGATED_ACCOUNT_STATES: readonly string[];
788
+ type Preset = Omit<LabAccountInput, "id">;
789
+ /**
790
+ * Every preset, without its id. A preset with no `team_id_allowlist` is linked to the
791
+ * configured team; the platform presets carry `[]`, as Junction's own accounts do.
792
+ */
793
+ declare const LAB_ACCOUNT_PRESETS: Readonly<Record<string, Preset>>;
794
+ /** A preset's id when none is given: stable across runs and namespaces. */
795
+ declare const presetAccountId: (name: string) => string;
796
+ /**
797
+ * A lab-account layout as a file or option declares it: a bare list of accounts, or
798
+ * presets (by name, or `{ name, id }`) plus accounts, added in that order.
799
+ */
800
+ type LabAccountLayout = readonly LabAccountInput[] | {
801
+ presets?: readonly (string | {
802
+ name: string;
803
+ id?: string;
804
+ })[];
805
+ accounts?: readonly LabAccountInput[];
806
+ };
501
807
 
502
808
  /**
503
809
  * Version of the sealed-corpus on-disk format. Bumped whenever the shape changes so a
504
810
  * stale recording is rejected instead of half-applied.
811
+ *
812
+ * - 1: observations, catalog and lab accounts.
813
+ * - 2: adds `teamId`, the recording team, so lab-account allowlists load verbatim.
505
814
  */
506
- declare const SEALED_CORPUS_VERSION = 1;
815
+ declare const SEALED_CORPUS_VERSION = 2;
816
+ /** Versions `parseSealedCorpus` still loads. A version-1 corpus behaves as it did in 0.2.0. */
817
+ declare const SUPPORTED_SEALED_CORPUS_VERSIONS: readonly number[];
507
818
  /**
508
819
  * Exact sandbox recording of the provider-owned reads a drop-in consumer depends on:
509
820
  * parameter-stable GET observations (area/PSC inventory), the lab catalog, team labs, and
@@ -511,9 +822,14 @@ declare const SEALED_CORPUS_VERSION = 1;
511
822
  * `booking_key`s can never match a live cache key, so it stays with the generator.
512
823
  */
513
824
  type SealedCorpus = {
514
- version: typeof SEALED_CORPUS_VERSION;
825
+ version: 1 | typeof SEALED_CORPUS_VERSION;
515
826
  recordedAt: string;
516
827
  source: string;
828
+ /**
829
+ * The recording team's id (version 2+). When present it is the mock's default team,
830
+ * and each lab account's `team_id_allowlist` is kept exactly as recorded.
831
+ */
832
+ teamId?: string;
517
833
  /** SHA-256 of the recording's content, written by `corpus pull`. Identifies it in logs. */
518
834
  fingerprint?: string;
519
835
  observations: Record<string, GetCacheEntry>;
@@ -645,10 +961,38 @@ type JunctionAdminOptions = {
645
961
  webhooks: WebhookDispatcher | undefined;
646
962
  };
647
963
 
964
+ type SeedCacheEntry = {
965
+ status: number;
966
+ headers: Record<string, string>;
967
+ body: unknown;
968
+ };
969
+
970
+ type PrefetchTarget = {
971
+ baseUrl: string;
972
+ fetch: (request: Request) => Promise<Response>;
973
+ headers: () => Promise<Record<string, string>> | Record<string, string>;
974
+ };
975
+ /**
976
+ * Seal coverage-corpus routing ZIPs + availability POSTs into the seed observation cache.
977
+ * Call after warmup, before `seedFrom`, so compare walks can forceInclude geo/scheduling reads.
978
+ */
979
+ declare const prefetchCoverageObservations: (args: {
980
+ real: PrefetchTarget;
981
+ getCache: Map<string, SeedCacheEntry>;
982
+ zips?: readonly string[];
983
+ /** ZIPs that also get PSC availability POST seals. Defaults to scheduling corpus. */
984
+ schedulingZips?: readonly string[];
985
+ /** ZIPs for phlebotomy availability (narrow served set). Defaults to PHLEBOTOMY_ZIPS. */
986
+ phlebotomyZips?: readonly string[];
987
+ labIds?: readonly number[];
988
+ /** Also prefetch phlebotomy + PSC availability. Default true. */
989
+ includeAvailability?: boolean;
990
+ sleep?: (ms: number) => Promise<void>;
991
+ minIntervalMs?: number;
992
+ }) => Promise<void>;
993
+
648
994
  declare const DEFAULT_JUNCTION_BASE_URL = "https://api.sandbox.tryvital.io";
649
- /** Key prefixes of sandbox team keys. `corpus pull` and `verify` refuse any other key. */
650
- declare const SANDBOX_KEY_PREFIXES: readonly ["sk_us_", "sk_eu_"];
651
- declare const isSandboxKey: (key: string) => boolean;
995
+
652
996
  type PullCorpusOptions = {
653
997
  apiKey: string;
654
998
  baseUrl?: string;
@@ -677,6 +1021,11 @@ type SetDiff = {
677
1021
  };
678
1022
  type CorpusDiff = {
679
1023
  identical: boolean;
1024
+ /** Set when the recorded team differs (or one side recorded none). */
1025
+ teamId?: {
1026
+ before: string | null;
1027
+ after: string | null;
1028
+ };
680
1029
  observations: SetDiff;
681
1030
  labTests: SetDiff;
682
1031
  labAccounts: SetDiff;
@@ -870,40 +1219,20 @@ type OpenAPIDocument = {
870
1219
  };
871
1220
 
872
1221
  declare const document: OpenAPIDocument;
873
- type OperationId = "get_teams_users_v2_user_get" | "create_user_v2_user_post" | "get_user_v2_user__user_id__get" | "delete_user_v2_user__user_id__delete" | "patch_user_v2_user__user_id__patch" | "get_user_by_client_user_id_v2_user_resolve__client_user_id__get" | "patch_user_info_v2_user__user_id__info_patch" | "get_latest_user_info_user_v2_user__user_id__info_latest_get" | "get_paginated_lab_tests_for_team_v3_lab_test_get" | "get_team_lab_accounts_v3_lab_test_lab_account_get" | "get_lab_test_for_team_v3_lab_tests__lab_test_id__get" | "get_labs_v3_lab_tests_labs_get" | "get_markers_for_lab_test_v3_lab_tests__lab_test_id__markers_get" | "list_order_set_markers_v3_lab_tests_list_order_set_markers_post" | "create_order_v3_order_post" | "get_area_info_v3_order_area_info_get" | "get_psc_info_v3_order_psc_info_get" | "get_phlebotomy_appointment_availability_v3_order_phlebotomy_appointment_availability_post" | "get_phlebotomy_appointment_cancellation_reason_v3_order_phlebotomy_appointment_cancellation_reasons_get" | "get_psc_appointment_availability_v3_order_psc_appointment_availability_post" | "get_psc_appointment_cancellation_reason_v3_order_psc_appointment_cancellation_reasons_get" | "get_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_get" | "book_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_book_post" | "reschedule_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_reschedule_patch" | "cancel_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_cancel_patch" | "get_psc_appointment_v3_order__order_id__psc_appointment_get" | "book_psc_appointment_v3_order__order_id__psc_appointment_book_post" | "reschedule_psc_appointment_v3_order__order_id__psc_appointment_reschedule_patch" | "cancel_psc_appointment_v3_order__order_id__psc_appointment_cancel_patch" | "get_order_v3_order__order_id__get" | "cancel_order_v3_order__order_id__cancel_post" | "simulate_order_v3_order__order_id__test_post" | "get_result_raw_v3_order__order_id__result_get" | "get_result_metadata_v3_order__order_id__result_metadata_get" | "get_result_pdf_v3_order__order_id__result_pdf_get" | "get_order_requisition_pdf_v3_order__order_id__requisition_pdf_get" | "get_orders_v3_orders_get" | "get_order_transaction_v3_order_transaction__transaction_id__get" | "get_order_transaction_result_v3_order_transaction__transaction_id__result_get";
874
- type SupportedOperationId = "get_teams_users_v2_user_get" | "create_user_v2_user_post" | "get_user_v2_user__user_id__get" | "delete_user_v2_user__user_id__delete" | "patch_user_v2_user__user_id__patch" | "get_user_by_client_user_id_v2_user_resolve__client_user_id__get" | "patch_user_info_v2_user__user_id__info_patch" | "get_latest_user_info_user_v2_user__user_id__info_latest_get" | "get_paginated_lab_tests_for_team_v3_lab_test_get" | "get_team_lab_accounts_v3_lab_test_lab_account_get" | "get_lab_test_for_team_v3_lab_tests__lab_test_id__get" | "get_labs_v3_lab_tests_labs_get" | "get_markers_for_lab_test_v3_lab_tests__lab_test_id__markers_get" | "list_order_set_markers_v3_lab_tests_list_order_set_markers_post" | "create_order_v3_order_post" | "get_area_info_v3_order_area_info_get" | "get_psc_info_v3_order_psc_info_get" | "get_phlebotomy_appointment_availability_v3_order_phlebotomy_appointment_availability_post" | "get_phlebotomy_appointment_cancellation_reason_v3_order_phlebotomy_appointment_cancellation_reasons_get" | "get_psc_appointment_availability_v3_order_psc_appointment_availability_post" | "get_psc_appointment_cancellation_reason_v3_order_psc_appointment_cancellation_reasons_get" | "get_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_get" | "book_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_book_post" | "reschedule_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_reschedule_patch" | "cancel_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_cancel_patch" | "get_psc_appointment_v3_order__order_id__psc_appointment_get" | "book_psc_appointment_v3_order__order_id__psc_appointment_book_post" | "reschedule_psc_appointment_v3_order__order_id__psc_appointment_reschedule_patch" | "cancel_psc_appointment_v3_order__order_id__psc_appointment_cancel_patch" | "get_order_v3_order__order_id__get" | "cancel_order_v3_order__order_id__cancel_post" | "simulate_order_v3_order__order_id__test_post" | "get_result_raw_v3_order__order_id__result_get" | "get_result_metadata_v3_order__order_id__result_metadata_get" | "get_result_pdf_v3_order__order_id__result_pdf_get" | "get_order_requisition_pdf_v3_order__order_id__requisition_pdf_get" | "get_orders_v3_orders_get" | "get_order_transaction_v3_order_transaction__transaction_id__get" | "get_order_transaction_result_v3_order_transaction__transaction_id__result_get";
875
- declare const operationIds: readonly ["get_teams_users_v2_user_get", "create_user_v2_user_post", "get_user_v2_user__user_id__get", "delete_user_v2_user__user_id__delete", "patch_user_v2_user__user_id__patch", "get_user_by_client_user_id_v2_user_resolve__client_user_id__get", "patch_user_info_v2_user__user_id__info_patch", "get_latest_user_info_user_v2_user__user_id__info_latest_get", "get_paginated_lab_tests_for_team_v3_lab_test_get", "get_team_lab_accounts_v3_lab_test_lab_account_get", "get_lab_test_for_team_v3_lab_tests__lab_test_id__get", "get_labs_v3_lab_tests_labs_get", "get_markers_for_lab_test_v3_lab_tests__lab_test_id__markers_get", "list_order_set_markers_v3_lab_tests_list_order_set_markers_post", "create_order_v3_order_post", "get_area_info_v3_order_area_info_get", "get_psc_info_v3_order_psc_info_get", "get_phlebotomy_appointment_availability_v3_order_phlebotomy_appointment_availability_post", "get_phlebotomy_appointment_cancellation_reason_v3_order_phlebotomy_appointment_cancellation_reasons_get", "get_psc_appointment_availability_v3_order_psc_appointment_availability_post", "get_psc_appointment_cancellation_reason_v3_order_psc_appointment_cancellation_reasons_get", "get_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_get", "book_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_book_post", "reschedule_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_reschedule_patch", "cancel_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_cancel_patch", "get_psc_appointment_v3_order__order_id__psc_appointment_get", "book_psc_appointment_v3_order__order_id__psc_appointment_book_post", "reschedule_psc_appointment_v3_order__order_id__psc_appointment_reschedule_patch", "cancel_psc_appointment_v3_order__order_id__psc_appointment_cancel_patch", "get_order_v3_order__order_id__get", "cancel_order_v3_order__order_id__cancel_post", "simulate_order_v3_order__order_id__test_post", "get_result_raw_v3_order__order_id__result_get", "get_result_metadata_v3_order__order_id__result_metadata_get", "get_result_pdf_v3_order__order_id__result_pdf_get", "get_order_requisition_pdf_v3_order__order_id__requisition_pdf_get", "get_orders_v3_orders_get", "get_order_transaction_v3_order_transaction__transaction_id__get", "get_order_transaction_result_v3_order_transaction__transaction_id__result_get"];
876
- declare const supportedOperationIds: readonly ["get_teams_users_v2_user_get", "create_user_v2_user_post", "get_user_v2_user__user_id__get", "delete_user_v2_user__user_id__delete", "patch_user_v2_user__user_id__patch", "get_user_by_client_user_id_v2_user_resolve__client_user_id__get", "patch_user_info_v2_user__user_id__info_patch", "get_latest_user_info_user_v2_user__user_id__info_latest_get", "get_paginated_lab_tests_for_team_v3_lab_test_get", "get_team_lab_accounts_v3_lab_test_lab_account_get", "get_lab_test_for_team_v3_lab_tests__lab_test_id__get", "get_labs_v3_lab_tests_labs_get", "get_markers_for_lab_test_v3_lab_tests__lab_test_id__markers_get", "list_order_set_markers_v3_lab_tests_list_order_set_markers_post", "create_order_v3_order_post", "get_area_info_v3_order_area_info_get", "get_psc_info_v3_order_psc_info_get", "get_phlebotomy_appointment_availability_v3_order_phlebotomy_appointment_availability_post", "get_phlebotomy_appointment_cancellation_reason_v3_order_phlebotomy_appointment_cancellation_reasons_get", "get_psc_appointment_availability_v3_order_psc_appointment_availability_post", "get_psc_appointment_cancellation_reason_v3_order_psc_appointment_cancellation_reasons_get", "get_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_get", "book_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_book_post", "reschedule_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_reschedule_patch", "cancel_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_cancel_patch", "get_psc_appointment_v3_order__order_id__psc_appointment_get", "book_psc_appointment_v3_order__order_id__psc_appointment_book_post", "reschedule_psc_appointment_v3_order__order_id__psc_appointment_reschedule_patch", "cancel_psc_appointment_v3_order__order_id__psc_appointment_cancel_patch", "get_order_v3_order__order_id__get", "cancel_order_v3_order__order_id__cancel_post", "simulate_order_v3_order__order_id__test_post", "get_result_raw_v3_order__order_id__result_get", "get_result_metadata_v3_order__order_id__result_metadata_get", "get_result_pdf_v3_order__order_id__result_pdf_get", "get_order_requisition_pdf_v3_order__order_id__requisition_pdf_get", "get_orders_v3_orders_get", "get_order_transaction_v3_order_transaction__transaction_id__get", "get_order_transaction_result_v3_order_transaction__transaction_id__result_get"];
877
-
878
- type SeedCacheEntry = {
879
- status: number;
880
- headers: Record<string, string>;
881
- body: unknown;
882
- };
1222
+ type OperationId = "get_teams_users_v2_user_get" | "create_user_v2_user_post" | "get_user_v2_user__user_id__get" | "delete_user_v2_user__user_id__delete" | "patch_user_v2_user__user_id__patch" | "get_user_by_client_user_id_v2_user_resolve__client_user_id__get" | "patch_user_info_v2_user__user_id__info_patch" | "get_latest_user_info_user_v2_user__user_id__info_latest_get" | "get_paginated_lab_tests_for_team_v3_lab_test_get" | "get_team_lab_accounts_v3_lab_test_lab_account_get" | "get_lab_tests_for_team_v3_lab_tests_get" | "get_lab_test_for_team_v3_lab_tests__lab_test_id__get" | "get_labs_v3_lab_tests_labs_get" | "get_markers_for_lab_test_v3_lab_tests__lab_test_id__markers_get" | "list_order_set_markers_v3_lab_tests_list_order_set_markers_post" | "create_order_v3_order_post" | "get_area_info_v3_order_area_info_get" | "get_psc_info_v3_order_psc_info_get" | "get_phlebotomy_appointment_availability_v3_order_phlebotomy_appointment_availability_post" | "get_phlebotomy_appointment_cancellation_reason_v3_order_phlebotomy_appointment_cancellation_reasons_get" | "get_psc_appointment_availability_v3_order_psc_appointment_availability_post" | "get_psc_appointment_cancellation_reason_v3_order_psc_appointment_cancellation_reasons_get" | "get_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_get" | "book_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_book_post" | "reschedule_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_reschedule_patch" | "cancel_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_cancel_patch" | "get_psc_appointment_v3_order__order_id__psc_appointment_get" | "book_psc_appointment_v3_order__order_id__psc_appointment_book_post" | "reschedule_psc_appointment_v3_order__order_id__psc_appointment_reschedule_patch" | "cancel_psc_appointment_v3_order__order_id__psc_appointment_cancel_patch" | "get_order_v3_order__order_id__get" | "cancel_order_v3_order__order_id__cancel_post" | "simulate_order_v3_order__order_id__test_post" | "get_result_raw_v3_order__order_id__result_get" | "get_result_metadata_v3_order__order_id__result_metadata_get" | "get_result_pdf_v3_order__order_id__result_pdf_get" | "get_order_requisition_pdf_v3_order__order_id__requisition_pdf_get" | "get_orders_v3_orders_get" | "get_order_transaction_v3_order_transaction__transaction_id__get" | "get_order_transaction_result_v3_order_transaction__transaction_id__result_get";
1223
+ type SupportedOperationId = "get_teams_users_v2_user_get" | "create_user_v2_user_post" | "get_user_v2_user__user_id__get" | "delete_user_v2_user__user_id__delete" | "patch_user_v2_user__user_id__patch" | "get_user_by_client_user_id_v2_user_resolve__client_user_id__get" | "patch_user_info_v2_user__user_id__info_patch" | "get_latest_user_info_user_v2_user__user_id__info_latest_get" | "get_paginated_lab_tests_for_team_v3_lab_test_get" | "get_team_lab_accounts_v3_lab_test_lab_account_get" | "get_lab_tests_for_team_v3_lab_tests_get" | "get_lab_test_for_team_v3_lab_tests__lab_test_id__get" | "get_labs_v3_lab_tests_labs_get" | "get_markers_for_lab_test_v3_lab_tests__lab_test_id__markers_get" | "list_order_set_markers_v3_lab_tests_list_order_set_markers_post" | "create_order_v3_order_post" | "get_area_info_v3_order_area_info_get" | "get_psc_info_v3_order_psc_info_get" | "get_phlebotomy_appointment_availability_v3_order_phlebotomy_appointment_availability_post" | "get_phlebotomy_appointment_cancellation_reason_v3_order_phlebotomy_appointment_cancellation_reasons_get" | "get_psc_appointment_availability_v3_order_psc_appointment_availability_post" | "get_psc_appointment_cancellation_reason_v3_order_psc_appointment_cancellation_reasons_get" | "get_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_get" | "book_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_book_post" | "reschedule_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_reschedule_patch" | "cancel_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_cancel_patch" | "get_psc_appointment_v3_order__order_id__psc_appointment_get" | "book_psc_appointment_v3_order__order_id__psc_appointment_book_post" | "reschedule_psc_appointment_v3_order__order_id__psc_appointment_reschedule_patch" | "cancel_psc_appointment_v3_order__order_id__psc_appointment_cancel_patch" | "get_order_v3_order__order_id__get" | "cancel_order_v3_order__order_id__cancel_post" | "simulate_order_v3_order__order_id__test_post" | "get_result_raw_v3_order__order_id__result_get" | "get_result_metadata_v3_order__order_id__result_metadata_get" | "get_result_pdf_v3_order__order_id__result_pdf_get" | "get_order_requisition_pdf_v3_order__order_id__requisition_pdf_get" | "get_orders_v3_orders_get" | "get_order_transaction_v3_order_transaction__transaction_id__get" | "get_order_transaction_result_v3_order_transaction__transaction_id__result_get";
1224
+ declare const operationIds: readonly ["get_teams_users_v2_user_get", "create_user_v2_user_post", "get_user_v2_user__user_id__get", "delete_user_v2_user__user_id__delete", "patch_user_v2_user__user_id__patch", "get_user_by_client_user_id_v2_user_resolve__client_user_id__get", "patch_user_info_v2_user__user_id__info_patch", "get_latest_user_info_user_v2_user__user_id__info_latest_get", "get_paginated_lab_tests_for_team_v3_lab_test_get", "get_team_lab_accounts_v3_lab_test_lab_account_get", "get_lab_tests_for_team_v3_lab_tests_get", "get_lab_test_for_team_v3_lab_tests__lab_test_id__get", "get_labs_v3_lab_tests_labs_get", "get_markers_for_lab_test_v3_lab_tests__lab_test_id__markers_get", "list_order_set_markers_v3_lab_tests_list_order_set_markers_post", "create_order_v3_order_post", "get_area_info_v3_order_area_info_get", "get_psc_info_v3_order_psc_info_get", "get_phlebotomy_appointment_availability_v3_order_phlebotomy_appointment_availability_post", "get_phlebotomy_appointment_cancellation_reason_v3_order_phlebotomy_appointment_cancellation_reasons_get", "get_psc_appointment_availability_v3_order_psc_appointment_availability_post", "get_psc_appointment_cancellation_reason_v3_order_psc_appointment_cancellation_reasons_get", "get_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_get", "book_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_book_post", "reschedule_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_reschedule_patch", "cancel_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_cancel_patch", "get_psc_appointment_v3_order__order_id__psc_appointment_get", "book_psc_appointment_v3_order__order_id__psc_appointment_book_post", "reschedule_psc_appointment_v3_order__order_id__psc_appointment_reschedule_patch", "cancel_psc_appointment_v3_order__order_id__psc_appointment_cancel_patch", "get_order_v3_order__order_id__get", "cancel_order_v3_order__order_id__cancel_post", "simulate_order_v3_order__order_id__test_post", "get_result_raw_v3_order__order_id__result_get", "get_result_metadata_v3_order__order_id__result_metadata_get", "get_result_pdf_v3_order__order_id__result_pdf_get", "get_order_requisition_pdf_v3_order__order_id__requisition_pdf_get", "get_orders_v3_orders_get", "get_order_transaction_v3_order_transaction__transaction_id__get", "get_order_transaction_result_v3_order_transaction__transaction_id__result_get"];
1225
+ declare const supportedOperationIds: readonly ["get_teams_users_v2_user_get", "create_user_v2_user_post", "get_user_v2_user__user_id__get", "delete_user_v2_user__user_id__delete", "patch_user_v2_user__user_id__patch", "get_user_by_client_user_id_v2_user_resolve__client_user_id__get", "patch_user_info_v2_user__user_id__info_patch", "get_latest_user_info_user_v2_user__user_id__info_latest_get", "get_paginated_lab_tests_for_team_v3_lab_test_get", "get_team_lab_accounts_v3_lab_test_lab_account_get", "get_lab_tests_for_team_v3_lab_tests_get", "get_lab_test_for_team_v3_lab_tests__lab_test_id__get", "get_labs_v3_lab_tests_labs_get", "get_markers_for_lab_test_v3_lab_tests__lab_test_id__markers_get", "list_order_set_markers_v3_lab_tests_list_order_set_markers_post", "create_order_v3_order_post", "get_area_info_v3_order_area_info_get", "get_psc_info_v3_order_psc_info_get", "get_phlebotomy_appointment_availability_v3_order_phlebotomy_appointment_availability_post", "get_phlebotomy_appointment_cancellation_reason_v3_order_phlebotomy_appointment_cancellation_reasons_get", "get_psc_appointment_availability_v3_order_psc_appointment_availability_post", "get_psc_appointment_cancellation_reason_v3_order_psc_appointment_cancellation_reasons_get", "get_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_get", "book_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_book_post", "reschedule_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_reschedule_patch", "cancel_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_cancel_patch", "get_psc_appointment_v3_order__order_id__psc_appointment_get", "book_psc_appointment_v3_order__order_id__psc_appointment_book_post", "reschedule_psc_appointment_v3_order__order_id__psc_appointment_reschedule_patch", "cancel_psc_appointment_v3_order__order_id__psc_appointment_cancel_patch", "get_order_v3_order__order_id__get", "cancel_order_v3_order__order_id__cancel_post", "simulate_order_v3_order__order_id__test_post", "get_result_raw_v3_order__order_id__result_get", "get_result_metadata_v3_order__order_id__result_metadata_get", "get_result_pdf_v3_order__order_id__result_pdf_get", "get_order_requisition_pdf_v3_order__order_id__requisition_pdf_get", "get_orders_v3_orders_get", "get_order_transaction_v3_order_transaction__transaction_id__get", "get_order_transaction_result_v3_order_transaction__transaction_id__result_get"];
883
1226
 
884
- type PrefetchTarget = {
885
- baseUrl: string;
886
- fetch: (request: Request) => Promise<Response>;
887
- headers: () => Promise<Record<string, string>> | Record<string, string>;
888
- };
1227
+ /** The `detail` of each order-scoped operation's 404 for an order that does not exist. */
1228
+ declare const ORDER_NOT_FOUND: Readonly<Record<string, string>>;
889
1229
  /**
890
- * Seal coverage-corpus routing ZIPs + availability POSTs into the seed observation cache.
891
- * Call after warmup, before `seedFrom`, so compare walks can forceInclude geo/scheduling reads.
1230
+ * Names the missing resource: `order <id>`, `user <id>`, or `user client:<client_user_id>`
1231
+ * (the id percent-encoded). Never part of Junction's answer.
892
1232
  */
893
- declare const prefetchCoverageObservations: (args: {
894
- real: PrefetchTarget;
895
- getCache: Map<string, SeedCacheEntry>;
896
- zips?: readonly string[];
897
- /** ZIPs that also get PSC availability POST seals. Defaults to scheduling corpus. */
898
- schedulingZips?: readonly string[];
899
- /** ZIPs for phlebotomy availability (narrow served set). Defaults to PHLEBOTOMY_ZIPS. */
900
- phlebotomyZips?: readonly string[];
901
- labIds?: readonly number[];
902
- /** Also prefetch phlebotomy + PSC availability. Default true. */
903
- includeAvailability?: boolean;
904
- sleep?: (ms: number) => Promise<void>;
905
- minIntervalMs?: number;
906
- }) => Promise<void>;
1233
+ declare const MISS_HEADER = "x-mockingbird-miss";
1234
+ /** What the namespace does hold: `users=<n> orders=<n>`. */
1235
+ declare const KNOWN_HEADER = "x-mockingbird-known";
907
1236
 
908
1237
  type Violation = "wrong-type" | "string-too-long" | "string-too-short" | "number-too-large" | "number-too-small" | "not-in-enum" | "missing-required" | "unexpected-property" | "array-too-long" | "array-too-short" | "bad-format";
909
1238
  type Mutation = {
@@ -980,8 +1309,18 @@ type JunctionRuntimeOptions = {
980
1309
  corpus?: SealedCorpus;
981
1310
  /** Default: `corpus` when a corpus is loaded, otherwise `synthetic`. */
982
1311
  geo?: GeoMode;
983
- /** The team's lab accounts; see {@link JunctionAPIOptions.labAccounts}. */
984
- labAccounts?: readonly LabAccountInput[];
1312
+ /** The team's lab accounts, or `{ presets, accounts }`; see {@link JunctionAPIOptions.labAccounts}. */
1313
+ labAccounts?: LabAccountLayout;
1314
+ /** The team the mock answers as. Default: the corpus's recorded team, else a fixed id. */
1315
+ teamId?: string;
1316
+ /** Sandbox-only restrictions, every one off by default; per namespace via `PUT /__admin/limits`. */
1317
+ limits?: JunctionLimitsInput;
1318
+ /** `adopt-users` creates unknown user ids on first use. Default `strict`. */
1319
+ identity?: IdentityMode;
1320
+ /** Users and orders every namespace starts with, re-applied on each reset. */
1321
+ fixtures?: JunctionFixtures;
1322
+ /** Requests each namespace's journal keeps (`GET /__admin/requests`). Default 1000. */
1323
+ journalSize?: number;
985
1324
  /** Deliver signed webhooks here, with Svix's retry schedule. */
986
1325
  webhooks?: WebhookEndpoint;
987
1326
  /** Called in-process for every webhook event, delivered or not. */
@@ -1028,8 +1367,12 @@ declare const UNKNOWN_ZIP_ERROR_TYPE = "MOCKINGBIRD_UNKNOWN_ZIP";
1028
1367
  * optionally orders) run against both sides, comparing status codes, response
1029
1368
  * shapes, and — for the documented error bodies — exact bytes.
1030
1369
  *
1370
+ * The scenario also replays every order-scoped operation against a random unknown order
1371
+ * (each 404 body compared exactly) and, with `orders` and a corpus holding an account whose
1372
+ * `team_id_allowlist` is empty, orders through that account with and without its id.
1373
+ *
1031
1374
  * Only a sandbox team should be used: the scenario creates, and always deletes, one
1032
- * user (and, with `orders`, places and cancels one order).
1375
+ * user (and, with `orders`, places and cancels its orders).
1033
1376
  */
1034
1377
  type VerifyOptions = {
1035
1378
  realKey: string;
@@ -1089,10 +1432,22 @@ type JunctionAPIOptions = APIOptions & {
1089
1432
  */
1090
1433
  geo?: GeoMode;
1091
1434
  /**
1092
- * The team's lab accounts, replacing the built-in fixtures (and any from the corpus).
1093
- * `create_order` routes, accepts and rejects `lab_account_id` against these.
1435
+ * The team's lab accounts, replacing the built-in fixtures (and any from the corpus):
1436
+ * a list of accounts, or `{ presets: [...], accounts: [...] }`. `create_order` routes,
1437
+ * accepts and rejects `lab_account_id` against these.
1438
+ */
1439
+ labAccounts?: LabAccountLayout;
1440
+ /**
1441
+ * The team the mock answers as: `team_id` on users and orders, and the team lab-account
1442
+ * allowlists are checked against. Default: the corpus's recorded team, else a fixed id.
1094
1443
  */
1095
- labAccounts?: readonly LabAccountInput[];
1444
+ teamId?: string;
1445
+ /** Sandbox-only restrictions to enforce. Every one is off unless set here. */
1446
+ limits?: JunctionLimitsInput;
1447
+ /** `adopt-users` creates an unknown (well-formed) `user_id` on first use. Default `strict`. */
1448
+ identity?: IdentityMode;
1449
+ /** Users and orders to load into every namespace, re-applied on every `reset()`. */
1450
+ fixtures?: JunctionFixtures;
1096
1451
  };
1097
1452
  /** What a loaded corpus covers, for `/health` and startup logs. */
1098
1453
  type CorpusInfo = {
@@ -1103,6 +1458,8 @@ type CorpusInfo = {
1103
1458
  labTests: number;
1104
1459
  labAccounts: number;
1105
1460
  zips: number;
1461
+ /** The recording team, when the corpus recorded one (version 2+). */
1462
+ teamId?: string;
1106
1463
  };
1107
1464
  /** A short, stable name for a corpus: its recording date plus a digest of what it holds. */
1108
1465
  declare const corpusLabel: (corpus: SealedCorpus) => string;
@@ -1111,6 +1468,10 @@ declare class JunctionAPI implements FetchAPI {
1111
1468
  readonly sqlite: SqliteClient;
1112
1469
  private readonly service;
1113
1470
  private readonly state;
1471
+ private readonly now;
1472
+ private readonly explicitTeamId;
1473
+ private readonly fixtures;
1474
+ private readonly rateWindow;
1114
1475
  private corpus;
1115
1476
  private labAccountConfig;
1116
1477
  constructor(options?: JunctionAPIOptions);
@@ -1127,9 +1488,40 @@ declare class JunctionAPI implements FetchAPI {
1127
1488
  * recorded from a team with no accounts leaves in place).
1128
1489
  */
1129
1490
  private seedLabAccounts;
1130
- /** Replace the team's lab accounts; `undefined` restores the default. Kept across resets. */
1131
- configureLabAccounts(accounts: readonly LabAccountInput[] | undefined): StoredLabAccount[];
1491
+ /** The team this namespace answers as. */
1492
+ get teamId(): string;
1493
+ /**
1494
+ * Replace the team's lab accounts (a list, or `{ presets, accounts }`); `undefined`
1495
+ * restores the default. Kept across `reset()`, per namespace.
1496
+ */
1497
+ configureLabAccounts(accounts: LabAccountLayout | undefined): StoredLabAccount[];
1132
1498
  labAccounts(): StoredLabAccount[];
1499
+ /** Apply one change to the effective account list and keep it as this namespace's config. */
1500
+ private editLabAccounts;
1501
+ /** Add one account. Throws `LabAccountConflict` when the id is taken. Kept across resets. */
1502
+ addLabAccount(input: LabAccountInput | StoredLabAccount): StoredLabAccount;
1503
+ /** Add a named preset (see `LAB_ACCOUNT_PRESETS`); `undefined` for an unknown name. */
1504
+ addLabAccountPreset(name: string, id?: string): StoredLabAccount | undefined;
1505
+ /** Merge fields into an account; `undefined` when there is none with that id. */
1506
+ patchLabAccount(id: string, patch: Partial<LabAccountInput>): StoredLabAccount | undefined;
1507
+ removeLabAccount(id: string): boolean;
1508
+ /** The sandbox limits this namespace enforces. Every one is off unless configured. */
1509
+ get limits(): JunctionLimits;
1510
+ /** Change some limits (`null` lifts a numeric one); kept across `reset()`. */
1511
+ configureLimits(input: JunctionLimitsInput): JunctionLimits;
1512
+ get identity(): IdentityMode;
1513
+ set identity(mode: IdentityMode);
1514
+ /** Insert users with chosen ids, all or none. Throws `FixtureError` (400/404/409). */
1515
+ insertUsers(users: readonly UserFixture[]): UserRecord[];
1516
+ /** Remove a user outright, leaving no deletion tombstone. */
1517
+ hardDeleteUser(userId: string): boolean;
1518
+ /** Insert orders, optionally already in a status. No webhook fires unless asked. */
1519
+ insertOrders(orders: readonly OrderFixture[], options?: InsertOptions): OrderRecord[];
1520
+ /** Load users, then orders, in one call. */
1521
+ importFixtures(fixtures: JunctionFixtures, options?: InsertOptions): {
1522
+ users: UserRecord[];
1523
+ orders: OrderRecord[];
1524
+ };
1133
1525
  corpusInfo(): CorpusInfo | undefined;
1134
1526
  get geoMode(): GeoMode;
1135
1527
  set geoMode(mode: GeoMode);
@@ -1154,6 +1546,11 @@ declare class JunctionAPI implements FetchAPI {
1154
1546
  webhookEvents(): JunctionWebhookEvent[];
1155
1547
  webhookDeliveryAttempts(): WebhookDeliveryAttempt[];
1156
1548
  }
1549
+ /** Raised by `addLabAccount` for an id the namespace already has. */
1550
+ declare class LabAccountConflict extends Error {
1551
+ readonly id: string;
1552
+ constructor(id: string);
1553
+ }
1157
1554
 
1158
- export { AVAILABILITY_ADDRESS, AVAILABILITY_START_DATE, COVERAGE_ZIPS, DEFAULT_JUNCTION_BASE_URL, FAULT_PRESETS, JUNCTION_NAMESPACE, JunctionAPI, ORDER_STATUSES_BY_METHOD, PHLEBOTOMY_AVAILABILITY_ZIPS, PSC_AVAILABILITY_ZIPS, PSC_LAB_IDS, RESULT_FIXTURES, SANDBOX_KEY_PREFIXES, SEALED_CORPUS_VERSION, TEAM_LAB_ACCOUNTS, TRANSITION_ALIASES, UNKNOWN_ZIP_ERROR_TYPE, UNKNOWN_ZIP_STATUS, US_STATES, corpusLabel, createRuntime, createWebhookDispatcher, diffCorpus, document, fingerprintCorpus, isSandboxKey, labAccountFromInput, observationCacheKey, operationIds, parseSealedCorpus, prefetchCoverageObservations, pullCorpus, reshapeCoverageGeoCommand, resolveTransition, signSvix, supportedOperationIds, verifyAgainstReal, verifySvix };
1159
- export type { CorpusDiff, CorpusInfo, Divergence, FetchAPI, GeoMode, GetCacheEntry, JunctionAPIOptions, JunctionAdminOptions, JunctionRuntime, JunctionRuntimeOptions, JunctionWebhookEvent, JunctionWebhookOptions, LabAccountDelegatedFlow, LabAccountInput, LabAccountRecord, LabAccountStatus, OperationId, OrderRecord, PullCorpusOptions, ResultFixture, SealedCorpus, SeedObservations, SeedReport, SeedSource, SetDiff, SqliteClient, StoredLabAccount, SupportedOperationId, VerifyOptions, VerifyReport, WebhookAttempt, WebhookDelivery, WebhookDispatcher, WebhookEndpoint, WebhookPublisher };
1555
+ export { AVAILABILITY_ADDRESS, AVAILABILITY_START_DATE, COVERAGE_ZIPS, DEFAULT_JUNCTION_BASE_URL, DEFAULT_LIMITS, DELEGATED_ACCOUNT_STATES, FAULT_PRESETS, FixtureError, IDENTITY_MODES, JUNCTION_NAMESPACE, JunctionAPI, KNOWN_HEADER, LAB_ACCOUNT_PRESETS, LabAccountConflict, MISS_HEADER, MOCK_TEAM_ID, ORDER_NOT_FOUND, ORDER_STATUSES_BY_METHOD, OTHER_TEAM_ID, PHLEBOTOMY_AVAILABILITY_ZIPS, PLATFORM_ACCOUNT_STATES, PSC_AVAILABILITY_ZIPS, PSC_LAB_IDS, RESULT_FIXTURES, SANDBOX_KEY_PREFIXES, SEALED_CORPUS_VERSION, SUPPORTED_SEALED_CORPUS_VERSIONS, TEAM_LAB_ACCOUNTS, TRANSITION_ALIASES, UNKNOWN_ZIP_ERROR_TYPE, UNKNOWN_ZIP_STATUS, US_STATES, corpusLabel, createRuntime, createWebhookDispatcher, diffCorpus, document, fingerprintCorpus, isLinkedToTeam, isSandboxKey, labAccountFromInput, observationCacheKey, operationIds, parseSealedCorpus, prefetchCoverageObservations, presetAccountId, pullCorpus, reshapeCoverageGeoCommand, resolveTransition, sandboxUserQuotaBody, signSvix, supportedOperationIds, verifyAgainstReal, verifySvix };
1556
+ export type { CorpusDiff, CorpusInfo, Divergence, FetchAPI, GeoMode, GetCacheEntry, IdentityMode, InsertOptions, JunctionAPIOptions, JunctionAdminOptions, JunctionFixtures, JunctionLimits, JunctionLimitsInput, JunctionRuntime, JunctionRuntimeOptions, JunctionWebhookEvent, JunctionWebhookOptions, LabAccountDelegatedFlow, LabAccountInput, LabAccountLayout, LabAccountRecord, LabAccountStatus, OperationId, OrderFixture, OrderRecord, PullCorpusOptions, ResultFixture, SealedCorpus, SeedObservations, SeedReport, SeedSource, SetDiff, SqliteClient, StoredLabAccount, SupportedOperationId, UserFixture, UserRecord, VerifyOptions, VerifyReport, WebhookAttempt, WebhookDelivery, WebhookDispatcher, WebhookEndpoint, WebhookPublisher };