@crvouga/mockingbird-service-junction 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -5
- package/README.md +222 -21
- package/dist/{chunk-MD4KYEIM.js → chunk-C2UGIPPM.js} +2 -2
- package/dist/{chunk-4C6VYRJN.js → chunk-ISDNA2TU.js} +8 -3
- package/dist/chunk-ISDNA2TU.js.map +7 -0
- package/dist/{chunk-KKNULV7X.js → chunk-KLBGX23P.js} +76 -8
- package/dist/chunk-KLBGX23P.js.map +7 -0
- package/dist/{chunk-MA3HSUVD.js → chunk-NFWUEPW4.js} +1856 -778
- package/dist/chunk-NFWUEPW4.js.map +7 -0
- package/dist/cli.js +4 -4
- package/dist/corpus.d.ts +10 -2
- package/dist/corpus.js +2 -2
- package/dist/index.d.ts +322 -49
- package/dist/index.js +34 -2
- package/dist/server.d.ts +242 -10
- package/dist/server.js +4 -4
- package/package.json +1 -1
- package/dist/chunk-4C6VYRJN.js.map +0 -7
- package/dist/chunk-KKNULV7X.js.map +0 -7
- package/dist/chunk-MA3HSUVD.js.map +0 -7
- /package/dist/{chunk-MD4KYEIM.js.map → chunk-C2UGIPPM.js.map} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SEALED_CORPUS_VERSION
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-ISDNA2TU.js";
|
|
4
4
|
|
|
5
5
|
// ../core/dist/clock.js
|
|
6
6
|
var createClock = (source = Date.now) => {
|
|
@@ -94,6 +94,11 @@ var Collection = class {
|
|
|
94
94
|
const result = this.sqlite.prepare("DELETE FROM mockingbird_records WHERE namespace = ? AND collection = ? AND id = ?").run(this.namespace, this.name, id);
|
|
95
95
|
return result.changes > 0;
|
|
96
96
|
}
|
|
97
|
+
/** How many records the collection holds, without reading them. */
|
|
98
|
+
count() {
|
|
99
|
+
const row = this.sqlite.prepare("SELECT COUNT(*) AS n FROM mockingbird_records WHERE namespace = ? AND collection = ?").get(this.namespace, this.name);
|
|
100
|
+
return Number(row?.n ?? 0);
|
|
101
|
+
}
|
|
97
102
|
list(options = {}) {
|
|
98
103
|
const rows = this.sqlite.prepare("SELECT id, seq, value FROM mockingbird_records WHERE namespace = ? AND collection = ?").all(this.namespace, this.name);
|
|
99
104
|
const out = [];
|
|
@@ -189,10 +194,10 @@ var createControlPlane = (context) => {
|
|
|
189
194
|
if (body.reset === true)
|
|
190
195
|
context.clock.reset();
|
|
191
196
|
if (body.set !== void 0) {
|
|
192
|
-
const
|
|
193
|
-
if (
|
|
197
|
+
const instant2 = parseInstant(body.set);
|
|
198
|
+
if (instant2 === void 0)
|
|
194
199
|
return adminError(400, "set: expected epoch ms or ISO-8601");
|
|
195
|
-
context.clock.set(
|
|
200
|
+
context.clock.set(instant2);
|
|
196
201
|
}
|
|
197
202
|
if (body.advance !== void 0) {
|
|
198
203
|
const delta = parseDuration(body.advance);
|
|
@@ -243,6 +248,35 @@ var createControlPlane = (context) => {
|
|
|
243
248
|
return json(200, { status: "ok", id: params.id, namespace });
|
|
244
249
|
},
|
|
245
250
|
"DELETE /snapshots/:id": ({ params }) => snapshots.delete(params.id) ? json(200, { status: "ok" }) : adminError(404, `no snapshot ${params.id}`),
|
|
251
|
+
"GET /requests": ({ url, namespace }) => {
|
|
252
|
+
const status = url.searchParams.get("status");
|
|
253
|
+
const since = url.searchParams.get("since");
|
|
254
|
+
const limit = url.searchParams.get("limit");
|
|
255
|
+
const sinceMs = since === null ? void 0 : parseInstant(/^\d+$/.test(since) ? Number(since) : since);
|
|
256
|
+
if (since !== null && sinceMs === void 0) {
|
|
257
|
+
return adminError(400, "since: expected epoch ms or ISO-8601");
|
|
258
|
+
}
|
|
259
|
+
if (status !== null && !/^\d{3}$/.test(status))
|
|
260
|
+
return adminError(400, "status: expected an HTTP status");
|
|
261
|
+
if (limit !== null && !/^\d+$/.test(limit))
|
|
262
|
+
return adminError(400, "limit: expected a count");
|
|
263
|
+
const operationId = url.searchParams.get("operationId");
|
|
264
|
+
const everyNamespace = url.searchParams.get("all") === "1";
|
|
265
|
+
return json(200, {
|
|
266
|
+
size: context.journal.size,
|
|
267
|
+
requests: context.journal.list({
|
|
268
|
+
...everyNamespace ? {} : { namespace },
|
|
269
|
+
...operationId !== null ? { operationId } : {},
|
|
270
|
+
...status !== null ? { status: Number(status) } : {},
|
|
271
|
+
...sinceMs !== void 0 ? { since: sinceMs } : {},
|
|
272
|
+
...limit !== null ? { limit: Number(limit) } : {}
|
|
273
|
+
})
|
|
274
|
+
});
|
|
275
|
+
},
|
|
276
|
+
"DELETE /requests": ({ url, namespace }) => {
|
|
277
|
+
context.journal.clear(url.searchParams.get("all") === "1" ? void 0 : namespace);
|
|
278
|
+
return json(200, { status: "ok" });
|
|
279
|
+
},
|
|
246
280
|
"GET /metrics": () => json(200, context.metrics.report()),
|
|
247
281
|
"DELETE /metrics": () => {
|
|
248
282
|
context.metrics.reset();
|
|
@@ -693,6 +727,57 @@ var IdSequence = class {
|
|
|
693
727
|
}
|
|
694
728
|
};
|
|
695
729
|
|
|
730
|
+
// ../core/dist/journal.js
|
|
731
|
+
var DEFAULT_JOURNAL_SIZE = 1e3;
|
|
732
|
+
var createJournal = (size = DEFAULT_JOURNAL_SIZE) => {
|
|
733
|
+
const capacity = Math.max(0, Math.floor(size));
|
|
734
|
+
const rings = /* @__PURE__ */ new Map();
|
|
735
|
+
let sequence = 0;
|
|
736
|
+
const order = /* @__PURE__ */ new WeakMap();
|
|
737
|
+
const inOrder = (ring) => ring.entries.length < capacity ? ring.entries : [...ring.entries.slice(ring.next), ...ring.entries.slice(0, ring.next)];
|
|
738
|
+
return {
|
|
739
|
+
size: capacity,
|
|
740
|
+
record(entry) {
|
|
741
|
+
if (capacity === 0)
|
|
742
|
+
return;
|
|
743
|
+
order.set(entry, sequence++);
|
|
744
|
+
let ring = rings.get(entry.namespace);
|
|
745
|
+
if (!ring) {
|
|
746
|
+
ring = { entries: [], next: 0 };
|
|
747
|
+
rings.set(entry.namespace, ring);
|
|
748
|
+
}
|
|
749
|
+
if (ring.entries.length < capacity)
|
|
750
|
+
ring.entries.push(entry);
|
|
751
|
+
else {
|
|
752
|
+
ring.entries[ring.next] = entry;
|
|
753
|
+
ring.next = (ring.next + 1) % capacity;
|
|
754
|
+
}
|
|
755
|
+
},
|
|
756
|
+
list(query = {}) {
|
|
757
|
+
const source = query.namespace !== void 0 ? inOrder(rings.get(query.namespace) ?? { entries: [], next: 0 }) : [...rings.values()].flatMap(inOrder).sort((a, b) => (order.get(a) ?? 0) - (order.get(b) ?? 0));
|
|
758
|
+
const matched = source.filter((entry) => (query.operationId === void 0 || entry.operationId === query.operationId) && (query.status === void 0 || entry.status === query.status) && (query.since === void 0 || Date.parse(entry.at) >= query.since));
|
|
759
|
+
return query.limit !== void 0 ? matched.slice(-Math.max(0, query.limit)) : matched;
|
|
760
|
+
},
|
|
761
|
+
clear(namespace) {
|
|
762
|
+
if (namespace === void 0)
|
|
763
|
+
rings.clear();
|
|
764
|
+
else
|
|
765
|
+
rings.delete(namespace);
|
|
766
|
+
}
|
|
767
|
+
};
|
|
768
|
+
};
|
|
769
|
+
var notes = /* @__PURE__ */ new WeakMap();
|
|
770
|
+
var annotateResponse = (response, extra) => {
|
|
771
|
+
const existing = notes.get(response);
|
|
772
|
+
notes.set(response, {
|
|
773
|
+
...existing,
|
|
774
|
+
...extra,
|
|
775
|
+
...existing?.ids || extra.ids ? { ids: { ...existing?.ids, ...extra.ids } } : {}
|
|
776
|
+
});
|
|
777
|
+
return response;
|
|
778
|
+
};
|
|
779
|
+
var responseNotes = (response) => notes.get(response);
|
|
780
|
+
|
|
696
781
|
// ../core/dist/metrics.js
|
|
697
782
|
var createMetrics = () => {
|
|
698
783
|
let requests = 0;
|
|
@@ -952,7 +1037,11 @@ var restoreNamespace = (sqlite, namespace, snapshot) => {
|
|
|
952
1037
|
});
|
|
953
1038
|
};
|
|
954
1039
|
|
|
1040
|
+
// ../core/dist/version.js
|
|
1041
|
+
var PACKAGE_VERSION = true ? "0.3.0" : UNRELEASED_VERSION;
|
|
1042
|
+
|
|
955
1043
|
// ../core/dist/runtime.js
|
|
1044
|
+
var MOCKINGBIRD_HEADER = "x-mockingbird";
|
|
956
1045
|
var DEFAULT_NAMESPACE = "default";
|
|
957
1046
|
var NAMESPACE_PATTERN = /^[A-Za-z0-9_.-]{1,64}$/;
|
|
958
1047
|
var operationMatcher = (document2) => {
|
|
@@ -970,6 +1059,8 @@ var createRuntime = (options) => {
|
|
|
970
1059
|
const rng = createRng(options.seed ?? 0);
|
|
971
1060
|
const faults = createFaultRegistry(createRng(options.seed ?? 0));
|
|
972
1061
|
const metrics = createMetrics();
|
|
1062
|
+
const journal = createJournal(options.journalSize ?? DEFAULT_JOURNAL_SIZE);
|
|
1063
|
+
const version = options.version ?? PACKAGE_VERSION;
|
|
973
1064
|
const instances = /* @__PURE__ */ new Map();
|
|
974
1065
|
const operationIdFor = options.document ? operationMatcher(options.document) : () => void 0;
|
|
975
1066
|
const storageNamespace = (name) => name === DEFAULT_NAMESPACE ? options.name : `${options.name}:${name}`;
|
|
@@ -1016,6 +1107,7 @@ var createRuntime = (options) => {
|
|
|
1016
1107
|
clock,
|
|
1017
1108
|
faults,
|
|
1018
1109
|
metrics,
|
|
1110
|
+
journal,
|
|
1019
1111
|
rng,
|
|
1020
1112
|
instance,
|
|
1021
1113
|
namespaces: () => [...instances.keys()].sort(),
|
|
@@ -1023,14 +1115,26 @@ var createRuntime = (options) => {
|
|
|
1023
1115
|
snapshot,
|
|
1024
1116
|
restore,
|
|
1025
1117
|
fetch: async (request2) => {
|
|
1118
|
+
const namespace = control.namespaceOf(request2);
|
|
1119
|
+
const stamp = (response2) => {
|
|
1120
|
+
const value = NAMESPACE_PATTERN.test(namespace) ? `${options.name}@${version}; ns=${namespace}` : `${options.name}@${version}`;
|
|
1121
|
+
try {
|
|
1122
|
+
response2.headers.set(MOCKINGBIRD_HEADER, value);
|
|
1123
|
+
return response2;
|
|
1124
|
+
} catch {
|
|
1125
|
+
const copy = new Response(response2.body, response2);
|
|
1126
|
+
copy.headers.set(MOCKINGBIRD_HEADER, value);
|
|
1127
|
+
return copy;
|
|
1128
|
+
}
|
|
1129
|
+
};
|
|
1026
1130
|
const handled = await control.handle(request2);
|
|
1027
1131
|
if (handled)
|
|
1028
|
-
return handled;
|
|
1132
|
+
return stamp(handled);
|
|
1029
1133
|
const started = performance.now();
|
|
1030
1134
|
const url = new URL(request2.url);
|
|
1031
|
-
const namespace = control.namespaceOf(request2);
|
|
1032
1135
|
const operationId = operationIdFor(request2, url.pathname);
|
|
1033
|
-
const log = (status, faultId) => {
|
|
1136
|
+
const log = (status, faultId, response2) => {
|
|
1137
|
+
const noted = response2 ? responseNotes(response2) : void 0;
|
|
1034
1138
|
const entry = {
|
|
1035
1139
|
service: options.name,
|
|
1036
1140
|
namespace,
|
|
@@ -1040,19 +1144,22 @@ var createRuntime = (options) => {
|
|
|
1040
1144
|
status,
|
|
1041
1145
|
durationMs: Math.round((performance.now() - started) * 100) / 100,
|
|
1042
1146
|
unmatched: options.document !== void 0 && operationId === void 0,
|
|
1043
|
-
...faultId !== void 0 ? { faultId } : {}
|
|
1147
|
+
...faultId !== void 0 ? { faultId } : {},
|
|
1148
|
+
...noted?.ids && Object.keys(noted.ids).length > 0 ? { ids: noted.ids } : {},
|
|
1149
|
+
...noted?.adopted ? { adopted: true } : {}
|
|
1044
1150
|
};
|
|
1045
1151
|
metrics.record(entry);
|
|
1152
|
+
journal.record({ ...entry, at: new Date(clock.now()).toISOString() });
|
|
1046
1153
|
options.onLog?.(entry);
|
|
1047
1154
|
};
|
|
1048
1155
|
if (!NAMESPACE_PATTERN.test(namespace)) {
|
|
1049
1156
|
log(400);
|
|
1050
|
-
return new Response(JSON.stringify({
|
|
1157
|
+
return stamp(new Response(JSON.stringify({
|
|
1051
1158
|
error: {
|
|
1052
1159
|
type: "mockingbird_admin",
|
|
1053
1160
|
message: `${NAMESPACE_HEADER} must match ${NAMESPACE_PATTERN}`
|
|
1054
1161
|
}
|
|
1055
|
-
}), { status: 400, headers: { "content-type": "application/json" } });
|
|
1162
|
+
}), { status: 400, headers: { "content-type": "application/json" } }));
|
|
1056
1163
|
}
|
|
1057
1164
|
const faulted = await faults.take({
|
|
1058
1165
|
operationId,
|
|
@@ -1062,11 +1169,11 @@ var createRuntime = (options) => {
|
|
|
1062
1169
|
});
|
|
1063
1170
|
if (faulted) {
|
|
1064
1171
|
log(faulted.response.status, faulted.id);
|
|
1065
|
-
return faulted.response;
|
|
1172
|
+
return stamp(faulted.response);
|
|
1066
1173
|
}
|
|
1067
1174
|
const response = await instance(namespace).fetch(request2);
|
|
1068
|
-
log(response.status);
|
|
1069
|
-
return response;
|
|
1175
|
+
log(response.status, void 0, response);
|
|
1176
|
+
return stamp(response);
|
|
1070
1177
|
}
|
|
1071
1178
|
};
|
|
1072
1179
|
const control = createControlPlane({
|
|
@@ -1075,6 +1182,7 @@ var createRuntime = (options) => {
|
|
|
1075
1182
|
clock,
|
|
1076
1183
|
faults,
|
|
1077
1184
|
metrics,
|
|
1185
|
+
journal,
|
|
1078
1186
|
defaultNamespace: DEFAULT_NAMESPACE,
|
|
1079
1187
|
namespaces: runtime.namespaces,
|
|
1080
1188
|
reset,
|
|
@@ -1087,11 +1195,6 @@ var createRuntime = (options) => {
|
|
|
1087
1195
|
return runtime;
|
|
1088
1196
|
};
|
|
1089
1197
|
|
|
1090
|
-
// src/generated/openapi.ts
|
|
1091
|
-
var document = JSON.parse(`{"openapi":"3.1.0","info":{"title":"Junction API (Mockingbird subset)","description":"Stateful mock subset of the Junction (Vital) API.\\nDocs: https://docs.junction.com/\\nAuth: https://docs.junction.com/api-details/junction-api\\nCreate user: https://docs.junction.com/api-reference/user/create-user\\nGet user: https://docs.junction.com/api-reference/user/get-user\\nDelete user: https://docs.junction.com/api-reference/user/delete-user\\nResolve user: https://docs.junction.com/api-reference/user/resolve-user\\nUpdate user: https://docs.junction.com/api-reference/user/patch-user\\nGet users: https://docs.junction.com/api-reference/user/get-users\\nCreate order: https://docs.junction.com/api-reference/lab-testing/create-order\\nGet order: https://docs.junction.com/api-reference/lab-testing/get-order\\nGet orders: https://docs.junction.com/api-reference/lab-testing/get-orders\\nGet order transaction: https://docs.junction.com/api-reference/lab-testing/order-transactions/get-order-transaction\\nGet order transaction result: https://docs.junction.com/api-reference/lab-testing/results/get-order-transaction-results\\nLab tests: https://docs.junction.com/api-reference/lab-testing/tests-paginated\\nAppointment availability: https://docs.junction.com/api-reference/lab-testing/appointments/get-appointment-availability\\nBook appointment: https://docs.junction.com/api-reference/lab-testing/appointments/book-appointment\\nGet appointment: https://docs.junction.com/api-reference/lab-testing/appointments/get-appointment\\nReschedule appointment: https://docs.junction.com/api-reference/lab-testing/appointments/reschedule-appointment\\nCancel appointment: https://docs.junction.com/api-reference/lab-testing/appointments/cancel-appointment\\nAppointment cancellation reasons: https://docs.junction.com/api-reference/lab-testing/appointments/get-appointment-cancellation-reasons\\nArea info: https://docs.junction.com/api-reference/lab-testing/service-areas/get-area-info\\nPSC info: https://docs.junction.com/api-reference/lab-testing/service-areas/get-psc-info\\nLab locations: https://docs.junction.com/api-reference/lab-testing/service-areas/get-lab-locations\\nRaw results: https://docs.junction.com/api-reference/lab-testing/results/get-lab-results\\nResult metadata: https://docs.junction.com/api-reference/lab-testing/results/get-lab-results-metadata\\nResult PDF: https://docs.junction.com/api-reference/lab-testing/results/get-lab-result-pdf\\nRequisition form PDF: https://docs.junction.com/api-reference/lab-testing/orders/get-requisition-form\\nList labs: https://docs.junction.com/api-reference/lab-testing/tests/get-labs\\nTest markers: https://docs.junction.com/api-reference/lab-testing/tests/get-markers-for-lab-test\\nOrder-set markers: https://docs.junction.com/api-reference/lab-testing/results/get-order-set-markers\\nLatest user info: https://docs.junction.com/api-reference/user/get-latest-user-info\\n","version":"0.4.758","x-mockingbird-upstream":{"docs":"https://docs.junction.com/","note":"Hand-authored subset from Junction public OpenAPI snippets in the docs."}},"servers":[{"url":"https://api.sandbox.us.junction.com"}],"security":[{"apiKeyAuth":[]}],"paths":{"/v2/user":{"post":{"operationId":"create_user_v2_user_post","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserCreateBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingUser"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientUserIDConflictResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"operationId":"get_teams_users_v2_user_get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedUsersResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"500":{"description":"Internal Server Error","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/v2/user/{user_id}":{"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"user","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_user_v2_user__user_id__get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingUser"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"operationId":"delete_user_v2_user__user_id__delete","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSuccessResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"operationId":"patch_user_v2_user__user_id__patch","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserPatchBody"}}}},"responses":{"204":{"description":"Successful Response"},"400":{"description":"Nothing to patch","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/user/resolve/{client_user_id}":{"parameters":[{"name":"client_user_id","in":"path","required":true,"schema":{"type":"string","minLength":1}}],"get":{"operationId":"get_user_by_client_user_id_v2_user_resolve__client_user_id__get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ClientFacingUser"},{"$ref":"#/components/schemas/PaginatedUsersResponse"}]}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/user/{user_id}/info":{"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"user","missing":"00000000-0000-4000-8000-000000000000"}}}],"patch":{"operationId":"patch_user_info_v2_user__user_id__info_patch","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserInfoPatchBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserInfo"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/user/{user_id}/info/latest":{"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"user","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_latest_user_info_user_v2_user__user_id__info_latest_get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserInfo"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/lab_test":{"get":{"operationId":"get_paginated_lab_tests_for_team_v3_lab_test_get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LabTestResourcesResponse"}}}}}}},"/v3/lab_test/lab_account":{"get":{"operationId":"get_team_lab_accounts_v3_lab_test_lab_account_get","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"lab-account inventory is fixture-owned; the mock models the documented shape, filters and routing rules, not a live account inventory"}},"parameters":[{"name":"lab_account_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/LabAccountStatus"},{"type":"null"}]}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetTeamLabAccountsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/lab_tests/{lab_test_id}":{"parameters":[{"name":"lab_test_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"lab_test","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_lab_test_for_team_v3_lab_tests__lab_test_id__get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingLabTest"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/lab_tests/labs":{"get":{"operationId":"get_labs_v3_lab_tests_labs_get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingLab"}}}}}}}},"/v3/lab_tests/{lab_test_id}/markers":{"parameters":[{"name":"lab_test_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"lab_test","missing":"00000000-0000-4000-8000-000000000000"}}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"provider_id","in":"query","required":false,"schema":{"type":"string"}}],"get":{"operationId":"get_markers_for_lab_test_v3_lab_tests__lab_test_id__markers_get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMarkersResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/lab_tests/list_order_set_markers":{"post":{"operationId":"list_order_set_markers_v3_lab_tests_list_order_set_markers_post","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOrderSetMarkersRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMarkersResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order":{"post":{"operationId":"create_order_v3_order_post","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrderRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostOrderResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"500":{"description":"Internal Server Error"}}}},"/v3/order/area/info":{"get":{"operationId":"get_area_info_v3_order_area_info_get","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"central_labs presence, within_radius counts and getlabs market coverage are provider-owned geo data that a mock cannot replicate per-zip; covered by the client-parity scenario shape checks instead"}},"parameters":[{"name":"zip_code","in":"query","required":true,"schema":{"type":"string","pattern":"^\\\\d{5}(?:-?\\\\d{4})?$"}},{"name":"radius","in":"query","required":false,"schema":{"$ref":"#/components/schemas/AllowedRadius"}},{"name":"lab_account_id","in":"query","required":false,"description":"Lab Account ID to use for availability checks","schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AreaInfo"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/psc/info":{"get":{"operationId":"get_psc_info_v3_order_psc_info_get","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"patient_service_centers are real site inventories per zip (thousands of sites, result-capped at 30) that a fixture mock cannot replicate per-zip; covered by the client-parity scenario shape checks instead"}},"parameters":[{"name":"zip_code","in":"query","required":true,"schema":{"type":"string","pattern":"^\\\\d{5}$"}},{"name":"lab_id","in":"query","required":true,"schema":{"type":"integer"}},{"name":"radius","in":"query","required":false,"schema":{"$ref":"#/components/schemas/AllowedRadius"}},{"name":"capabilities","in":"query","required":false,"schema":{"type":"array","items":{"$ref":"#/components/schemas/LabLocationCapability"}}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PscInfo"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/phlebotomy/appointment/availability":{"post":{"operationId":"get_phlebotomy_appointment_availability_v3_order_phlebotomy_appointment_availability_post","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"availability slots are provider-side data whose values shift between sandbox calls; covered by the mock-internal scheduling property suite instead"}},"parameters":[{"name":"start_date","in":"query","required":false,"schema":{"type":"string","format":"date"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsAddress"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppointmentAvailabilitySlots"}}}},"400":{"description":"Availability not bookable for this address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"No availability found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/phlebotomy/appointment/cancellation-reasons":{"get":{"operationId":"get_phlebotomy_appointment_cancellation_reason_v3_order_phlebotomy_appointment_cancellation_reasons_get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingAppointmentCancellationReason"}}}}}}}},"/v3/order/psc/appointment/availability":{"post":{"operationId":"get_psc_appointment_availability_v3_order_psc_appointment_availability_post","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"availability slots are provider-side data whose values shift between sandbox calls; covered by the mock-internal scheduling property suite instead"}},"parameters":[{"name":"lab","in":"query","required":true,"schema":{"$ref":"#/components/schemas/AppointmentPscLabs"}},{"name":"start_date","in":"query","required":false,"schema":{"type":"string","format":"date"}},{"name":"site_codes","in":"query","required":false,"schema":{"type":"string","description":"JSON-encoded array of site codes"}},{"name":"zip_code","in":"query","required":false,"schema":{"type":"string"}},{"name":"radius","in":"query","required":false,"schema":{"$ref":"#/components/schemas/AllowedRadius"}},{"name":"allow_stale","in":"query","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppointmentAvailabilitySlots"}}}},"400":{"description":"Availability not bookable for this address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"No slots found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/psc/appointment/cancellation-reasons":{"get":{"operationId":"get_psc_appointment_cancellation_reason_v3_order_psc_appointment_cancellation_reasons_get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingAppointmentCancellationReason"}}}}}}}},"/v3/order/{order_id}/phlebotomy/appointment":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_get","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"appointment payloads embed provider-side slot data; covered by the mock-internal scheduling property suite instead"}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingAppointment"}}}},"404":{"description":"No appointment for this order","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/phlebotomy/appointment/book":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"post":{"operationId":"book_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_book_post","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"booking depends on live provider slot state; covered by the mock-internal scheduling property suite instead"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppointmentBookingRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingAppointment"}}}},"400":{"description":"Booking failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"Order not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/phlebotomy/appointment/reschedule":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"patch":{"operationId":"reschedule_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_reschedule_patch","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"rescheduling depends on live provider slot state; covered by the mock-internal scheduling property suite instead"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppointmentRescheduleRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingAppointment"}}}},"400":{"description":"Invalid or expired booking key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"No appointment for this order","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/phlebotomy/appointment/cancel":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"patch":{"operationId":"cancel_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_cancel_patch","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"cancellation depends on live provider appointment state; covered by the mock-internal scheduling property suite instead"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhlebotomyAppointmentCancelRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingAppointment"}}}},"400":{"description":"Invalid cancellation reason","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"No appointment for this order","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/psc/appointment":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_psc_appointment_v3_order__order_id__psc_appointment_get","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"appointment payloads embed provider-side slot data; covered by the mock-internal scheduling property suite instead"}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingAppointment"}}}},"404":{"description":"No appointment for this order","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/psc/appointment/book":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"post":{"operationId":"book_psc_appointment_v3_order__order_id__psc_appointment_book_post","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"booking depends on live provider slot state; covered by the mock-internal scheduling property suite instead"}},"parameters":[{"name":"x-idempotency-key","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PscAppointmentBookingRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingAppointment"}}}},"400":{"description":"Booking failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"Order not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/psc/appointment/reschedule":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"patch":{"operationId":"reschedule_psc_appointment_v3_order__order_id__psc_appointment_reschedule_patch","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"rescheduling depends on live provider slot state; covered by the mock-internal scheduling property suite instead"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppointmentRescheduleRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingAppointment"}}}},"400":{"description":"Invalid or expired booking key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"No appointment for this order","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/psc/appointment/cancel":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"patch":{"operationId":"cancel_psc_appointment_v3_order__order_id__psc_appointment_cancel_patch","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"cancellation depends on live provider appointment state; covered by the mock-internal scheduling property suite instead"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PscAppointmentCancelRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingAppointment"}}}},"400":{"description":"Invalid cancellation reason","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"No appointment for this order","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_order_v3_order__order_id__get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingOrder"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/cancel":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"post":{"operationId":"cancel_order_v3_order__order_id__cancel_post","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostOrderResponse"}}}},"400":{"description":"Order is not in a cancellable status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/test":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"post":{"operationId":"simulate_order_v3_order__order_id__test_post","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"name":"final_status","in":"query","required":true,"schema":{"type":"string","enum":["received.walk_in_test.ordered","received.walk_in_test.requisition_created","received.walk_in_test.requisition_bypassed","completed.walk_in_test.completed","sample_with_lab.walk_in_test.partial_results","failed.walk_in_test.sample_error","cancelled.walk_in_test.cancelled","collecting_sample.walk_in_test.appointment_pending","collecting_sample.walk_in_test.appointment_scheduled","collecting_sample.walk_in_test.appointment_cancelled","collecting_sample.walk_in_test.redraw_available","received.at_home_phlebotomy.ordered","received.at_home_phlebotomy.requisition_created","received.at_home_phlebotomy.requisition_bypassed","collecting_sample.at_home_phlebotomy.appointment_pending","collecting_sample.at_home_phlebotomy.appointment_scheduled","collecting_sample.at_home_phlebotomy.draw_completed","collecting_sample.at_home_phlebotomy.appointment_cancelled","completed.at_home_phlebotomy.completed","sample_with_lab.at_home_phlebotomy.partial_results","cancelled.at_home_phlebotomy.cancelled","failed.at_home_phlebotomy.sample_error","received.testkit.ordered","received.testkit.awaiting_registration","received.testkit.requisition_created","received.testkit.requisition_bypassed","received.testkit.registered","collecting_sample.testkit.transit_customer","collecting_sample.testkit.out_for_delivery","collecting_sample.testkit.with_customer","collecting_sample.testkit.transit_lab","sample_with_lab.testkit.delivered_to_lab","sample_with_lab.testkit.lab_processing_blocked","completed.testkit.completed","failed.testkit.failure_to_deliver_to_customer","failed.testkit.failure_to_deliver_to_lab","failed.testkit.sample_error","failed.testkit.lost","cancelled.testkit.cancelled","cancelled.testkit.do_not_process","collecting_sample.testkit.problem_in_transit_customer","collecting_sample.testkit.problem_in_transit_lab","received.on_site_collection.ordered","received.on_site_collection.requisition_created","received.on_site_collection.requisition_bypassed","sample_with_lab.on_site_collection.draw_completed","completed.on_site_collection.completed","cancelled.on_site_collection.cancelled","sample_with_lab.on_site_collection.partial_results","failed.on_site_collection.sample_error","completed.walk_in_test.corrected","completed.at_home_phlebotomy.corrected","completed.on_site_collection.corrected","completed.testkit.corrected"]}},{"name":"delay","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Seconds to defer the status transition"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimulationFlags"}}}},"responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string","examples":["Success"]}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/result":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_result_raw_v3_order__order_id__result_get","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"results carry provider-side specimen data; covered by the mock-internal results property suite instead"}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LabResultsRaw"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/result/metadata":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_result_metadata_v3_order__order_id__result_metadata_get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LabResultsMetadata"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/result/pdf":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_result_pdf_v3_order__order_id__result_pdf_get","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"PDF bytes are provider-rendered; compared by shape (byteLength) only in the scenario script"}},"responses":{"200":{"description":"Successful Response","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/requisition/pdf":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_order_requisition_pdf_v3_order__order_id__requisition_pdf_get","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"PDF bytes are provider-rendered; compared by shape (byteLength) only in the scenario script"}},"responses":{"200":{"description":"Successful Response","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/orders":{"get":{"operationId":"get_orders_v3_orders_get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"name":"user_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"user","missing":"00000000-0000-4000-8000-000000000000"}}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetOrdersResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order_transaction/{transaction_id}":{"parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order_transaction","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_order_transaction_v3_order_transaction__transaction_id__get","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"order transactions are not available to the sandbox team (feature not available)"}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetOrderTransactionResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order_transaction/{transaction_id}/result":{"parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order_transaction","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_order_transaction_result_v3_order_transaction__transaction_id__result_get","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"lab results are not available to the sandbox team (feature not available)"}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LabResultsRaw"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"securitySchemes":{"apiKeyAuth":{"type":"apiKey","in":"header","name":"x-vital-api-key"}},"schemas":{"UserCreateBody":{"type":"object","required":["client_user_id"],"properties":{"client_user_id":{"type":"string","minLength":1,"maxLength":64,"examples":["mbr_8891","patient-1042","user.profile_52"]},"fallback_time_zone":{"type":["string","null"],"enum":["America/Los_Angeles","America/New_York","Europe/London","UTC",null]}}},"ClientFacingUser":{"type":"object","required":["user_id","team_id","client_user_id","created_on","connected_sources","fallback_time_zone"],"properties":{"user_id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"user","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"team_id":{"type":"string","format":"uuid","x-mockingbird-volatile":{"kind":"account"}},"client_user_id":{"type":"string"},"created_on":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}},"connected_sources":{"type":"array","items":{"type":"object","additionalProperties":true}},"fallback_time_zone":{"type":["object","null"],"properties":{"id":{"type":"string"},"source_slug":{"type":"string"},"updated_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}}}},"fallback_birth_date":{"type":["object","null"],"properties":{"value":{"type":"string"},"source_slug":{"type":"string"},"updated_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}}}},"ingestion_start":{"type":["string","null"]},"ingestion_end":{"type":["string","null"]}}},"UserInfoPatchBody":{"type":"object","properties":{"first_name":{"type":["string","null"]},"last_name":{"type":["string","null"]},"dob":{"type":["string","null"]},"gender":{"type":["string","null"]},"phone_number":{"type":["string","null"]},"email":{"type":["string","null"]},"address":{"type":["object","null"],"additionalProperties":true}}},"UserInfo":{"type":"object","additionalProperties":true},"ClientUserIDConflictResponse":{"type":"object","required":["detail"],"properties":{"detail":{"type":"object","required":["error_type","error_message","user_id","created_on"],"properties":{"error_type":{"type":"string"},"error_message":{"type":"string"},"user_id":{"type":"string","format":"uuid","x-mockingbird-volatile":{"kind":"id"}},"created_on":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}}}}}},"UserSuccessResponse":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean"}}},"PaginatedUsersResponse":{"type":"object","required":["users","total","offset","limit"],"properties":{"users":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingUser"}},"total":{"type":"integer"},"offset":{"type":"integer"},"limit":{"type":"integer"}}},"UserPatchBody":{"type":"object","properties":{"fallback_time_zone":{"type":["string","null"]},"fallback_birth_date":{"type":["string","null"],"format":"date"},"ingestion_start":{"type":["string","null"],"format":"date"},"ingestion_end":{"type":["string","null"],"format":"date"},"client_user_id":{"type":["string","null"]}}},"LabTestCollectionMethod":{"type":"string","enum":["testkit","walk_in_test","at_home_phlebotomy","on_site_collection"]},"LabTestSampleType":{"type":"string","enum":["dried_blood_spot","arm_collector","serum","saliva","urine","stool"]},"LabTestStatus":{"type":"string","enum":["active","pending_approval","inactive"]},"MarkerType":{"type":"string","enum":["biomarker","panel"]},"ClientFacingLab":{"type":"object","required":["id","slug","name","first_line_address","city","zipcode","collection_methods","sample_types"],"properties":{"id":{"type":"integer","x-mockingbird-volatile":{"kind":"id"}},"slug":{"type":"string"},"name":{"type":"string"},"first_line_address":{"type":"string"},"city":{"type":"string"},"zipcode":{"type":"string"},"collection_methods":{"type":"array","items":{"$ref":"#/components/schemas/LabTestCollectionMethod"}},"sample_types":{"type":"array","items":{"$ref":"#/components/schemas/LabTestSampleType"}},"logo_url":{"type":["string","null"]}}},"ClientFacingMarker":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"integer","x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"slug":{"type":"string"},"description":{"type":["string","null"]},"lab_id":{"type":["integer","null"]},"provider_id":{"type":["string","null"]},"type":{"anyOf":[{"$ref":"#/components/schemas/MarkerType"},{"type":"null"}]},"unit":{"type":["string","null"]},"price":{"type":["string","null"]},"aoe":{"anyOf":[{"type":"object","additionalProperties":true},{"type":"null"}]},"a_la_carte_enabled":{"type":"boolean","default":false},"common_tat_days":{"type":["integer","null"]},"worst_case_tat_days":{"type":["integer","null"]},"is_orderable":{"type":["boolean","null"],"default":true}}},"ClientFacingLabTest":{"type":"object","required":["id","slug","name","sample_type","method","price","is_active","status","lab","markers"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"lab_test","identity":true}},"slug":{"type":"string","x-mockingbird-volatile":{"kind":"token"}},"name":{"type":"string","x-mockingbird-volatile":{"kind":"token"}},"sample_type":{"$ref":"#/components/schemas/LabTestSampleType"},"method":{"$ref":"#/components/schemas/LabTestCollectionMethod"},"price":{"type":"number"},"is_active":{"type":"boolean"},"status":{"$ref":"#/components/schemas/LabTestStatus"},"fasting":{"type":"boolean","default":false},"lab":{"anyOf":[{"$ref":"#/components/schemas/ClientFacingLab"},{"type":"null"}]},"markers":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingMarker"}},{"type":"null"}]},"is_delegated":{"type":"boolean","default":false},"auto_generated":{"type":"boolean","default":false},"has_collection_instructions":{"type":["boolean","null"]},"common_tat_days":{"type":["integer","null"]},"worst_case_tat_days":{"type":["integer","null"]}}},"LabTestResourcesResponse":{"type":"object","required":["data","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingLabTest"}},"next_cursor":{"type":["string","null"]}}},"LabAccountStatus":{"type":"string","enum":["active","pending","suspended","ready_to_launch"]},"LabAccountDelegatedFlow":{"type":"string","enum":["order_delegated","result_delegated","fully_delegated","not_delegated"]},"USState":{"type":"string","enum":["AL","AK","AZ","AR","CA","CO","CT","DE","FL","GA","HI","ID","IL","IN","IA","KS","KY","LA","ME","MD","MA","MI","MN","MS","MO","MT","NE","NV","NH","NJ","NM","NY","NC","ND","OH","OK","OR","PA","RI","SC","SD","TN","TX","UT","VT","VA","WA","WV","WI","WY"]},"Labs":{"type":"string","enum":["ayumetrix","spiriplex","ussl","quest","sonora_quest","labcorp","bioreference","us_biotek","manual","sanocardio","ihd","nexus","my_uti","crl","mtl"]},"ClientFacingLabAccount":{"type":"object","required":["id","lab","status","delegated_flow","provider_account_id","allowed_billing","team_id_allowlist"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"lab_account","identity":true}},"lab":{"$ref":"#/components/schemas/Labs"},"org_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"status":{"$ref":"#/components/schemas/LabAccountStatus"},"delegated_flow":{"$ref":"#/components/schemas/LabAccountDelegatedFlow"},"provider_account_id":{"type":"string"},"account_name":{"anyOf":[{"type":"string"},{"type":"null"}]},"default_clinical_notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"business_units":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"allowed_billing":{"type":"object","propertyNames":{"$ref":"#/components/schemas/Billing"},"additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/USState"}}},"team_id_allowlist":{"type":"array","items":{"type":"string","format":"uuid"}}}},"GetTeamLabAccountsResponse":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingLabAccount"}}}},"ClientFacingResult":{"type":"object","required":["name","slug","type"],"properties":{"name":{"type":"string"},"slug":{"type":"string"},"provider_id":{"type":["string","null"]},"type":{"$ref":"#/components/schemas/ResultType"},"value":{"type":["number","null"]},"unit":{"type":["string","null"]},"low_value":{"type":["number","null"]},"high_value":{"type":["number","null"]},"string_value":{"type":["string","null"]},"coded_value":{"type":["string","null"]},"is_abnormal":{"type":"boolean","default":false},"notes":{"type":["string","null"]}}},"GetMarkersResponse":{"type":"object","required":["markers"],"properties":{"markers":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingMarkerComplete"}},"total":{"type":["integer","null"]},"page":{"type":["integer","null"]},"size":{"type":["integer","null"]},"pages":{"type":["integer","null"]}}},"ClientFacingExpectedResult":{"type":"object","required":["id","name","slug","required"],"properties":{"id":{"type":"integer","x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"slug":{"type":"string"},"lab_id":{"type":["integer","null"]},"provider_id":{"type":["string","null"]},"required":{"type":"boolean"},"loinc":{"type":["object","null"],"required":["id","name","slug","code"],"properties":{"id":{"type":"integer","x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"slug":{"type":"string"},"code":{"type":"string"},"unit":{"type":["string","null"]}}}}},"ClientFacingMarkerComplete":{"type":"object","required":["id","name","slug","expected_results"],"properties":{"id":{"type":"integer","x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"slug":{"type":"string"},"description":{"type":["string","null"]},"lab_id":{"type":["integer","null"]},"provider_id":{"type":["string","null"]},"type":{"anyOf":[{"$ref":"#/components/schemas/MarkerType"},{"type":"null"}]},"unit":{"type":["string","null"]},"price":{"type":["string","null"]},"a_la_carte_enabled":{"type":"boolean","default":false},"common_tat_days":{"type":["integer","null"]},"worst_case_tat_days":{"type":["integer","null"]},"is_orderable":{"type":["boolean","null"],"default":true},"expected_results":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingExpectedResult"}}}},"ListOrderSetMarkersRequest":{"type":"object","required":["order_set_id"],"properties":{"order_set_id":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order_transaction","missing":"00000000-0000-4000-8000-000000000000"}},"provider_id":{"type":["string","null"]}}},"AllowedRadius":{"type":"integer","enum":[10,20,25,50,100]},"AppointmentPscLabs":{"type":"string","enum":["quest"]},"AppointmentProvider":{"type":"string","enum":["getlabs","phlebfinders","quest"]},"AppointmentType":{"type":"string","enum":["phlebotomy","patient_service_center"]},"AppointmentStatus":{"type":"string","enum":["confirmed","pending","reserved","in_progress","completed","cancelled"]},"AppointmentEventStatus":{"type":"string","enum":["pending","reserved","scheduled","completed","cancelled","in_progress"]},"AppointmentServiceType":{"type":"string","enum":["appointment-ready","appointment-request"]},"Billing":{"type":"string","enum":["client_bill","commercial_insurance","patient_bill_passthrough","patient_bill"]},"LabLocationCapability":{"type":"string","enum":["stat","appointment_scheduling_via_junction","appointment_scheduling_with_lab"]},"LngLat":{"type":"object","required":["lng","lat"],"properties":{"lng":{"type":"number"},"lat":{"type":"number"}}},"UsAddress":{"type":"object","required":["first_line","city","state","zip_code"],"properties":{"first_line":{"type":"string","minLength":1},"second_line":{"type":["string","null"]},"city":{"type":"string","minLength":1},"state":{"type":"string","minLength":1},"zip_code":{"type":"string","minLength":1},"unit":{"type":["string","null"]}}},"AppointmentLocation":{"type":"object","required":["location","address","code","name"],"properties":{"location":{"$ref":"#/components/schemas/LngLat"},"distance":{"type":["number","null"]},"address":{"$ref":"#/components/schemas/UsAddress"},"code":{"type":"string"},"name":{"type":"string"},"iana_timezone":{"type":["string","null"]}}},"TimeSlot":{"type":"object","required":["start","end","price","is_priority","num_appointments_available"],"properties":{"booking_key":{"type":["string","null"],"x-mockingbird-resource":{"type":"booking_key","identity":true},"x-mockingbird-volatile":{"kind":"token"}},"start":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}},"end":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}},"expires_at":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"timestamp"}},"price":{"type":"number"},"is_priority":{"type":"boolean"},"num_appointments_available":{"type":"integer"}}},"DaySlots":{"type":"object","required":["date","slots"],"properties":{"location":{"anyOf":[{"$ref":"#/components/schemas/AppointmentLocation"},{"type":"null"}]},"date":{"type":"string","format":"date"},"slots":{"type":"array","items":{"$ref":"#/components/schemas/TimeSlot"}}}},"AppointmentAvailabilitySlots":{"type":"object","required":["slots"],"properties":{"slots":{"type":"array","items":{"$ref":"#/components/schemas/DaySlots"}},"timezone":{"type":["string","null"]}}},"AppointmentBookingRequest":{"type":"object","required":["booking_key"],"properties":{"booking_key":{"type":"string","minLength":1,"x-mockingbird-resource-ref":{"type":"booking_key"}}}},"AppointmentRescheduleRequest":{"type":"object","required":["booking_key"],"properties":{"booking_key":{"type":"string","minLength":1,"x-mockingbird-resource-ref":{"type":"booking_key"}}}},"PscAppointmentBookingRequest":{"type":"object","required":["booking_key","site_code"],"properties":{"booking_key":{"type":"string","minLength":1,"x-mockingbird-resource-ref":{"type":"booking_key"}},"site_code":{"type":"string","minLength":1}}},"PhlebotomyAppointmentCancelRequest":{"type":"object","required":["cancellation_reason_id"],"properties":{"cancellation_reason_id":{"type":"string","minLength":1},"notes":{"type":["string","null"]}}},"PscAppointmentCancelRequest":{"type":"object","required":["cancellationReasonId"],"properties":{"cancellationReasonId":{"type":"string","minLength":1},"note":{"type":["string","null"]}}},"ClientFacingAppointmentEvent":{"type":"object","required":["created_at","status"],"properties":{"created_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}},"status":{"$ref":"#/components/schemas/AppointmentEventStatus"},"data":{"anyOf":[{"type":"object","additionalProperties":true},{"type":"null"}]}}},"ClientFacingAppointment":{"type":"object","required":["id","user_id","order_id","address","location","type","provider","status","provider_id","can_reschedule","event_status","events"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"appointment","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"user_id":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"user"}},"order_id":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order"}},"address":{"$ref":"#/components/schemas/UsAddress"},"location":{"$ref":"#/components/schemas/LngLat"},"start_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"timestamp"}},"end_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"timestamp"}},"iana_timezone":{"type":["string","null"]},"type":{"$ref":"#/components/schemas/AppointmentType"},"provider":{"$ref":"#/components/schemas/AppointmentProvider"},"status":{"$ref":"#/components/schemas/AppointmentStatus"},"provider_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"external_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"can_reschedule":{"type":"boolean"},"event_status":{"$ref":"#/components/schemas/AppointmentEventStatus"},"event_data":{"anyOf":[{"type":"object","additionalProperties":true},{"type":"null"}]},"order_transaction_id":{"type":["string","null"],"x-mockingbird-resource-ref":{"type":"order_transaction"}},"appointment_notes":{"type":["string","null"]},"events":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingAppointmentEvent"}}}},"ClientFacingAppointmentCancellationReason":{"type":"object","required":["id","name","is_refundable"],"properties":{"id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"is_refundable":{"type":"boolean"}}},"PhlebotomyAreaInfo":{"type":"object","required":["is_served","providers"],"properties":{"is_served":{"type":"boolean"},"providers":{"type":"array","items":{"$ref":"#/components/schemas/PhlebotomyProviderInfo"}}}},"PhlebotomyProviderInfo":{"type":"object","required":["name","service_types"],"properties":{"name":{"$ref":"#/components/schemas/AppointmentProvider"},"service_types":{"type":"array","items":{"$ref":"#/components/schemas/AppointmentServiceType"}}}},"PscAreaInfoDetails":{"type":"object","required":["appointment_with_vital","within_radius","radius"],"properties":{"appointment_with_vital":{"type":"boolean"},"within_radius":{"type":"number"},"radius":{"type":"string"},"capabilities":{"type":["array","null"],"items":{"$ref":"#/components/schemas/LabLocationCapability"}}}},"PscAreaInfo":{"type":"object","required":["patient_service_centers","supported_bill_types","lab_id"],"properties":{"patient_service_centers":{"$ref":"#/components/schemas/PscAreaInfoDetails"},"supported_bill_types":{"type":"array","items":{"$ref":"#/components/schemas/Billing"}},"lab_id":{"type":"integer"}}},"AreaInfo":{"type":"object","required":["zip_code","phlebotomy","central_labs"],"properties":{"zip_code":{"type":"string"},"phlebotomy":{"$ref":"#/components/schemas/PhlebotomyAreaInfo"},"central_labs":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/PscAreaInfo"}}}},"LabLocationMetadata":{"type":"object","required":["name","state","city","zip_code","first_line"],"properties":{"name":{"type":"string"},"state":{"type":"string"},"city":{"type":"string"},"zip_code":{"type":"string"},"first_line":{"type":"string"},"second_line":{"type":["string","null"]},"phone_number":{"type":["string","null"]},"fax_number":{"type":["string","null"]},"hours":{"type":["object","null"],"additionalProperties":true}}},"ClientFacingLabLocation":{"type":"object","required":["metadata","distance","site_code","supported_bill_types","location","capabilities"],"properties":{"metadata":{"$ref":"#/components/schemas/LabLocationMetadata"},"distance":{"type":"number"},"site_code":{"type":"string"},"supported_bill_types":{"type":"array","items":{"$ref":"#/components/schemas/Billing"}},"location":{"$ref":"#/components/schemas/LngLat"},"capabilities":{"type":"array","items":{"$ref":"#/components/schemas/LabLocationCapability"}}}},"PscInfo":{"type":"object","required":["lab_id","slug","patient_service_centers"],"properties":{"lab_id":{"type":"integer"},"slug":{"type":"string"},"patient_service_centers":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingLabLocation"}}}},"OrderTopLevelStatus":{"type":"string","enum":["received","collecting_sample","sample_with_lab","completed","cancelled","failed"]},"OrderLowLevelStatus":{"type":"string","enum":["ordered","requisition_created","requisition_bypassed","transit_customer","out_for_delivery","with_customer","transit_lab","delivered_to_lab","completed","failure_to_deliver_to_lab","failure_to_deliver_to_customer","problem_in_transit_lab","problem_in_transit_customer","sample_error","appointment_scheduled","appointment_cancelled","appointment_pending","draw_completed","cancelled","lost","do_not_process","partial_results","awaiting_registration","registered","redraw_available","corrected","lab_processing_blocked"]},"OrderStatus":{"type":"string","enum":["received.walk_in_test.ordered","received.walk_in_test.requisition_created","received.walk_in_test.requisition_bypassed","completed.walk_in_test.completed","sample_with_lab.walk_in_test.partial_results","failed.walk_in_test.sample_error","cancelled.walk_in_test.cancelled","collecting_sample.walk_in_test.appointment_pending","collecting_sample.walk_in_test.appointment_scheduled","collecting_sample.walk_in_test.appointment_cancelled","collecting_sample.walk_in_test.redraw_available","received.at_home_phlebotomy.ordered","received.at_home_phlebotomy.requisition_created","received.at_home_phlebotomy.requisition_bypassed","collecting_sample.at_home_phlebotomy.appointment_pending","collecting_sample.at_home_phlebotomy.appointment_scheduled","collecting_sample.at_home_phlebotomy.draw_completed","collecting_sample.at_home_phlebotomy.appointment_cancelled","completed.at_home_phlebotomy.completed","sample_with_lab.at_home_phlebotomy.partial_results","cancelled.at_home_phlebotomy.cancelled","failed.at_home_phlebotomy.sample_error","received.testkit.ordered","received.testkit.awaiting_registration","received.testkit.requisition_created","received.testkit.requisition_bypassed","received.testkit.registered","collecting_sample.testkit.transit_customer","collecting_sample.testkit.out_for_delivery","collecting_sample.testkit.with_customer","collecting_sample.testkit.transit_lab","sample_with_lab.testkit.delivered_to_lab","sample_with_lab.testkit.lab_processing_blocked","completed.testkit.completed","failed.testkit.failure_to_deliver_to_customer","failed.testkit.failure_to_deliver_to_lab","failed.testkit.sample_error","failed.testkit.lost","cancelled.testkit.cancelled","cancelled.testkit.do_not_process","collecting_sample.testkit.problem_in_transit_customer","collecting_sample.testkit.problem_in_transit_lab","received.on_site_collection.ordered","received.on_site_collection.requisition_created","received.on_site_collection.requisition_bypassed","sample_with_lab.on_site_collection.draw_completed","completed.on_site_collection.completed","cancelled.on_site_collection.cancelled","sample_with_lab.on_site_collection.partial_results","failed.on_site_collection.sample_error","completed.walk_in_test.corrected","completed.at_home_phlebotomy.corrected","completed.on_site_collection.corrected","completed.testkit.corrected"]},"OrderStatusDetail":{"type":"string","enum":["fulfillment_error","date_of_collection_unspecified","demographic_information_unspecified","demographic_information_mismatch","sample_quantity_not_sufficient","sample_contaminated","sample_stability_exceeded","sample_hemolyzed","sample_improper_collection"]},"OrderTransactionStatus":{"type":"string","enum":["active","completed","cancelled"]},"ClientFacingOrderEvent":{"type":"object","required":["id","created_at","status"],"properties":{"id":{"type":"integer","x-mockingbird-volatile":{"kind":"opaque"}},"created_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}},"status":{"$ref":"#/components/schemas/OrderStatus"},"status_detail":{"anyOf":[{"$ref":"#/components/schemas/OrderStatusDetail"},{"type":"null"}]}}},"ShippingAddress":{"type":"object","required":["receiver_name","first_line","city","state","zip","country","phone_number"],"properties":{"receiver_name":{"type":"string"},"first_line":{"type":"string"},"second_line":{"type":["string","null"]},"city":{"type":"string"},"state":{"type":"string"},"zip":{"type":"string"},"country":{"type":"string"},"phone_number":{"type":"string"}}},"ClientFacingPhysician":{"type":"object","required":["first_name","last_name","npi"],"properties":{"first_name":{"type":"string"},"last_name":{"type":"string"},"npi":{"type":"string"}}},"ClientFacingShipment":{"type":"object","required":["id","outbound_tracking_number","outbound_tracking_url","inbound_tracking_number","inbound_tracking_url","outbound_courier","inbound_courier","notes"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-volatile":{"kind":"id"}},"outbound_tracking_number":{"type":["string","null"]},"outbound_tracking_url":{"type":["string","null"]},"inbound_tracking_number":{"type":["string","null"]},"inbound_tracking_url":{"type":["string","null"]},"outbound_courier":{"type":["string","null"]},"inbound_courier":{"type":["string","null"]},"notes":{"type":["string","null"]}}},"ClientFacingTestkitOrder":{"type":"object","required":["id","shipment","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-volatile":{"kind":"id"}},"shipment":{"anyOf":[{"$ref":"#/components/schemas/ClientFacingShipment"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"opaque"}},"created_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}}}},"ClientFacingWalkInOrder":{"type":"object","required":["id","appointment_id","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-volatile":{"kind":"id"}},"appointment_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"created_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}}}},"ClientFacingTestKitOrderDetails":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["testkit","walk_in_test","at_home_phlebotomy","on_site_collection"]},"data":{"anyOf":[{"$ref":"#/components/schemas/ClientFacingTestkitOrder"},{"$ref":"#/components/schemas/ClientFacingWalkInOrder"},{"type":"null"}]}}},"ClientFacingPatientDetailsCompatible":{"type":"object","required":["first_name","last_name","dob","gender","phone_number","email"],"properties":{"first_name":{"type":"string","minLength":1,"pattern":"^[a-zA-Z0-9][a-zA-Z0-9 .,'-]*$","examples":["Ada","Chris","Maria","Jun"]},"last_name":{"type":"string","minLength":1,"pattern":"^[a-zA-Z0-9][a-zA-Z0-9 .,'-]*$","examples":["Lovelace","Vouga","Delgado","Park"]},"dob":{"type":"string","format":"date-time","examples":["1990-06-15T00:00:00.000Z","1983-02-02T00:00:00.000Z"]},"gender":{"type":"string","minLength":1,"pattern":"\\\\S","examples":["male","female","other","prefer_not_to_say"]},"phone_number":{"type":"string","minLength":1,"pattern":"^\\\\+1[2-9]\\\\d{9}$","examples":["+14155550123","+12125550987","+13105554444"]},"email":{"type":"string","format":"email","minLength":1,"examples":["ada@example.com","chris@example.com","maria@example.com"]}}},"PatientAddressCompatible":{"type":"object","required":["first_line","city","state","zip","country"],"properties":{"receiver_name":{"type":"string","default":"","examples":["Ada Lovelace","Chris Vouga"]},"first_line":{"type":"string","minLength":1,"pattern":"\\\\S","examples":["1 Main St","450 Market St","88 Kearny St"]},"second_line":{"type":["string","null"]},"city":{"type":"string","minLength":1,"pattern":"\\\\S","examples":["San Diego","San Francisco","New York"]},"state":{"type":"string","minLength":1,"enum":["AL","AK","AZ","AR","CA","CO","CT","DE","FL","GA","HI","ID","IL","IN","IA","KS","KY","LA","ME","MD","MA","MI","MN","MS","MO","MT","NE","NV","NH","NJ","NM","NY","NC","ND","OH","OK","OR","PA","RI","SC","SD","TN","TX","UT","VT","VA","WA","WV","WI","WY"]},"zip":{"type":"string","pattern":"^\\\\d{5}(-\\\\d{4})?$","examples":["92101","94105","10001"]},"country":{"type":"string","minLength":1,"pattern":"\\\\S","examples":["US"]},"access_notes":{"type":["string","null"],"examples":[null]},"phone_number":{"type":["string","null"],"examples":["+14155550123",null]}}},"AoeAnswerRequest":{"type":"object","required":["marker_id","question_id","answer"],"properties":{"marker_id":{"type":"integer","examples":[2075,1975]},"question_id":{"type":"integer","examples":[1]},"answer":{"type":"string","minLength":1,"examples":["No","Yes"]}}},"ClientFacingOrderInTransaction":{"type":"object","required":["id","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid"},"low_level_status":{"anyOf":[{"$ref":"#/components/schemas/OrderLowLevelStatus"},{"type":"null"}]},"low_level_status_created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"timestamp"}},"created_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}}}},"ClientFacingOrderTransaction":{"type":"object","required":["id","status","orders"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"order_transaction","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"status":{"$ref":"#/components/schemas/OrderTransactionStatus"},"orders":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingOrderInTransaction"}}}},"OrderSummary":{"type":"object","required":["id","last_status","last_status_created_at","updated_at","created_at"],"properties":{"id":{"type":"string","format":"uuid"},"origin":{"anyOf":[{"type":"string","enum":["initial","redraw","recreation"]},{"type":"null"}]},"parent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"last_status":{"$ref":"#/components/schemas/OrderLowLevelStatus"},"last_status_created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"}}},"GetOrderTransactionResponse":{"type":"object","required":["id","team_id","status"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"order_transaction","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"team_id":{"type":"string","format":"uuid","x-mockingbird-volatile":{"kind":"account"}},"status":{"$ref":"#/components/schemas/OrderTransactionStatus"},"orders":{"type":"array","items":{"$ref":"#/components/schemas/OrderSummary"}}}},"ClientFacingOrder":{"type":"object","required":["user_id","id","team_id","patient_details","patient_address","lab_test","details","sample_id","notes","created_at","updated_at","events","last_event","health_insurance_id","requisition_form_url","shipping_details","has_abn"],"properties":{"user_id":{"type":"string","format":"uuid"},"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"order","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"team_id":{"type":"string","format":"uuid","x-mockingbird-volatile":{"kind":"account"}},"patient_details":{"anyOf":[{"$ref":"#/components/schemas/ClientFacingPatientDetailsCompatible"},{"type":"null"}]},"patient_address":{"anyOf":[{"$ref":"#/components/schemas/PatientAddressCompatible"},{"type":"null"}]},"lab_test":{"$ref":"#/components/schemas/ClientFacingLabTest"},"details":{"$ref":"#/components/schemas/ClientFacingTestKitOrderDetails"},"sample_id":{"anyOf":[{"type":"string"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"opaque"}},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"clinical_notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}},"events":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingOrderEvent"}},"status":{"anyOf":[{"$ref":"#/components/schemas/OrderTopLevelStatus"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"opaque"}},"last_event":{"$ref":"#/components/schemas/ClientFacingOrderEvent"},"physician":{"anyOf":[{"$ref":"#/components/schemas/ClientFacingPhysician"},{"type":"null"}]},"health_insurance_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"requisition_form_url":{"anyOf":[{"type":"string"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"url"}},"priority":{"type":"boolean","default":false},"shipping_details":{"anyOf":[{"$ref":"#/components/schemas/ShippingAddress"},{"type":"null"}]},"activate_by":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}]},"passthrough":{"anyOf":[{"type":"string"},{"type":"null"}]},"billing_type":{"type":"string","enum":["client_bill","commercial_insurance","patient_bill_passthrough","patient_bill","upfront_payment"],"default":"client_bill"},"icd_codes":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"has_abn":{"type":"boolean"},"interpretation":{"anyOf":[{"type":"string","enum":["normal","abnormal","critical","unknown"]},{"type":"null"}]},"has_missing_results":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"expected_result_by_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}]},"worst_case_result_by_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}]},"origin":{"anyOf":[{"type":"string","enum":["initial","redraw","recreation"]},{"type":"null"}]},"order_transaction":{"anyOf":[{"$ref":"#/components/schemas/ClientFacingOrderTransaction"},{"type":"null"}]}}},"OrderSetRequest":{"type":"object","required":["lab_test_ids"],"properties":{"lab_test_ids":{"type":"array","minItems":1,"items":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"lab_test","missing":"00000000-0000-4000-8000-000000000000"}}}}},"CreateOrderRequest":{"type":"object","required":["user_id","patient_details","patient_address","order_set"],"properties":{"user_id":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"user","missing":"00000000-0000-4000-8000-000000000000"}},"patient_details":{"$ref":"#/components/schemas/ClientFacingPatientDetailsCompatible"},"patient_address":{"$ref":"#/components/schemas/PatientAddressCompatible"},"order_set":{"$ref":"#/components/schemas/OrderSetRequest"},"clinical_notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"passthrough":{"anyOf":[{"type":"string"},{"type":"null"}]},"collection_method":{"$ref":"#/components/schemas/LabTestCollectionMethod"},"lab_account_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"idempotency_key":{"type":["string","null"]},"idempotency_error":{"type":["string","null"]},"aoe_answers":{"type":["array","null"],"items":{"$ref":"#/components/schemas/AoeAnswerRequest"}}}},"PostOrderResponse":{"type":"object","required":["order","status","message"],"properties":{"order":{"$ref":"#/components/schemas/ClientFacingOrder"},"status":{"type":"string"},"message":{"type":"string"}}},"ResultType":{"type":"string","enum":["numeric","range","comment","coded_value"]},"ParentBiomarkerData":{"type":"object","required":["marker_id","name","slug"],"properties":{"marker_id":{"type":"integer"},"name":{"type":"string"},"slug":{"type":"string"},"provider_id":{"type":["string","null"]}}},"BiomarkerResult":{"type":"object","required":["name","result","type"],"properties":{"name":{"type":"string"},"slug":{"type":"string","default":""},"value":{"anyOf":[{"type":"number"},{"type":"null"}]},"result":{"type":"string"},"type":{"$ref":"#/components/schemas/ResultType"},"unit":{"type":["string","null"]},"timestamp":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"timestamp"}},"notes":{"type":["string","null"]},"reference_range":{"type":["string","null"]},"min_range_value":{"type":["number","null"]},"max_range_value":{"type":["number","null"]},"is_above_max_range":{"type":["boolean","null"]},"is_below_min_range":{"type":["boolean","null"]},"interpretation":{"type":"string","default":"normal"},"source_interpretation":{"type":"string","default":""},"loinc":{"type":["string","null"]},"loinc_slug":{"type":["string","null"]},"provider_id":{"type":["string","null"]},"source_markers":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/ParentBiomarkerData"}},{"type":"null"}]},"performing_laboratory":{"type":["string","null"]},"source_sample_id":{"type":["string","null"]}}},"FailureType":{"type":"string","enum":["quantity_not_sufficient_failure","collection_process_failure","drop_off_failure","internal_lab_failure","order_entry_failure","non_failure","unknown_failure","patient_condition_failure","missing_result_calc_failure","missing_demo_aoe_calc_failure","insufficient_volume"]},"MissingBiomarkerResult":{"type":"object","required":["name","slug","inferred_failure_type"],"properties":{"name":{"type":"string"},"slug":{"type":"string"},"inferred_failure_type":{"$ref":"#/components/schemas/FailureType"},"note":{"type":["string","null"]},"loinc":{"type":["string","null"]},"loinc_slug":{"type":["string","null"]},"provider_id":{"type":["string","null"]},"source_markers":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/ParentBiomarkerData"}},{"type":"null"}]}}},"SampleData":{"type":"object","properties":{"sample_id":{"type":["string","null"]},"control_number":{"type":["string","null"]},"date_collected":{"type":["string","null"]},"date_received":{"type":["string","null"]},"date_reported":{"type":["string","null"]},"performing_laboratories":{"anyOf":[{"type":"object","additionalProperties":true},{"type":"null"}]},"clinical_information":{"anyOf":[{"type":"object","additionalProperties":true},{"type":"null"}]}}},"LabResultsMetadata":{"type":"object","required":["age","dob","patient","date_reported","specimen_number"],"properties":{"age":{"type":"string","x-mockingbird-volatile":{"kind":"token"}},"dob":{"type":"string","x-mockingbird-volatile":{"kind":"token"}},"clia_#":{"anyOf":[{"type":"string"},{"type":"null"}]},"patient":{"type":"string","x-mockingbird-volatile":{"kind":"token"}},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"token"}},"laboratory":{"anyOf":[{"type":"string"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"token"}},"date_reported":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"date_collected":{"anyOf":[{"type":"string"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"timestamp"}},"specimen_number":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"date_received":{"anyOf":[{"type":"string"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"timestamp"}},"status":{"type":"string","default":"final"},"interpretation":{"anyOf":[{"type":"string"},{"type":"null"}]},"patient_id":{"anyOf":[{"type":"string"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"id"}},"account_id":{"anyOf":[{"type":"string"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"id"}}}},"LabResultsRaw":{"type":"object","required":["metadata","results"],"properties":{"metadata":{"$ref":"#/components/schemas/LabResultsMetadata"},"results":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/BiomarkerResult"}},{"type":"object","additionalProperties":true}],"x-mockingbird-volatile":{"kind":"opaque"}},"missing_results":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/MissingBiomarkerResult"}},{"type":"null"}],"x-mockingbird-volatile":{"kind":"opaque"}},"sample_information":{"anyOf":[{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SampleData"}},{"type":"null"}],"x-mockingbird-volatile":{"kind":"opaque"}},"order_transaction":{"anyOf":[{"$ref":"#/components/schemas/ClientFacingOrderTransaction"},{"type":"null"}]}}},"SimulationFlags":{"type":"object","properties":{"interpretation":{"anyOf":[{"type":"string","enum":["normal","abnormal","critical","unknown"]},{"type":"null"}]},"result_types":{"type":"array","items":{"$ref":"#/components/schemas/ResultType"}},"has_missing_results":{"type":"boolean"}}},"GetOrdersResponse":{"type":"object","required":["orders"],"properties":{"orders":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingOrder"}},"total":{"anyOf":[{"type":"integer"},{"type":"null"}]},"page":{"anyOf":[{"type":"integer"},{"type":"null"}]},"size":{"anyOf":[{"type":"integer"},{"type":"null"}]}}},"HTTPValidationError":{"type":"object","properties":{"detail":{"title":"Detail"}}}}}}`);
|
|
1092
|
-
var operationIds = ["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"];
|
|
1093
|
-
var supportedOperationIds = ["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"];
|
|
1094
|
-
|
|
1095
1198
|
// src/catalog.ts
|
|
1096
1199
|
var LAB_TEST_CATALOG = [
|
|
1097
1200
|
{
|
|
@@ -1821,6 +1924,69 @@ var EXPECTED_RESULTS = {
|
|
|
1821
1924
|
]
|
|
1822
1925
|
};
|
|
1823
1926
|
|
|
1927
|
+
// src/limits.ts
|
|
1928
|
+
var SANDBOX_KEY_PREFIXES = ["sk_us_", "sk_eu_"];
|
|
1929
|
+
var isSandboxKey = (key) => SANDBOX_KEY_PREFIXES.some((prefix) => key.startsWith(prefix));
|
|
1930
|
+
var DEFAULT_LIMITS = {
|
|
1931
|
+
maxUsers: null,
|
|
1932
|
+
simulateRequiresSandbox: false,
|
|
1933
|
+
rateLimitPerSecond: null
|
|
1934
|
+
};
|
|
1935
|
+
var sandboxUserQuotaBody = (max) => ({
|
|
1936
|
+
detail: {
|
|
1937
|
+
error_type: "INVALID_REQUEST",
|
|
1938
|
+
error_message: `You have reached the maximum of ${max} Sandbox users`
|
|
1939
|
+
}
|
|
1940
|
+
});
|
|
1941
|
+
var positiveOrNull = (value, field) => {
|
|
1942
|
+
if (value === null) return null;
|
|
1943
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 0)
|
|
1944
|
+
throw new TypeError(`${field} must be a non-negative integer, or null for unlimited`);
|
|
1945
|
+
return value;
|
|
1946
|
+
};
|
|
1947
|
+
var mergeLimits = (base, input) => {
|
|
1948
|
+
if (typeof input !== "object" || input === null || Array.isArray(input))
|
|
1949
|
+
throw new TypeError("limits must be an object");
|
|
1950
|
+
const record = input;
|
|
1951
|
+
for (const key of Object.keys(record)) {
|
|
1952
|
+
if (!(key in DEFAULT_LIMITS))
|
|
1953
|
+
throw new TypeError(`unknown limit ${key}; one of ${Object.keys(DEFAULT_LIMITS).join(", ")}`);
|
|
1954
|
+
}
|
|
1955
|
+
const next = { ...base };
|
|
1956
|
+
if (record.maxUsers !== void 0) next.maxUsers = positiveOrNull(record.maxUsers, "maxUsers");
|
|
1957
|
+
if (record.rateLimitPerSecond !== void 0)
|
|
1958
|
+
next.rateLimitPerSecond = positiveOrNull(record.rateLimitPerSecond, "rateLimitPerSecond");
|
|
1959
|
+
if (record.simulateRequiresSandbox !== void 0) {
|
|
1960
|
+
if (typeof record.simulateRequiresSandbox !== "boolean")
|
|
1961
|
+
throw new TypeError("simulateRequiresSandbox must be a boolean");
|
|
1962
|
+
next.simulateRequiresSandbox = record.simulateRequiresSandbox;
|
|
1963
|
+
}
|
|
1964
|
+
return next;
|
|
1965
|
+
};
|
|
1966
|
+
var checkUserQuota = (limits, liveUsers) => {
|
|
1967
|
+
if (limits.maxUsers !== null && liveUsers >= limits.maxUsers)
|
|
1968
|
+
throw new HttpError(400, sandboxUserQuotaBody(limits.maxUsers));
|
|
1969
|
+
};
|
|
1970
|
+
var checkSimulateAllowed = (limits, apiKey) => {
|
|
1971
|
+
if (limits.simulateRequiresSandbox && !isSandboxKey(apiKey ?? ""))
|
|
1972
|
+
throw new HttpError(400, { detail: "Order simulation is only available in sandbox" });
|
|
1973
|
+
};
|
|
1974
|
+
var RateWindow = class {
|
|
1975
|
+
windowStart = 0;
|
|
1976
|
+
count = 0;
|
|
1977
|
+
/** Whether one more request fits under `perSecond` now. */
|
|
1978
|
+
take(perSecond, nowMs = Date.now()) {
|
|
1979
|
+
if (perSecond === null) return true;
|
|
1980
|
+
if (nowMs - this.windowStart >= 1e3) {
|
|
1981
|
+
this.windowStart = nowMs;
|
|
1982
|
+
this.count = 0;
|
|
1983
|
+
}
|
|
1984
|
+
if (this.count >= perSecond) return false;
|
|
1985
|
+
this.count++;
|
|
1986
|
+
return true;
|
|
1987
|
+
}
|
|
1988
|
+
};
|
|
1989
|
+
|
|
1824
1990
|
// src/state.ts
|
|
1825
1991
|
var sortedQueryString = (params) => {
|
|
1826
1992
|
const entries = [...params.entries()].sort(([leftKey, leftValue], [rightKey, rightValue]) => {
|
|
@@ -1893,6 +2059,14 @@ var JunctionState = class {
|
|
|
1893
2059
|
getCache;
|
|
1894
2060
|
/** Configuration, not data: set by JunctionAPI and re-applied on reset. */
|
|
1895
2061
|
geoMode = "synthetic";
|
|
2062
|
+
/** The team this mock answers as: `team_id` on users and orders, and lab-account linking. */
|
|
2063
|
+
teamId = MOCK_TEAM_ID;
|
|
2064
|
+
/** Sandbox-only restrictions to enforce; every one is off by default. */
|
|
2065
|
+
limits = { ...DEFAULT_LIMITS };
|
|
2066
|
+
/** Whether an unknown `user_id` is refused (`strict`) or created on first use. */
|
|
2067
|
+
identity = "strict";
|
|
2068
|
+
webhooksMuted = 0;
|
|
2069
|
+
adoptedRequests = /* @__PURE__ */ new WeakSet();
|
|
1896
2070
|
/** ZIPs the loaded corpus has serviceability records for. */
|
|
1897
2071
|
coveredZips = /* @__PURE__ */ new Set();
|
|
1898
2072
|
/** Identifies the loaded corpus in errors and `/health`. */
|
|
@@ -2171,7 +2345,24 @@ var JunctionState = class {
|
|
|
2171
2345
|
testkitIdFor(orderId) {
|
|
2172
2346
|
return deterministicUuid(`junction:testkit:${orderId}`);
|
|
2173
2347
|
}
|
|
2348
|
+
/** Run `fn` without publishing any webhook: how fixtures load without side effects. */
|
|
2349
|
+
muteWebhooks(fn) {
|
|
2350
|
+
this.webhooksMuted++;
|
|
2351
|
+
try {
|
|
2352
|
+
return fn();
|
|
2353
|
+
} finally {
|
|
2354
|
+
this.webhooksMuted--;
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
/** Record that handling `request` adopted an unknown user (see `requireUser`). */
|
|
2358
|
+
noteAdoption(request2) {
|
|
2359
|
+
this.adoptedRequests.add(request2);
|
|
2360
|
+
}
|
|
2361
|
+
adopted(request2) {
|
|
2362
|
+
return this.adoptedRequests.has(request2);
|
|
2363
|
+
}
|
|
2174
2364
|
publishWebhook(event, now = Date.now()) {
|
|
2365
|
+
if (this.webhooksMuted > 0) return;
|
|
2175
2366
|
const sequence = this.webhookEvents.nextSequence();
|
|
2176
2367
|
const snapshot = clone(event);
|
|
2177
2368
|
this.webhookEvents.insert(String(sequence), { sequence, event: snapshot });
|
|
@@ -2313,6 +2504,7 @@ var LAB_ACCOUNT_STATUSES = [
|
|
|
2313
2504
|
"ready_to_launch"
|
|
2314
2505
|
];
|
|
2315
2506
|
var MOCK_ORG_ID = deterministicUuid("junction:org:mock");
|
|
2507
|
+
var OTHER_TEAM_ID = deterministicUuid("junction:team:other");
|
|
2316
2508
|
var PLATFORM_BILLING = Object.fromEntries(
|
|
2317
2509
|
BILLING_TYPES.map((type) => [type, ALL_BILLING_STATES])
|
|
2318
2510
|
);
|
|
@@ -2386,18 +2578,19 @@ var TEAM_LAB_ACCOUNTS = [
|
|
|
2386
2578
|
status: "active",
|
|
2387
2579
|
account_name: "IHD \u2014 other team",
|
|
2388
2580
|
allowed_billing: CLIENT_BILL_ONLY,
|
|
2389
|
-
team_id_allowlist: []
|
|
2581
|
+
team_id_allowlist: [OTHER_TEAM_ID]
|
|
2390
2582
|
})
|
|
2391
2583
|
];
|
|
2392
2584
|
var PLATFORM_ACCOUNT_LABS = TEAM_LABS.map((lab) => String(lab.slug));
|
|
2393
|
-
var labAccountById = (id, accounts
|
|
2394
|
-
var
|
|
2585
|
+
var labAccountById = (id, accounts) => accounts.find((entry) => entry.id === id);
|
|
2586
|
+
var isLinkedToTeam = (entry, teamId) => entry.team_id_allowlist.length === 0 || entry.team_id_allowlist.includes(teamId);
|
|
2587
|
+
var linkedLabAccounts = (labSlug, teamId, accounts) => accounts.filter((entry) => entry.lab === labSlug && isLinkedToTeam(entry, teamId));
|
|
2395
2588
|
var effectiveBilling = (account2) => account2 === "platform" ? PLATFORM_BILLING : account2.allowed_billing;
|
|
2396
|
-
var selectLabAccount = (labSlug, requestedId, teamId, accounts
|
|
2589
|
+
var selectLabAccount = (labSlug, requestedId, teamId, accounts) => {
|
|
2397
2590
|
if (requestedId !== null) {
|
|
2398
2591
|
const linked = labAccountById(requestedId, accounts);
|
|
2399
2592
|
if (!linked) throw new HttpError(400, { detail: "Lab account does not exist" });
|
|
2400
|
-
if (!linked
|
|
2593
|
+
if (!isLinkedToTeam(linked, teamId))
|
|
2401
2594
|
throw new HttpError(400, { detail: "Lab account is not linked to your team" });
|
|
2402
2595
|
if (linked.lab !== labSlug)
|
|
2403
2596
|
throw new HttpError(400, { detail: `Lab account is not associated with lab ${labSlug}` });
|
|
@@ -2434,15 +2627,56 @@ var renderLabAccount = (entry) => ({
|
|
|
2434
2627
|
team_id_allowlist: [...entry.team_id_allowlist]
|
|
2435
2628
|
});
|
|
2436
2629
|
var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2630
|
+
var DELEGATED_FLOWS = [
|
|
2631
|
+
"order_delegated",
|
|
2632
|
+
"result_delegated",
|
|
2633
|
+
"fully_delegated",
|
|
2634
|
+
"not_delegated"
|
|
2635
|
+
];
|
|
2636
|
+
var checkStates = (value, where) => {
|
|
2637
|
+
if (!Array.isArray(value)) throw new TypeError(`${where} must be an array of US state codes`);
|
|
2638
|
+
for (const state of value) {
|
|
2639
|
+
if (typeof state !== "string" || !US_STATES.includes(state))
|
|
2640
|
+
throw new TypeError(`${where}: ${String(state)} is not a US state code`);
|
|
2641
|
+
}
|
|
2642
|
+
};
|
|
2437
2643
|
var stringList = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string") ? [...value] : void 0;
|
|
2438
|
-
var labAccountFromInput = (input) => {
|
|
2644
|
+
var labAccountFromInput = (input, teamId = MOCK_TEAM_ID) => {
|
|
2645
|
+
if (!isRecord3(input)) throw new TypeError("lab account must be an object");
|
|
2439
2646
|
if (typeof input.id !== "string" || input.id === "")
|
|
2440
2647
|
throw new TypeError("lab account needs a non-empty id");
|
|
2648
|
+
const where = `lab account ${input.id}`;
|
|
2441
2649
|
if (typeof input.lab !== "string" || input.lab === "")
|
|
2442
|
-
throw new TypeError(
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2650
|
+
throw new TypeError(`${where}: lab must be a lab slug such as "quest"`);
|
|
2651
|
+
if (input.status !== void 0 && !LAB_ACCOUNT_STATUSES.includes(input.status))
|
|
2652
|
+
throw new TypeError(`${where}: status must be one of ${LAB_ACCOUNT_STATUSES.join(", ")}`);
|
|
2653
|
+
if (input.delegated_flow !== void 0 && !DELEGATED_FLOWS.includes(input.delegated_flow))
|
|
2654
|
+
throw new TypeError(`${where}: delegated_flow must be one of ${DELEGATED_FLOWS.join(", ")}`);
|
|
2655
|
+
if (input.states !== void 0) checkStates(input.states, `${where}: states`);
|
|
2656
|
+
if (input.allowed_billing !== void 0) {
|
|
2657
|
+
if (!isRecord3(input.allowed_billing))
|
|
2658
|
+
throw new TypeError(`${where}: allowed_billing must map billing types to state lists`);
|
|
2659
|
+
for (const [type, states] of Object.entries(input.allowed_billing)) {
|
|
2660
|
+
if (!BILLING_TYPES.includes(type))
|
|
2661
|
+
throw new TypeError(
|
|
2662
|
+
`${where}: allowed_billing.${type} is not a billing type (${BILLING_TYPES.join(", ")})`
|
|
2663
|
+
);
|
|
2664
|
+
checkStates(states, `${where}: allowed_billing.${type}`);
|
|
2665
|
+
}
|
|
2666
|
+
}
|
|
2667
|
+
if (input.team_id_allowlist !== void 0 && stringList(input.team_id_allowlist) === void 0)
|
|
2668
|
+
throw new TypeError(`${where}: team_id_allowlist must be an array of team ids`);
|
|
2669
|
+
if (input.business_units != null && stringList(input.business_units) === void 0)
|
|
2670
|
+
throw new TypeError(`${where}: business_units must be an array of strings or null`);
|
|
2671
|
+
for (const field of [
|
|
2672
|
+
"account_name",
|
|
2673
|
+
"provider_account_id",
|
|
2674
|
+
"org_id",
|
|
2675
|
+
"default_clinical_notes"
|
|
2676
|
+
]) {
|
|
2677
|
+
const value = input[field];
|
|
2678
|
+
if (value != null && typeof value !== "string")
|
|
2679
|
+
throw new TypeError(`${where}: ${field} must be a string`);
|
|
2446
2680
|
}
|
|
2447
2681
|
return {
|
|
2448
2682
|
id: input.id,
|
|
@@ -2455,10 +2689,28 @@ var labAccountFromInput = (input) => {
|
|
|
2455
2689
|
default_clinical_notes: input.default_clinical_notes ?? null,
|
|
2456
2690
|
business_units: input.business_units ?? null,
|
|
2457
2691
|
allowed_billing: input.allowed_billing ?? { client_bill: input.states ?? ALL_BILLING_STATES },
|
|
2458
|
-
team_id_allowlist: input.team_id_allowlist ?? [
|
|
2692
|
+
team_id_allowlist: input.team_id_allowlist ?? [teamId]
|
|
2459
2693
|
};
|
|
2460
2694
|
};
|
|
2461
|
-
var
|
|
2695
|
+
var patchLabAccount = (existing, patch, teamId) => {
|
|
2696
|
+
if (!isRecord3(patch)) throw new TypeError("lab account patch must be an object");
|
|
2697
|
+
if (patch.id !== void 0 && patch.id !== existing.id)
|
|
2698
|
+
throw new TypeError(`lab account ${existing.id}: id cannot be changed`);
|
|
2699
|
+
const { states, ...rest } = patch;
|
|
2700
|
+
if (states !== void 0) checkStates(states, `lab account ${existing.id}: states`);
|
|
2701
|
+
const allowed_billing = rest.allowed_billing ?? (states !== void 0 ? { ...existing.allowed_billing, client_bill: states } : existing.allowed_billing);
|
|
2702
|
+
return labAccountFromInput(
|
|
2703
|
+
{
|
|
2704
|
+
...existing,
|
|
2705
|
+
business_units: existing.business_units,
|
|
2706
|
+
...rest,
|
|
2707
|
+
id: existing.id,
|
|
2708
|
+
allowed_billing
|
|
2709
|
+
},
|
|
2710
|
+
teamId
|
|
2711
|
+
);
|
|
2712
|
+
};
|
|
2713
|
+
var labAccountFromClientFacing = (value, recordedTeamId) => {
|
|
2462
2714
|
if (typeof value.id !== "string" || typeof value.lab !== "string") return void 0;
|
|
2463
2715
|
const billing = {};
|
|
2464
2716
|
if (isRecord3(value.allowed_billing)) {
|
|
@@ -2479,141 +2731,633 @@ var labAccountFromClientFacing = (value) => {
|
|
|
2479
2731
|
default_clinical_notes: typeof value.default_clinical_notes === "string" ? value.default_clinical_notes : null,
|
|
2480
2732
|
business_units: stringList(value.business_units) ?? null,
|
|
2481
2733
|
allowed_billing: billing,
|
|
2482
|
-
team_id_allowlist: allowlist.includes(MOCK_TEAM_ID) ? allowlist : [...allowlist, MOCK_TEAM_ID]
|
|
2734
|
+
team_id_allowlist: recordedTeamId !== void 0 || allowlist.includes(MOCK_TEAM_ID) ? allowlist : [...allowlist, MOCK_TEAM_ID]
|
|
2483
2735
|
};
|
|
2484
2736
|
};
|
|
2485
2737
|
|
|
2486
|
-
// src/
|
|
2487
|
-
var
|
|
2488
|
-
var
|
|
2489
|
-
var
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
}
|
|
2498
|
-
});
|
|
2499
|
-
};
|
|
2500
|
-
var cachedResponse = (state, context) => {
|
|
2501
|
-
const body = context.request.method.toUpperCase() === "GET" || context.request.method.toUpperCase() === "HEAD" ? void 0 : context.body.kind === "json" ? context.body.value : context.body.kind === "form" ? context.body.value : void 0;
|
|
2502
|
-
const key = state.cacheKeyForRequest(
|
|
2503
|
-
context.request.method,
|
|
2504
|
-
context.url.pathname,
|
|
2505
|
-
context.url.searchParams,
|
|
2506
|
-
body
|
|
2507
|
-
);
|
|
2508
|
-
const cached = state.getGetCache(key);
|
|
2509
|
-
if (!cached) return void 0;
|
|
2510
|
-
if (key.toLowerCase().includes("availability")) {
|
|
2511
|
-
materializeAvailabilityBookingKeys(state, context, cached.body);
|
|
2512
|
-
rotateAvailabilityBookingKeys(state, cached.body, context.now());
|
|
2513
|
-
}
|
|
2514
|
-
const headers = new Headers(cached.headers);
|
|
2515
|
-
headers.delete("content-encoding");
|
|
2516
|
-
headers.delete("content-length");
|
|
2517
|
-
headers.delete("transfer-encoding");
|
|
2518
|
-
if (!headers.has("content-type")) headers.set("content-type", "application/json");
|
|
2519
|
-
return new Response(JSON.stringify(cached.body), { status: cached.status, headers });
|
|
2738
|
+
// src/lab-account-presets.ts
|
|
2739
|
+
var except = (...excluded) => US_STATES.filter((state) => !excluded.includes(state));
|
|
2740
|
+
var PLATFORM_ACCOUNT_STATES = except("NJ", "NY", "RI");
|
|
2741
|
+
var DELEGATED_ACCOUNT_STATES = except("NJ", "NY");
|
|
2742
|
+
var bioreferenceCustomer = {
|
|
2743
|
+
lab: "bioreference",
|
|
2744
|
+
account_name: "Junction BioReference Account",
|
|
2745
|
+
delegated_flow: "not_delegated",
|
|
2746
|
+
org_id: null,
|
|
2747
|
+
allowed_billing: { client_bill: PLATFORM_ACCOUNT_STATES },
|
|
2748
|
+
team_id_allowlist: []
|
|
2520
2749
|
};
|
|
2521
|
-
var
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
const root = cachedBody;
|
|
2529
|
-
const dayBuckets = [];
|
|
2530
|
-
if (Array.isArray(root.days)) dayBuckets.push(...root.days);
|
|
2531
|
-
if (Array.isArray(root.slots)) dayBuckets.push(...root.slots);
|
|
2532
|
-
for (const day of dayBuckets) {
|
|
2533
|
-
if (typeof day !== "object" || day === null || Array.isArray(day)) continue;
|
|
2534
|
-
const daySlots = day.slots;
|
|
2535
|
-
const slots = Array.isArray(daySlots) ? daySlots : [day];
|
|
2536
|
-
for (const entry of slots) {
|
|
2537
|
-
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) continue;
|
|
2538
|
-
const slot = entry;
|
|
2539
|
-
const bookingKey = typeof slot.booking_key === "string" ? slot.booking_key : "";
|
|
2540
|
-
if (!bookingKey) continue;
|
|
2541
|
-
const record = state.bookingKeys.get(bookingKey);
|
|
2542
|
-
if (!record) continue;
|
|
2543
|
-
if (modalityHint) record.modality = modalityHint;
|
|
2544
|
-
record.zip_code = zip;
|
|
2545
|
-
record.provider = record.modality === "patient_service_center" ? "quest" : "getlabs";
|
|
2546
|
-
record.address = addressFromAvailabilityRequest(requestBody, zip);
|
|
2547
|
-
record.location = zipLocation(zip);
|
|
2548
|
-
state.bookingKeys.update(bookingKey, record);
|
|
2549
|
-
}
|
|
2550
|
-
}
|
|
2551
|
-
}
|
|
2750
|
+
var questPlatform = {
|
|
2751
|
+
lab: "quest",
|
|
2752
|
+
account_name: "Junction Quest Account",
|
|
2753
|
+
delegated_flow: "not_delegated",
|
|
2754
|
+
org_id: null,
|
|
2755
|
+
allowed_billing: { client_bill: PLATFORM_ACCOUNT_STATES },
|
|
2756
|
+
team_id_allowlist: []
|
|
2552
2757
|
};
|
|
2553
|
-
var
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2758
|
+
var labcorpPlatform = {
|
|
2759
|
+
lab: "labcorp",
|
|
2760
|
+
account_name: "Junction Labcorp Account",
|
|
2761
|
+
delegated_flow: "not_delegated",
|
|
2762
|
+
org_id: null,
|
|
2763
|
+
allowed_billing: { client_bill: PLATFORM_ACCOUNT_STATES },
|
|
2764
|
+
team_id_allowlist: []
|
|
2765
|
+
};
|
|
2766
|
+
var LAB_ACCOUNT_PRESETS = {
|
|
2767
|
+
bioreference_ny_nj_delegated: {
|
|
2768
|
+
lab: "bioreference",
|
|
2769
|
+
delegated_flow: "order_delegated",
|
|
2770
|
+
allowed_billing: { client_bill: ["NY", "NJ"] }
|
|
2771
|
+
},
|
|
2772
|
+
bioreference_delegated_multi_state: {
|
|
2773
|
+
lab: "bioreference",
|
|
2774
|
+
delegated_flow: "order_delegated",
|
|
2775
|
+
allowed_billing: { client_bill: DELEGATED_ACCOUNT_STATES }
|
|
2776
|
+
},
|
|
2777
|
+
bioreference_customer_multi_state: bioreferenceCustomer,
|
|
2778
|
+
bioreference_patient_bill_passthrough: {
|
|
2779
|
+
lab: "bioreference",
|
|
2780
|
+
delegated_flow: "not_delegated",
|
|
2781
|
+
allowed_billing: { patient_bill_passthrough: ["NJ", "NY"] }
|
|
2782
|
+
},
|
|
2783
|
+
quest_platform: questPlatform,
|
|
2784
|
+
labcorp_platform: labcorpPlatform,
|
|
2785
|
+
suspended_bioreference: { ...bioreferenceCustomer, status: "suspended" },
|
|
2786
|
+
suspended_quest: { ...questPlatform, status: "suspended" },
|
|
2787
|
+
suspended_labcorp: { ...labcorpPlatform, status: "suspended" }
|
|
2788
|
+
};
|
|
2789
|
+
var presetAccountId = (name) => deterministicUuid(`junction:lab-account:${name}`);
|
|
2790
|
+
var labAccountFromPreset = (name, options) => {
|
|
2791
|
+
const preset = Object.hasOwn(LAB_ACCOUNT_PRESETS, name) ? LAB_ACCOUNT_PRESETS[name] : void 0;
|
|
2792
|
+
if (!preset) return void 0;
|
|
2793
|
+
return labAccountFromInput({ ...preset, id: options.id ?? presetAccountId(name) }, options.teamId);
|
|
2794
|
+
};
|
|
2795
|
+
var expandLabAccountLayout = (layout, teamId) => {
|
|
2796
|
+
if (Array.isArray(layout))
|
|
2797
|
+
return layout.map((input) => labAccountFromInput(input, teamId));
|
|
2798
|
+
if (typeof layout !== "object" || layout === null)
|
|
2799
|
+
throw new TypeError('lab accounts must be an array, or { "presets": [...], "accounts": [...] }');
|
|
2800
|
+
const { presets = [], accounts = [] } = layout;
|
|
2801
|
+
if (!Array.isArray(presets)) throw new TypeError("presets must be an array of preset names");
|
|
2802
|
+
if (!Array.isArray(accounts)) throw new TypeError("accounts must be an array of lab accounts");
|
|
2803
|
+
const records = [];
|
|
2804
|
+
for (const entry of presets) {
|
|
2805
|
+
const name = typeof entry === "string" ? entry : entry?.name;
|
|
2806
|
+
const id = typeof entry === "string" ? void 0 : entry?.id;
|
|
2807
|
+
const record = typeof name === "string" ? labAccountFromPreset(name, { teamId, ...id !== void 0 ? { id } : {} }) : void 0;
|
|
2808
|
+
if (!record)
|
|
2809
|
+
throw new TypeError(
|
|
2810
|
+
`no lab-account preset ${JSON.stringify(name)}; one of ${Object.keys(LAB_ACCOUNT_PRESETS).join(", ")}`
|
|
2811
|
+
);
|
|
2812
|
+
records.push(record);
|
|
2581
2813
|
}
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
for (
|
|
2585
|
-
|
|
2586
|
-
|
|
2814
|
+
for (const input of accounts) records.push(labAccountFromInput(input, teamId));
|
|
2815
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2816
|
+
for (const record of records) {
|
|
2817
|
+
if (seen.has(record.id)) throw new TypeError(`lab account ${record.id} is declared twice`);
|
|
2818
|
+
seen.add(record.id);
|
|
2587
2819
|
}
|
|
2588
|
-
return
|
|
2589
|
-
`rotation:${sealedKey}:${nowMs}:${index}:fallback:${state.bookingKeys.list().length}`
|
|
2590
|
-
);
|
|
2820
|
+
return records;
|
|
2591
2821
|
};
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2822
|
+
|
|
2823
|
+
// src/admin.ts
|
|
2824
|
+
var ORDER_STATUSES_BY_METHOD = {
|
|
2825
|
+
at_home_phlebotomy: [
|
|
2826
|
+
"received.ordered",
|
|
2827
|
+
"received.requisition_created",
|
|
2828
|
+
"received.requisition_bypassed",
|
|
2829
|
+
"collecting_sample.appointment_pending",
|
|
2830
|
+
"collecting_sample.appointment_scheduled",
|
|
2831
|
+
"collecting_sample.appointment_cancelled",
|
|
2832
|
+
"collecting_sample.draw_completed",
|
|
2833
|
+
"sample_with_lab.partial_results",
|
|
2834
|
+
"completed.completed",
|
|
2835
|
+
"completed.corrected",
|
|
2836
|
+
"cancelled.cancelled",
|
|
2837
|
+
"failed.sample_error"
|
|
2838
|
+
],
|
|
2839
|
+
on_site_collection: [
|
|
2840
|
+
"received.ordered",
|
|
2841
|
+
"received.requisition_created",
|
|
2842
|
+
"received.requisition_bypassed",
|
|
2843
|
+
"sample_with_lab.draw_completed",
|
|
2844
|
+
"sample_with_lab.partial_results",
|
|
2845
|
+
"completed.completed",
|
|
2846
|
+
"completed.corrected",
|
|
2847
|
+
"cancelled.cancelled",
|
|
2848
|
+
"failed.sample_error"
|
|
2849
|
+
],
|
|
2850
|
+
testkit: [
|
|
2851
|
+
"received.ordered",
|
|
2852
|
+
"received.awaiting_registration",
|
|
2853
|
+
"received.registered",
|
|
2854
|
+
"received.requisition_created",
|
|
2855
|
+
"received.requisition_bypassed",
|
|
2856
|
+
"collecting_sample.transit_customer",
|
|
2857
|
+
"collecting_sample.out_for_delivery",
|
|
2858
|
+
"collecting_sample.with_customer",
|
|
2859
|
+
"collecting_sample.transit_lab",
|
|
2860
|
+
"collecting_sample.problem_in_transit_customer",
|
|
2861
|
+
"collecting_sample.problem_in_transit_lab",
|
|
2862
|
+
"sample_with_lab.delivered_to_lab",
|
|
2863
|
+
"sample_with_lab.lab_processing_blocked",
|
|
2864
|
+
"completed.completed",
|
|
2865
|
+
"completed.corrected",
|
|
2866
|
+
"cancelled.cancelled",
|
|
2867
|
+
"cancelled.do_not_process",
|
|
2868
|
+
"failed.sample_error",
|
|
2869
|
+
"failed.failure_to_deliver_to_customer",
|
|
2870
|
+
"failed.failure_to_deliver_to_lab",
|
|
2871
|
+
"failed.lost"
|
|
2872
|
+
],
|
|
2873
|
+
walk_in_test: [
|
|
2874
|
+
"received.ordered",
|
|
2875
|
+
"received.requisition_created",
|
|
2876
|
+
"received.requisition_bypassed",
|
|
2877
|
+
"collecting_sample.appointment_pending",
|
|
2878
|
+
"collecting_sample.appointment_scheduled",
|
|
2879
|
+
"collecting_sample.appointment_cancelled",
|
|
2880
|
+
"collecting_sample.redraw_available",
|
|
2881
|
+
"sample_with_lab.partial_results",
|
|
2882
|
+
"completed.completed",
|
|
2883
|
+
"completed.corrected",
|
|
2884
|
+
"cancelled.cancelled",
|
|
2885
|
+
"failed.sample_error"
|
|
2886
|
+
]
|
|
2615
2887
|
};
|
|
2616
|
-
var
|
|
2888
|
+
var TRANSITION_ALIASES = {
|
|
2889
|
+
at_home_phlebotomy: {
|
|
2890
|
+
requisition_created: "received.requisition_created",
|
|
2891
|
+
scheduled: "collecting_sample.appointment_scheduled",
|
|
2892
|
+
collected: "collecting_sample.draw_completed",
|
|
2893
|
+
partial_results: "sample_with_lab.partial_results",
|
|
2894
|
+
completed: "completed.completed",
|
|
2895
|
+
corrected: "completed.corrected",
|
|
2896
|
+
cancelled: "cancelled.cancelled",
|
|
2897
|
+
failed: "failed.sample_error"
|
|
2898
|
+
},
|
|
2899
|
+
on_site_collection: {
|
|
2900
|
+
requisition_created: "received.requisition_created",
|
|
2901
|
+
collected: "sample_with_lab.draw_completed",
|
|
2902
|
+
at_lab: "sample_with_lab.draw_completed",
|
|
2903
|
+
partial_results: "sample_with_lab.partial_results",
|
|
2904
|
+
completed: "completed.completed",
|
|
2905
|
+
corrected: "completed.corrected",
|
|
2906
|
+
cancelled: "cancelled.cancelled",
|
|
2907
|
+
failed: "failed.sample_error"
|
|
2908
|
+
},
|
|
2909
|
+
testkit: {
|
|
2910
|
+
requisition_created: "received.requisition_created",
|
|
2911
|
+
shipped: "collecting_sample.transit_customer",
|
|
2912
|
+
delivered: "collecting_sample.with_customer",
|
|
2913
|
+
collected: "collecting_sample.transit_lab",
|
|
2914
|
+
at_lab: "sample_with_lab.delivered_to_lab",
|
|
2915
|
+
completed: "completed.completed",
|
|
2916
|
+
corrected: "completed.corrected",
|
|
2917
|
+
cancelled: "cancelled.cancelled",
|
|
2918
|
+
failed: "failed.sample_error"
|
|
2919
|
+
},
|
|
2920
|
+
walk_in_test: {
|
|
2921
|
+
requisition_created: "received.requisition_created",
|
|
2922
|
+
scheduled: "collecting_sample.appointment_scheduled",
|
|
2923
|
+
partial_results: "sample_with_lab.partial_results",
|
|
2924
|
+
completed: "completed.completed",
|
|
2925
|
+
corrected: "completed.corrected",
|
|
2926
|
+
cancelled: "cancelled.cancelled",
|
|
2927
|
+
failed: "failed.sample_error"
|
|
2928
|
+
}
|
|
2929
|
+
};
|
|
2930
|
+
var RESULT_FIXTURES = {
|
|
2931
|
+
normal: { interpretation: "normal" },
|
|
2932
|
+
abnormal: { interpretation: "abnormal" },
|
|
2933
|
+
critical: { interpretation: "critical" },
|
|
2934
|
+
missing_results: { interpretation: "normal", has_missing_results: true }
|
|
2935
|
+
};
|
|
2936
|
+
var FAULT_PRESETS = {
|
|
2937
|
+
sandbox_user_quota: {
|
|
2938
|
+
operationId: "create_user_v2_user_post",
|
|
2939
|
+
status: 400,
|
|
2940
|
+
body: sandboxUserQuotaBody(50)
|
|
2941
|
+
},
|
|
2942
|
+
rate_limited: {
|
|
2943
|
+
status: 429,
|
|
2944
|
+
body: { detail: "Too Many Requests" },
|
|
2945
|
+
headers: { "retry-after": "1" }
|
|
2946
|
+
},
|
|
2947
|
+
server_error: { status: 500, body: { detail: "Internal Server Error" } },
|
|
2948
|
+
bad_gateway: { status: 502, body: { detail: "Bad Gateway" } },
|
|
2949
|
+
unavailable: { status: 503, body: { detail: "Service Unavailable" } }
|
|
2950
|
+
};
|
|
2951
|
+
var methodOf = (order) => typeof order.lab_test.method === "string" && order.lab_test.method !== "" ? order.lab_test.method : typeof order.details?.type === "string" && order.details.type !== "" ? order.details.type : "at_home_phlebotomy";
|
|
2952
|
+
var resolveTransition = (method, target) => {
|
|
2953
|
+
const allowed = ORDER_STATUSES_BY_METHOD[method];
|
|
2954
|
+
if (!allowed) return { error: `unknown collection method ${method}` };
|
|
2955
|
+
const alias = TRANSITION_ALIASES[method]?.[target];
|
|
2956
|
+
const short = alias ?? (target.split(".").length === 3 ? null : target);
|
|
2957
|
+
if (short !== null && allowed.includes(short)) {
|
|
2958
|
+
const [phase, event] = short.split(".");
|
|
2959
|
+
return { status: `${phase}.${method}.${event}` };
|
|
2960
|
+
}
|
|
2961
|
+
if (target.split(".").length === 3) {
|
|
2962
|
+
const [phase, targetMethod, event] = target.split(".");
|
|
2963
|
+
if (targetMethod === method && allowed.includes(`${phase}.${event}`)) return { status: target };
|
|
2964
|
+
}
|
|
2965
|
+
const names = Object.keys(TRANSITION_ALIASES[method] ?? {});
|
|
2966
|
+
return {
|
|
2967
|
+
error: `${JSON.stringify(target)} is not a ${method} status. Use one of: ${names.join(", ")}, or a full status such as ${allowed.slice(0, 2).map((s) => `${s.split(".")[0]}.${method}.${s.split(".")[1]}`).join(", ")}`
|
|
2968
|
+
};
|
|
2969
|
+
};
|
|
2970
|
+
var adminError2 = (status, message) => jsonRes(status, { error: { type: "mockingbird_admin", message } });
|
|
2971
|
+
var isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2972
|
+
var guarded = (run) => {
|
|
2973
|
+
try {
|
|
2974
|
+
return run();
|
|
2975
|
+
} catch (error) {
|
|
2976
|
+
if (error instanceof TypeError) return adminError2(400, error.message);
|
|
2977
|
+
if (error instanceof Error && error.name === "LabAccountConflict") {
|
|
2978
|
+
return adminError2(409, error.message);
|
|
2979
|
+
}
|
|
2980
|
+
const { status, message } = fixtureErrorMessage(error);
|
|
2981
|
+
return adminError2(status, message);
|
|
2982
|
+
}
|
|
2983
|
+
};
|
|
2984
|
+
var junctionAdminRoutes = (options) => (runtime) => {
|
|
2985
|
+
const api = (request2) => runtime.instance(request2.namespace);
|
|
2986
|
+
return {
|
|
2987
|
+
"GET /orders": (request2) => jsonRes(200, {
|
|
2988
|
+
orders: api(request2).orders().map((order) => ({
|
|
2989
|
+
id: order.id,
|
|
2990
|
+
user_id: order.user_id,
|
|
2991
|
+
method: methodOf(order),
|
|
2992
|
+
status: order.last_event.status,
|
|
2993
|
+
updated_at: order.updated_at
|
|
2994
|
+
}))
|
|
2995
|
+
}),
|
|
2996
|
+
"POST /orders/:id/transition": (request2) => {
|
|
2997
|
+
const body = isRecord4(request2.body) ? request2.body : {};
|
|
2998
|
+
const order = api(request2).order(request2.params.id);
|
|
2999
|
+
if (!order) return adminError2(404, `no order ${request2.params.id} in ${request2.namespace}`);
|
|
3000
|
+
if (typeof body.to !== "string") {
|
|
3001
|
+
return adminError2(400, 'body needs "to": a status like "completed" or "at_lab"');
|
|
3002
|
+
}
|
|
3003
|
+
const method = methodOf(order);
|
|
3004
|
+
const resolved = resolveTransition(method, body.to);
|
|
3005
|
+
if ("error" in resolved) return adminError2(400, resolved.error);
|
|
3006
|
+
let flags = isRecord4(body.flags) ? body.flags : null;
|
|
3007
|
+
if (typeof body.result === "string") {
|
|
3008
|
+
const named = RESULT_FIXTURES[body.result];
|
|
3009
|
+
if (!named) {
|
|
3010
|
+
return adminError2(
|
|
3011
|
+
400,
|
|
3012
|
+
`no result fixture ${body.result}; one of ${Object.keys(RESULT_FIXTURES).join(", ")}`
|
|
3013
|
+
);
|
|
3014
|
+
}
|
|
3015
|
+
flags = { ...named, ...flags };
|
|
3016
|
+
}
|
|
3017
|
+
const updated = api(request2).transitionOrder(order.id, resolved.status, {
|
|
3018
|
+
now: runtime.clock.now,
|
|
3019
|
+
flags
|
|
3020
|
+
});
|
|
3021
|
+
return jsonRes(200, {
|
|
3022
|
+
id: order.id,
|
|
3023
|
+
status: updated?.last_event.status,
|
|
3024
|
+
events: updated?.events
|
|
3025
|
+
});
|
|
3026
|
+
},
|
|
3027
|
+
"GET /result-fixtures": () => jsonRes(200, { fixtures: RESULT_FIXTURES }),
|
|
3028
|
+
"GET /results/:id": (request2) => {
|
|
3029
|
+
const fixture = api(request2).resultFixture(request2.params.id);
|
|
3030
|
+
return fixture ? jsonRes(200, fixture) : adminError2(404, "no result fixture for that order");
|
|
3031
|
+
},
|
|
3032
|
+
"PUT /results/:id": (request2) => {
|
|
3033
|
+
if (!isRecord4(request2.body)) return adminError2(400, "expected a result fixture object");
|
|
3034
|
+
const fixture = { name: "custom", ...request2.body };
|
|
3035
|
+
if (fixture.results !== void 0 && !Array.isArray(fixture.results)) {
|
|
3036
|
+
return adminError2(400, "results must be an array of result lines");
|
|
3037
|
+
}
|
|
3038
|
+
return api(request2).installResultFixture(request2.params.id, fixture) ? jsonRes(200, fixture) : adminError2(404, `no order ${request2.params.id} in ${request2.namespace}`);
|
|
3039
|
+
},
|
|
3040
|
+
"GET /lab-accounts": (request2) => jsonRes(200, { data: api(request2).labAccounts() }),
|
|
3041
|
+
"PUT /lab-accounts": (request2) => {
|
|
3042
|
+
const body = isRecord4(request2.body) ? request2.body : {};
|
|
3043
|
+
const accounts = body.accounts;
|
|
3044
|
+
const presets = body.presets;
|
|
3045
|
+
if (accounts === void 0 && presets === void 0 || accounts !== void 0 && accounts !== null && !Array.isArray(accounts) || presets !== void 0 && !Array.isArray(presets)) {
|
|
3046
|
+
return adminError2(
|
|
3047
|
+
400,
|
|
3048
|
+
'body needs "accounts": an array (or null to restore the default), and/or "presets": an array of preset names'
|
|
3049
|
+
);
|
|
3050
|
+
}
|
|
3051
|
+
const layout = presets !== void 0 ? {
|
|
3052
|
+
presets,
|
|
3053
|
+
...Array.isArray(accounts) ? { accounts } : {}
|
|
3054
|
+
} : accounts === null ? void 0 : accounts;
|
|
3055
|
+
return guarded(() => jsonRes(200, { data: api(request2).configureLabAccounts(layout) }));
|
|
3056
|
+
},
|
|
3057
|
+
"POST /lab-accounts": (request2) => {
|
|
3058
|
+
if (!isRecord4(request2.body)) return adminError2(400, "expected one lab account object");
|
|
3059
|
+
const input = request2.body;
|
|
3060
|
+
return guarded(() => jsonRes(201, api(request2).addLabAccount(input)));
|
|
3061
|
+
},
|
|
3062
|
+
"PATCH /lab-accounts/:id": (request2) => {
|
|
3063
|
+
if (!isRecord4(request2.body))
|
|
3064
|
+
return adminError2(400, "expected an object of fields to change");
|
|
3065
|
+
const patch = request2.body;
|
|
3066
|
+
return guarded(() => {
|
|
3067
|
+
const updated = api(request2).patchLabAccount(request2.params.id, patch);
|
|
3068
|
+
return updated ? jsonRes(200, updated) : adminError2(404, `no lab account ${request2.params.id} in ${request2.namespace}`);
|
|
3069
|
+
});
|
|
3070
|
+
},
|
|
3071
|
+
"DELETE /lab-accounts/:id": (request2) => api(request2).removeLabAccount(request2.params.id) ? jsonRes(200, { status: "ok" }) : adminError2(404, `no lab account ${request2.params.id} in ${request2.namespace}`),
|
|
3072
|
+
"GET /lab-accounts/presets": (request2) => jsonRes(200, {
|
|
3073
|
+
presets: Object.fromEntries(
|
|
3074
|
+
Object.keys(LAB_ACCOUNT_PRESETS).map((name) => {
|
|
3075
|
+
const record = labAccountFromPreset(name, { teamId: api(request2).teamId });
|
|
3076
|
+
return [name, record ? renderLabAccount(record) : null];
|
|
3077
|
+
})
|
|
3078
|
+
)
|
|
3079
|
+
}),
|
|
3080
|
+
"POST /lab-accounts/presets/:name": (request2) => {
|
|
3081
|
+
const body = isRecord4(request2.body) ? request2.body : {};
|
|
3082
|
+
if (body.id !== void 0 && typeof body.id !== "string") {
|
|
3083
|
+
return adminError2(400, "id must be a string");
|
|
3084
|
+
}
|
|
3085
|
+
const name = request2.params.name;
|
|
3086
|
+
return guarded(() => {
|
|
3087
|
+
const record = api(request2).addLabAccountPreset(name, body.id);
|
|
3088
|
+
return record ? jsonRes(201, record) : adminError2(
|
|
3089
|
+
404,
|
|
3090
|
+
`no lab-account preset ${name}; one of ${Object.keys(LAB_ACCOUNT_PRESETS).join(", ")}`
|
|
3091
|
+
);
|
|
3092
|
+
});
|
|
3093
|
+
},
|
|
3094
|
+
"GET /team": (request2) => jsonRes(200, { teamId: api(request2).teamId }),
|
|
3095
|
+
"GET /limits": (request2) => jsonRes(200, { limits: api(request2).limits }),
|
|
3096
|
+
"PUT /limits": (request2) => {
|
|
3097
|
+
if (!isRecord4(request2.body)) return adminError2(400, "expected an object of limits");
|
|
3098
|
+
const input = request2.body;
|
|
3099
|
+
return guarded(() => jsonRes(200, { limits: api(request2).configureLimits(input) }));
|
|
3100
|
+
},
|
|
3101
|
+
"GET /identity": (request2) => jsonRes(200, { identity: api(request2).identity }),
|
|
3102
|
+
"PUT /identity": (request2) => {
|
|
3103
|
+
const mode = isRecord4(request2.body) ? request2.body.mode : void 0;
|
|
3104
|
+
if (!IDENTITY_MODES.includes(mode)) {
|
|
3105
|
+
return adminError2(400, `body needs "mode": one of ${IDENTITY_MODES.join(", ")}`);
|
|
3106
|
+
}
|
|
3107
|
+
api(request2).identity = mode;
|
|
3108
|
+
return jsonRes(200, { identity: mode });
|
|
3109
|
+
},
|
|
3110
|
+
"POST /users": (request2) => {
|
|
3111
|
+
if (!isRecord4(request2.body)) return adminError2(400, "expected one user object");
|
|
3112
|
+
const input = request2.body;
|
|
3113
|
+
return guarded(() => jsonRes(201, api(request2).insertUsers([input])[0]));
|
|
3114
|
+
},
|
|
3115
|
+
"POST /users/bulk": (request2) => {
|
|
3116
|
+
const users = isRecord4(request2.body) ? request2.body.users : void 0;
|
|
3117
|
+
if (!Array.isArray(users)) return adminError2(400, 'body needs "users": an array');
|
|
3118
|
+
return guarded(
|
|
3119
|
+
() => jsonRes(201, { users: api(request2).insertUsers(users) })
|
|
3120
|
+
);
|
|
3121
|
+
},
|
|
3122
|
+
"DELETE /users/:id": (request2) => api(request2).hardDeleteUser(request2.params.id) ? jsonRes(200, { status: "ok" }) : adminError2(404, `no user ${request2.params.id} in ${request2.namespace}`),
|
|
3123
|
+
"POST /orders": (request2) => {
|
|
3124
|
+
if (!isRecord4(request2.body)) return adminError2(400, "expected one order object");
|
|
3125
|
+
const { emitWebhooks, ...input } = request2.body;
|
|
3126
|
+
return guarded(
|
|
3127
|
+
() => jsonRes(
|
|
3128
|
+
201,
|
|
3129
|
+
api(request2).insertOrders([input], {
|
|
3130
|
+
emitWebhooks: emitWebhooks === true
|
|
3131
|
+
})[0]
|
|
3132
|
+
)
|
|
3133
|
+
);
|
|
3134
|
+
},
|
|
3135
|
+
"POST /import": (request2) => {
|
|
3136
|
+
if (!isRecord4(request2.body)) {
|
|
3137
|
+
return adminError2(400, 'expected { "users": [...], "orders": [...] }');
|
|
3138
|
+
}
|
|
3139
|
+
const { emitWebhooks, ...fixtures } = request2.body;
|
|
3140
|
+
return guarded(() => {
|
|
3141
|
+
const loaded = api(request2).importFixtures(fixtures, {
|
|
3142
|
+
emitWebhooks: emitWebhooks === true
|
|
3143
|
+
});
|
|
3144
|
+
return jsonRes(201, loaded);
|
|
3145
|
+
});
|
|
3146
|
+
},
|
|
3147
|
+
"GET /corpus": (request2) => jsonRes(200, {
|
|
3148
|
+
corpus: api(request2).corpusInfo() ?? null,
|
|
3149
|
+
geo: api(request2).geoMode
|
|
3150
|
+
}),
|
|
3151
|
+
"PUT /geo": (request2) => {
|
|
3152
|
+
const mode = isRecord4(request2.body) ? request2.body.mode : void 0;
|
|
3153
|
+
if (mode !== "corpus" && mode !== "synthetic") {
|
|
3154
|
+
return adminError2(400, 'body needs "mode": "corpus" or "synthetic"');
|
|
3155
|
+
}
|
|
3156
|
+
api(request2).geoMode = mode;
|
|
3157
|
+
return jsonRes(200, { geo: mode });
|
|
3158
|
+
},
|
|
3159
|
+
"GET /webhooks/events": (request2) => jsonRes(200, { events: api(request2).webhookEvents() }),
|
|
3160
|
+
"GET /webhooks": (request2) => options.webhooks ? jsonRes(200, { deliveries: options.webhooks.deliveries(request2.namespace) }) : adminError2(
|
|
3161
|
+
409,
|
|
3162
|
+
"webhook delivery is off; serve with --webhook-url and --webhook-secret"
|
|
3163
|
+
),
|
|
3164
|
+
"POST /webhooks/:id/replay": async (request2) => {
|
|
3165
|
+
if (!options.webhooks) return adminError2(409, "webhook delivery is off");
|
|
3166
|
+
const delivery = await options.webhooks.replay(request2.params.id);
|
|
3167
|
+
return delivery ? jsonRes(200, delivery) : adminError2(404, `no message ${request2.params.id}`);
|
|
3168
|
+
},
|
|
3169
|
+
"POST /webhooks/flush": async () => {
|
|
3170
|
+
if (!options.webhooks) return adminError2(409, "webhook delivery is off");
|
|
3171
|
+
await options.webhooks.flush();
|
|
3172
|
+
return jsonRes(200, { status: "ok" });
|
|
3173
|
+
},
|
|
3174
|
+
"GET /faults/presets": () => jsonRes(200, { presets: FAULT_PRESETS }),
|
|
3175
|
+
"POST /faults/presets/:name": (request2) => {
|
|
3176
|
+
const preset = FAULT_PRESETS[request2.params.name];
|
|
3177
|
+
if (!preset) {
|
|
3178
|
+
return adminError2(
|
|
3179
|
+
404,
|
|
3180
|
+
`no preset ${request2.params.name}; one of ${Object.keys(FAULT_PRESETS).join(", ")}`
|
|
3181
|
+
);
|
|
3182
|
+
}
|
|
3183
|
+
const overrides = isRecord4(request2.body) ? request2.body : {};
|
|
3184
|
+
const rule = runtime.faults.add({
|
|
3185
|
+
namespace: request2.namespace,
|
|
3186
|
+
...preset,
|
|
3187
|
+
...overrides,
|
|
3188
|
+
id: typeof overrides.id === "string" ? overrides.id : request2.params.name
|
|
3189
|
+
});
|
|
3190
|
+
return jsonRes(201, rule);
|
|
3191
|
+
}
|
|
3192
|
+
};
|
|
3193
|
+
};
|
|
3194
|
+
|
|
3195
|
+
// src/not-found.ts
|
|
3196
|
+
var ORDER_NOT_FOUND = {
|
|
3197
|
+
get_order_v3_order__order_id__get: "This order doesn't exist",
|
|
3198
|
+
cancel_order_v3_order__order_id__cancel_post: "Order doesn't exist",
|
|
3199
|
+
simulate_order_v3_order__order_id__test_post: "Order doesn't exist",
|
|
3200
|
+
get_order_requisition_pdf_v3_order__order_id__requisition_pdf_get: "This order doesn't exist",
|
|
3201
|
+
get_result_raw_v3_order__order_id__result_get: "Order not found",
|
|
3202
|
+
get_result_metadata_v3_order__order_id__result_metadata_get: "Order not found",
|
|
3203
|
+
get_result_pdf_v3_order__order_id__result_pdf_get: "Order not found",
|
|
3204
|
+
get_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_get: "This order doesn't exist.",
|
|
3205
|
+
book_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_book_post: "This order doesn't exist.",
|
|
3206
|
+
reschedule_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_reschedule_patch: "This order doesn't exist.",
|
|
3207
|
+
cancel_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_cancel_patch: "This order doesn't exist.",
|
|
3208
|
+
get_psc_appointment_v3_order__order_id__psc_appointment_get: "This order doesn't exist.",
|
|
3209
|
+
book_psc_appointment_v3_order__order_id__psc_appointment_book_post: "This order doesn't exist.",
|
|
3210
|
+
reschedule_psc_appointment_v3_order__order_id__psc_appointment_reschedule_patch: "This order doesn't exist.",
|
|
3211
|
+
cancel_psc_appointment_v3_order__order_id__psc_appointment_cancel_patch: "This order doesn't exist."
|
|
3212
|
+
};
|
|
3213
|
+
var MISS_HEADER = "x-mockingbird-miss";
|
|
3214
|
+
var KNOWN_HEADER = "x-mockingbird-known";
|
|
3215
|
+
function missing(state, kind, id, detail) {
|
|
3216
|
+
throw new HttpError(
|
|
3217
|
+
404,
|
|
3218
|
+
{ detail },
|
|
3219
|
+
{
|
|
3220
|
+
// Percent-encoded: an id is caller input, and a header value must be ASCII.
|
|
3221
|
+
[MISS_HEADER]: `${kind} ${encodeURIComponent(id).replace(/%3A/gi, ":")}`,
|
|
3222
|
+
[KNOWN_HEADER]: `users=${state.users.count()} orders=${state.orders.count()}`
|
|
3223
|
+
}
|
|
3224
|
+
);
|
|
3225
|
+
}
|
|
3226
|
+
function orderMissing(state, operationId, id) {
|
|
3227
|
+
return missing(state, "order", id, ORDER_NOT_FOUND[operationId] ?? "This order doesn't exist");
|
|
3228
|
+
}
|
|
3229
|
+
|
|
3230
|
+
// src/scheduling.ts
|
|
3231
|
+
var UNKNOWN_ZIP_STATUS = 424;
|
|
3232
|
+
var UNKNOWN_ZIP_ERROR_TYPE = "MOCKINGBIRD_UNKNOWN_ZIP";
|
|
3233
|
+
var requireCoveredZip = (state, zip) => {
|
|
3234
|
+
if (state.geoMode !== "corpus" || state.coveredZips.has(zip)) return;
|
|
3235
|
+
throw new HttpError(UNKNOWN_ZIP_STATUS, {
|
|
3236
|
+
detail: {
|
|
3237
|
+
error_type: UNKNOWN_ZIP_ERROR_TYPE,
|
|
3238
|
+
error_message: `ZIP ${zip} is not in the loaded Junction corpus (${String(state.coveredZips.size)} ZIPs covered). Record it with \`mockingbird-junction corpus pull --zip ${zip}\`, or serve with --geo synthetic to invent coverage.`,
|
|
3239
|
+
zip_code: zip,
|
|
3240
|
+
corpus: state.corpusLabel ?? null
|
|
3241
|
+
}
|
|
3242
|
+
});
|
|
3243
|
+
};
|
|
3244
|
+
var cachedResponse = (state, context) => {
|
|
3245
|
+
const body = context.request.method.toUpperCase() === "GET" || context.request.method.toUpperCase() === "HEAD" ? void 0 : context.body.kind === "json" ? context.body.value : context.body.kind === "form" ? context.body.value : void 0;
|
|
3246
|
+
const key = state.cacheKeyForRequest(
|
|
3247
|
+
context.request.method,
|
|
3248
|
+
context.url.pathname,
|
|
3249
|
+
context.url.searchParams,
|
|
3250
|
+
body
|
|
3251
|
+
);
|
|
3252
|
+
const cached = state.getGetCache(key);
|
|
3253
|
+
if (!cached) return void 0;
|
|
3254
|
+
if (key.toLowerCase().includes("availability")) {
|
|
3255
|
+
materializeAvailabilityBookingKeys(state, context, cached.body);
|
|
3256
|
+
rotateAvailabilityBookingKeys(state, cached.body, context.now());
|
|
3257
|
+
}
|
|
3258
|
+
const headers = new Headers(cached.headers);
|
|
3259
|
+
headers.delete("content-encoding");
|
|
3260
|
+
headers.delete("content-length");
|
|
3261
|
+
headers.delete("transfer-encoding");
|
|
3262
|
+
if (!headers.has("content-type")) headers.set("content-type", "application/json");
|
|
3263
|
+
return new Response(JSON.stringify(cached.body), { status: cached.status, headers });
|
|
3264
|
+
};
|
|
3265
|
+
var materializeAvailabilityBookingKeys = (state, context, cachedBody) => {
|
|
3266
|
+
const requestBody = context.body.kind === "json" && typeof context.body.value === "object" && context.body.value !== null && !Array.isArray(context.body.value) ? context.body.value : {};
|
|
3267
|
+
const zip = typeof requestBody.zip_code === "string" && /^\d{5}/.test(requestBody.zip_code) ? requestBody.zip_code.slice(0, 5) : "85004";
|
|
3268
|
+
const path = context.url.pathname;
|
|
3269
|
+
const modalityHint = path.includes("psc") ? "patient_service_center" : path.includes("phlebotomy") ? "phlebotomy" : void 0;
|
|
3270
|
+
state.hydrateBookingKeysFromAvailability(cachedBody, context.now(), zip, modalityHint);
|
|
3271
|
+
if (typeof cachedBody === "object" && cachedBody !== null && !Array.isArray(cachedBody)) {
|
|
3272
|
+
const root = cachedBody;
|
|
3273
|
+
const dayBuckets = [];
|
|
3274
|
+
if (Array.isArray(root.days)) dayBuckets.push(...root.days);
|
|
3275
|
+
if (Array.isArray(root.slots)) dayBuckets.push(...root.slots);
|
|
3276
|
+
for (const day of dayBuckets) {
|
|
3277
|
+
if (typeof day !== "object" || day === null || Array.isArray(day)) continue;
|
|
3278
|
+
const daySlots = day.slots;
|
|
3279
|
+
const slots = Array.isArray(daySlots) ? daySlots : [day];
|
|
3280
|
+
for (const entry of slots) {
|
|
3281
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) continue;
|
|
3282
|
+
const slot = entry;
|
|
3283
|
+
const bookingKey = typeof slot.booking_key === "string" ? slot.booking_key : "";
|
|
3284
|
+
if (!bookingKey) continue;
|
|
3285
|
+
const record = state.bookingKeys.get(bookingKey);
|
|
3286
|
+
if (!record) continue;
|
|
3287
|
+
if (modalityHint) record.modality = modalityHint;
|
|
3288
|
+
record.zip_code = zip;
|
|
3289
|
+
record.provider = record.modality === "patient_service_center" ? "quest" : "getlabs";
|
|
3290
|
+
record.address = addressFromAvailabilityRequest(requestBody, zip);
|
|
3291
|
+
record.location = zipLocation(zip);
|
|
3292
|
+
state.bookingKeys.update(bookingKey, record);
|
|
3293
|
+
}
|
|
3294
|
+
}
|
|
3295
|
+
}
|
|
3296
|
+
};
|
|
3297
|
+
var rotateAvailabilityBookingKeys = (state, cachedBody, nowMs) => {
|
|
3298
|
+
if (typeof cachedBody !== "object" || cachedBody === null || Array.isArray(cachedBody)) return;
|
|
3299
|
+
const root = cachedBody;
|
|
3300
|
+
const dayBuckets = [];
|
|
3301
|
+
if (Array.isArray(root.days)) dayBuckets.push(...root.days);
|
|
3302
|
+
if (Array.isArray(root.slots)) dayBuckets.push(...root.slots);
|
|
3303
|
+
for (const day of dayBuckets) {
|
|
3304
|
+
if (typeof day !== "object" || day === null || Array.isArray(day)) continue;
|
|
3305
|
+
const daySlots = day.slots;
|
|
3306
|
+
const slots = Array.isArray(daySlots) ? daySlots : [day];
|
|
3307
|
+
for (let index = 0; index < slots.length; index += 1) {
|
|
3308
|
+
const slot = slots[index];
|
|
3309
|
+
if (typeof slot !== "object" || slot === null || Array.isArray(slot)) continue;
|
|
3310
|
+
const entry = slot;
|
|
3311
|
+
const sealedKey = typeof entry.booking_key === "string" ? entry.booking_key : "";
|
|
3312
|
+
if (!sealedKey) continue;
|
|
3313
|
+
const sealed = state.bookingKeys.get(sealedKey);
|
|
3314
|
+
if (!sealed) continue;
|
|
3315
|
+
const freshKey = bookingKeyRotationFor(state, sealedKey, nowMs, index);
|
|
3316
|
+
const record = {
|
|
3317
|
+
...sealed,
|
|
3318
|
+
key: freshKey,
|
|
3319
|
+
consumed_by_order_id: null,
|
|
3320
|
+
created_at: new Date(nowMs).toISOString()
|
|
3321
|
+
};
|
|
3322
|
+
state.bookingKeys.insert(freshKey, record);
|
|
3323
|
+
entry.booking_key = freshKey;
|
|
3324
|
+
}
|
|
3325
|
+
}
|
|
3326
|
+
};
|
|
3327
|
+
var bookingKeyRotationFor = (state, sealedKey, nowMs, index) => {
|
|
3328
|
+
for (let attempt = 0; attempt < 64; attempt += 1) {
|
|
3329
|
+
const candidate = state.bookingKeyFor(`rotation:${sealedKey}:${nowMs}:${index}:${attempt}`);
|
|
3330
|
+
if (!state.bookingKeys.has(candidate)) return candidate;
|
|
3331
|
+
}
|
|
3332
|
+
return state.bookingKeyFor(
|
|
3333
|
+
`rotation:${sealedKey}:${nowMs}:${index}:fallback:${state.bookingKeys.list().length}`
|
|
3334
|
+
);
|
|
3335
|
+
};
|
|
3336
|
+
var rotateGeneratedAvailabilityKeys = (state, days, nowMs, override) => {
|
|
3337
|
+
for (const day of days) {
|
|
3338
|
+
const slots = Array.isArray(day.slots) ? day.slots : [];
|
|
3339
|
+
for (let index = 0; index < slots.length; index += 1) {
|
|
3340
|
+
const slot = slots[index];
|
|
3341
|
+
if (typeof slot !== "object" || slot === null || Array.isArray(slot)) continue;
|
|
3342
|
+
const entry = slot;
|
|
3343
|
+
const currentKey = typeof entry.booking_key === "string" ? entry.booking_key : "";
|
|
3344
|
+
if (!currentKey) continue;
|
|
3345
|
+
const current = state.bookingKeys.get(currentKey);
|
|
3346
|
+
if (!current) continue;
|
|
3347
|
+
const freshKey = bookingKeyRotationFor(state, currentKey, nowMs, index);
|
|
3348
|
+
const record = {
|
|
3349
|
+
...current,
|
|
3350
|
+
key: freshKey,
|
|
3351
|
+
...override ?? {},
|
|
3352
|
+
consumed_by_order_id: null,
|
|
3353
|
+
created_at: new Date(nowMs).toISOString()
|
|
3354
|
+
};
|
|
3355
|
+
state.bookingKeys.insert(freshKey, record);
|
|
3356
|
+
entry.booking_key = freshKey;
|
|
3357
|
+
}
|
|
3358
|
+
}
|
|
3359
|
+
};
|
|
3360
|
+
var zipTimezone = (zip) => {
|
|
2617
3361
|
const prefix = Number(zip.slice(0, 3));
|
|
2618
3362
|
if (!Number.isFinite(prefix) || prefix === 0) return "America/New_York";
|
|
2619
3363
|
if (prefix < 500) return "America/New_York";
|
|
@@ -2934,7 +3678,7 @@ var zipCodeOf = (context, required) => {
|
|
|
2934
3678
|
if (typeof raw !== "string") throw new HttpError(422, { detail: "zip_code must be a string" });
|
|
2935
3679
|
return raw;
|
|
2936
3680
|
};
|
|
2937
|
-
var labAccountOf = (context) => {
|
|
3681
|
+
var labAccountOf = (state, context) => {
|
|
2938
3682
|
const raw = context.query.lab_account_id;
|
|
2939
3683
|
if (raw === void 0) return null;
|
|
2940
3684
|
if (typeof raw !== "string" || !isUuid(raw)) {
|
|
@@ -2942,8 +3686,8 @@ var labAccountOf = (context) => {
|
|
|
2942
3686
|
detail: [uuidError(typeof raw === "string" ? raw : String(raw), ["query", "lab_account_id"])]
|
|
2943
3687
|
});
|
|
2944
3688
|
}
|
|
2945
|
-
const account2 = labAccountById(raw);
|
|
2946
|
-
if (!account2
|
|
3689
|
+
const account2 = labAccountById(raw, state.listLabAccounts());
|
|
3690
|
+
if (!account2 || !isLinkedToTeam(account2, state.teamId))
|
|
2947
3691
|
throw new HttpError(404, { detail: "Lab account does not exist" });
|
|
2948
3692
|
if (account2.status !== "active") throw new HttpError(400, { detail: "Lab account is not active" });
|
|
2949
3693
|
return account2;
|
|
@@ -3137,19 +3881,15 @@ function notFound(message) {
|
|
|
3137
3881
|
function invalidBookingKey() {
|
|
3138
3882
|
throw new HttpError(400, { detail: "Invalid or expired booking key" });
|
|
3139
3883
|
}
|
|
3140
|
-
var requireOrder = (state, orderId, context
|
|
3884
|
+
var requireOrder = (state, orderId, context) => {
|
|
3141
3885
|
if (!isUuid(orderId)) {
|
|
3142
3886
|
throw new HttpError(422, { detail: [uuidError(orderId, ["path", "order_id"])] });
|
|
3143
3887
|
}
|
|
3144
|
-
const
|
|
3145
|
-
if (order === void 0) notFound(missingMessage);
|
|
3146
|
-
const loaded = order;
|
|
3888
|
+
const loaded = state.orders.get(orderId) ?? orderMissing(state, context.operation.operationId, orderId);
|
|
3147
3889
|
state.applyDueSimulateTransitions(context.now(), (_due, finalStatus, flags) => {
|
|
3148
3890
|
applySimulateTransition(state, loaded, finalStatus, flags, context);
|
|
3149
3891
|
});
|
|
3150
|
-
|
|
3151
|
-
if (fresh === void 0) notFound(missingMessage);
|
|
3152
|
-
return fresh;
|
|
3892
|
+
return state.orders.get(orderId) ?? orderMissing(state, context.operation.operationId, orderId);
|
|
3153
3893
|
};
|
|
3154
3894
|
var orderCollectionMethod = (order) => {
|
|
3155
3895
|
if (typeof order.lab_test.method === "string" && order.lab_test.method.length > 0) {
|
|
@@ -3376,7 +4116,7 @@ var schedulingHandlers = (state) => ({
|
|
|
3376
4116
|
}
|
|
3377
4117
|
const zip = rawZip.slice(0, 5);
|
|
3378
4118
|
requireCoveredZip(state, zip);
|
|
3379
|
-
return jsonRes(200, areaInfoFor(zip, radius, labAccountOf(context)));
|
|
4119
|
+
return jsonRes(200, areaInfoFor(zip, radius, labAccountOf(state, context)));
|
|
3380
4120
|
},
|
|
3381
4121
|
get_psc_info_v3_order_psc_info_get: async (context) => {
|
|
3382
4122
|
const hit = cachedResponse(state, context);
|
|
@@ -4066,6 +4806,80 @@ var labAccountStatusFilter = (context) => {
|
|
|
4066
4806
|
]
|
|
4067
4807
|
});
|
|
4068
4808
|
};
|
|
4809
|
+
var enumError = (name, value, allowed) => {
|
|
4810
|
+
const expected = allowed.length === 1 ? `'${allowed[0]}'` : `${allowed.slice(0, -1).map((entry) => `'${entry}'`).join(", ")} or '${allowed.at(-1)}'`;
|
|
4811
|
+
return {
|
|
4812
|
+
type: "enum",
|
|
4813
|
+
loc: ["query", name],
|
|
4814
|
+
msg: `Input should be ${expected}`,
|
|
4815
|
+
input: value,
|
|
4816
|
+
ctx: { expected }
|
|
4817
|
+
};
|
|
4818
|
+
};
|
|
4819
|
+
var listParam = (params, name) => {
|
|
4820
|
+
const values = params.getAll(name);
|
|
4821
|
+
if (values.length === 0) return null;
|
|
4822
|
+
if (values.length === 1 && values[0]?.trim().startsWith("[")) {
|
|
4823
|
+
try {
|
|
4824
|
+
const parsed = JSON.parse(values[0]);
|
|
4825
|
+
if (Array.isArray(parsed)) return parsed.map(String);
|
|
4826
|
+
} catch {
|
|
4827
|
+
}
|
|
4828
|
+
}
|
|
4829
|
+
return values;
|
|
4830
|
+
};
|
|
4831
|
+
var LAB_TEST_FILTER_ENUMS = {
|
|
4832
|
+
generation_method: ["auto", "manual", "all"],
|
|
4833
|
+
collection_method: ["testkit", "walk_in_test", "at_home_phlebotomy", "on_site_collection"],
|
|
4834
|
+
status: ["active", "pending_approval", "inactive"],
|
|
4835
|
+
order_key: ["price", "created_at", "updated_at"],
|
|
4836
|
+
order_direction: ["asc", "desc"]
|
|
4837
|
+
};
|
|
4838
|
+
var filterLabTests = (tests, params) => {
|
|
4839
|
+
const errors = [];
|
|
4840
|
+
const pick = (name2) => {
|
|
4841
|
+
const value = params.get(name2);
|
|
4842
|
+
if (value === null) return null;
|
|
4843
|
+
const allowed = LAB_TEST_FILTER_ENUMS[name2];
|
|
4844
|
+
if (allowed && !allowed.includes(value)) errors.push(enumError(name2, value, allowed));
|
|
4845
|
+
return value;
|
|
4846
|
+
};
|
|
4847
|
+
const generation = pick("generation_method") ?? "manual";
|
|
4848
|
+
const collection = pick("collection_method");
|
|
4849
|
+
const status = pick("status");
|
|
4850
|
+
const orderKey = pick("order_key");
|
|
4851
|
+
const direction = pick("order_direction") ?? "asc";
|
|
4852
|
+
const labSlug = params.get("lab_slug");
|
|
4853
|
+
const name = params.get("name")?.toLowerCase() ?? null;
|
|
4854
|
+
const markerIds = listParam(params, "marker_ids");
|
|
4855
|
+
const providerIds = listParam(params, "provider_ids");
|
|
4856
|
+
for (const id of markerIds ?? []) {
|
|
4857
|
+
if (!/^-?\d+$/.test(id))
|
|
4858
|
+
errors.push({
|
|
4859
|
+
type: "int_parsing",
|
|
4860
|
+
loc: ["query", "marker_ids", markerIds?.indexOf(id) ?? 0],
|
|
4861
|
+
msg: "Input should be a valid integer, unable to parse string as an integer",
|
|
4862
|
+
input: id
|
|
4863
|
+
});
|
|
4864
|
+
}
|
|
4865
|
+
if (errors.length > 0) throw new HttpError(422, { detail: errors });
|
|
4866
|
+
const filtered = tests.filter((test) => {
|
|
4867
|
+
if (generation === "manual" && test.auto_generated === true) return false;
|
|
4868
|
+
if (generation === "auto" && test.auto_generated !== true) return false;
|
|
4869
|
+
if (collection !== null && test.method !== collection) return false;
|
|
4870
|
+
if (status !== null && test.status !== status) return false;
|
|
4871
|
+
if (labSlug !== null && String(test.lab?.slug ?? "") !== labSlug) return false;
|
|
4872
|
+
if (name !== null && !test.name.toLowerCase().includes(name)) return false;
|
|
4873
|
+
const markers = test.markers ?? [];
|
|
4874
|
+
if (markerIds && !markerIds.every((id) => markers.some((m) => String(m.id) === id)))
|
|
4875
|
+
return false;
|
|
4876
|
+
if (providerIds && !providerIds.every((id) => markers.some((m) => String(m.provider_id ?? "") === id)))
|
|
4877
|
+
return false;
|
|
4878
|
+
return true;
|
|
4879
|
+
});
|
|
4880
|
+
const ordered = orderKey === "price" ? [...filtered].sort((a, b) => (a.price ?? 0) - (b.price ?? 0)) : filtered;
|
|
4881
|
+
return direction === "desc" ? [...ordered].reverse() : ordered;
|
|
4882
|
+
};
|
|
4069
4883
|
var isValidPhone = (value) => {
|
|
4070
4884
|
const digits = value.replace(/\D/g, "");
|
|
4071
4885
|
if (digits.length < 10 || digits.length > 15) return false;
|
|
@@ -4452,6 +5266,9 @@ var orderHandlers = (state) => ({
|
|
|
4452
5266
|
data: state.listLabTests().filter((test) => test.auto_generated !== true),
|
|
4453
5267
|
next_cursor: null
|
|
4454
5268
|
}),
|
|
5269
|
+
// Deprecated upstream but still what team-catalog readers call: the same records as the
|
|
5270
|
+
// paged `/v3/lab_test`, as a bare array, filtered the way the real endpoint documents.
|
|
5271
|
+
get_lab_tests_for_team_v3_lab_tests_get: async (context) => jsonRes(200, filterLabTests(state.listLabTests(), context.url.searchParams)),
|
|
4455
5272
|
get_lab_test_for_team_v3_lab_tests__lab_test_id__get: async (context) => {
|
|
4456
5273
|
const id = context.params.lab_test_id ?? "";
|
|
4457
5274
|
const test = state.labTestById(id);
|
|
@@ -4462,7 +5279,7 @@ var orderHandlers = (state) => ({
|
|
|
4462
5279
|
get_team_lab_accounts_v3_lab_test_lab_account_get: async (context) => {
|
|
4463
5280
|
const requestedId = labAccountIdFilter(context);
|
|
4464
5281
|
const status = labAccountStatusFilter(context);
|
|
4465
|
-
const data = state.listLabAccounts().filter((entry) => entry.
|
|
5282
|
+
const data = state.listLabAccounts().filter((entry) => isLinkedToTeam(entry, state.teamId)).filter((entry) => requestedId === null || entry.id === requestedId).filter((entry) => status === null || entry.status === status).map(renderLabAccount);
|
|
4466
5283
|
return jsonRes(200, { data });
|
|
4467
5284
|
},
|
|
4468
5285
|
get_markers_for_lab_test_v3_lab_tests__lab_test_id__markers_get: async (context) => {
|
|
@@ -4527,8 +5344,7 @@ var orderHandlers = (state) => ({
|
|
|
4527
5344
|
}
|
|
4528
5345
|
const userId = body.user_id;
|
|
4529
5346
|
if (typeof userId !== "string") throw new HttpError(422, { detail: "user_id must be a string" });
|
|
4530
|
-
|
|
4531
|
-
notFound2("User does not exist on this team");
|
|
5347
|
+
requireUser(state, userId, context);
|
|
4532
5348
|
const phone = body.patient_details?.phone_number;
|
|
4533
5349
|
if (typeof phone === "string" && /^\+1\d{10}$/.test(phone) && phone.slice(2, 5) === "555") {
|
|
4534
5350
|
throw new HttpError(400, { detail: "Phone number is not correct" });
|
|
@@ -4577,7 +5393,7 @@ var orderHandlers = (state) => ({
|
|
|
4577
5393
|
const labAccount = selectLabAccount(
|
|
4578
5394
|
labSlug,
|
|
4579
5395
|
typeof body.lab_account_id === "string" ? body.lab_account_id : null,
|
|
4580
|
-
|
|
5396
|
+
state.teamId,
|
|
4581
5397
|
state.listLabAccounts()
|
|
4582
5398
|
);
|
|
4583
5399
|
const billingType = typeof body.billing_type === "string" && body.billing_type !== "" ? body.billing_type : "client_bill";
|
|
@@ -4596,10 +5412,7 @@ var orderHandlers = (state) => ({
|
|
|
4596
5412
|
throw new HttpError(400, {
|
|
4597
5413
|
detail: "Commercial insurance orders require at least one ICD code in icd_codes"
|
|
4598
5414
|
});
|
|
4599
|
-
const nowIso = state.isoNow(context.now);
|
|
4600
|
-
const nowMicro = new Date(context.now()).toISOString();
|
|
4601
5415
|
const orderId = state.nextOrderId();
|
|
4602
|
-
const transactionId = state.transactionIdFor(orderId);
|
|
4603
5416
|
const method = typeof body.collection_method === "string" ? body.collection_method : labTest.method;
|
|
4604
5417
|
const nativeMethod = typeof labTest.method === "string" && labTest.method.length > 0 ? labTest.method : method;
|
|
4605
5418
|
const markerCount = labTests.reduce((sum, test) => sum + (test.markers?.length ?? 0), 0);
|
|
@@ -4620,113 +5433,24 @@ var orderHandlers = (state) => ({
|
|
|
4620
5433
|
return jsonRes(200, replay.response);
|
|
4621
5434
|
}
|
|
4622
5435
|
}
|
|
4623
|
-
const
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
status_detail: null
|
|
4630
|
-
};
|
|
4631
|
-
let orderLabTest;
|
|
4632
|
-
if (method === nativeMethod) {
|
|
4633
|
-
orderLabTest = labTest;
|
|
4634
|
-
} else {
|
|
4635
|
-
const markerFingerprint = (test) => (test.markers ?? []).map((marker) => marker.id).sort((a, b) => a - b).join(",");
|
|
4636
|
-
const sourceFingerprint = markerFingerprint(labTest);
|
|
4637
|
-
const existingAuto = state.listLabTests().find(
|
|
4638
|
-
(test) => test.auto_generated === true && test.method === method && markerFingerprint(test) === sourceFingerprint
|
|
4639
|
-
);
|
|
4640
|
-
const orderLabTestKey = `${labTest.id}:${method}`;
|
|
4641
|
-
const orderLabTestName = existingAuto?.name ?? opaqueToken(`junction:order-lab-name:${orderLabTestKey}`, 16);
|
|
4642
|
-
orderLabTest = existingAuto ?? {
|
|
4643
|
-
...labTest,
|
|
4644
|
-
id: deterministicUuid(`junction:order-lab-test:${orderLabTestKey}`),
|
|
5436
|
+
const order = buildOrderRecord(
|
|
5437
|
+
state,
|
|
5438
|
+
{
|
|
5439
|
+
orderId,
|
|
5440
|
+
userId,
|
|
5441
|
+
labTest,
|
|
4645
5442
|
method,
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
patient_details: patientDetails(details),
|
|
4656
|
-
patient_address: patientAddress(address),
|
|
4657
|
-
lab_test: orderLabTest,
|
|
4658
|
-
details: METHOD_DETAILS(method, state.testkitIdFor(orderId), nowIso),
|
|
4659
|
-
sample_id: null,
|
|
4660
|
-
notes: null,
|
|
4661
|
-
clinical_notes: typeof body.clinical_notes === "string" ? body.clinical_notes : null,
|
|
4662
|
-
passthrough: typeof body.passthrough === "string" ? body.passthrough : null,
|
|
4663
|
-
...typeof body.lab_account_id === "string" ? { lab_account_id: body.lab_account_id } : {},
|
|
4664
|
-
created_at: nowIso,
|
|
4665
|
-
updated_at: nowIso,
|
|
4666
|
-
events: [event],
|
|
4667
|
-
status: "received",
|
|
4668
|
-
last_event: event,
|
|
4669
|
-
physician: PHYSICIAN,
|
|
4670
|
-
health_insurance_id: null,
|
|
4671
|
-
requisition_form_url: null,
|
|
4672
|
-
shipping_details: null,
|
|
4673
|
-
has_abn: false,
|
|
4674
|
-
billing_type: billingType,
|
|
4675
|
-
priority: false,
|
|
4676
|
-
activate_by: null,
|
|
4677
|
-
icd_codes: icdCodes,
|
|
4678
|
-
interpretation: null,
|
|
4679
|
-
has_missing_results: null,
|
|
4680
|
-
result_types: null,
|
|
4681
|
-
expected_result_by_date: null,
|
|
4682
|
-
worst_case_result_by_date: null,
|
|
4683
|
-
origin: "initial",
|
|
4684
|
-
order_transaction: {
|
|
4685
|
-
id: transactionId,
|
|
4686
|
-
status: "active",
|
|
4687
|
-
orders: [
|
|
4688
|
-
{
|
|
4689
|
-
id: orderId,
|
|
4690
|
-
low_level_status: "ordered",
|
|
4691
|
-
low_level_status_created_at: nowMicro,
|
|
4692
|
-
origin: "initial",
|
|
4693
|
-
parent_id: null,
|
|
4694
|
-
created_at: nowMicro,
|
|
4695
|
-
updated_at: nowMicro
|
|
4696
|
-
}
|
|
4697
|
-
]
|
|
4698
|
-
}
|
|
4699
|
-
};
|
|
4700
|
-
state.orders.insert(orderId, order);
|
|
4701
|
-
state.orderByTransaction.insert(transactionId, { order_id: orderId });
|
|
4702
|
-
state.upsertLabTest(
|
|
4703
|
-
orderLabTest,
|
|
4704
|
-
orderLabTest.id === labTest.id ? void 0 : state.expectedResultsFor(labTest.id)
|
|
5443
|
+
patientDetails: details,
|
|
5444
|
+
patientAddress: address,
|
|
5445
|
+
billingType,
|
|
5446
|
+
icdCodes,
|
|
5447
|
+
clinicalNotes: typeof body.clinical_notes === "string" ? body.clinical_notes : null,
|
|
5448
|
+
passthrough: typeof body.passthrough === "string" ? body.passthrough : null,
|
|
5449
|
+
...typeof body.lab_account_id === "string" ? { labAccountId: body.lab_account_id } : {}
|
|
5450
|
+
},
|
|
5451
|
+
context.now
|
|
4705
5452
|
);
|
|
4706
|
-
|
|
4707
|
-
first_name: details.first_name ?? null,
|
|
4708
|
-
last_name: details.last_name ?? null,
|
|
4709
|
-
dob: details.dob ?? null,
|
|
4710
|
-
gender: details.gender ?? null,
|
|
4711
|
-
phone_number: details.phone_number ?? null,
|
|
4712
|
-
email: details.email ?? null,
|
|
4713
|
-
gender_identity: null,
|
|
4714
|
-
sexual_orientation: null,
|
|
4715
|
-
race: null,
|
|
4716
|
-
ethnicity: null,
|
|
4717
|
-
medical_proxy: null,
|
|
4718
|
-
address: {
|
|
4719
|
-
first_line: address.first_line ?? "",
|
|
4720
|
-
second_line: typeof address.second_line === "string" ? address.second_line : "",
|
|
4721
|
-
country: address.country ?? "",
|
|
4722
|
-
zip: address.zip ?? "",
|
|
4723
|
-
city: address.city ?? "",
|
|
4724
|
-
state: address.state ?? "",
|
|
4725
|
-
access_notes: null
|
|
4726
|
-
}
|
|
4727
|
-
};
|
|
4728
|
-
if (state.userInfo.get(userId)) state.userInfo.update(userId, demographics);
|
|
4729
|
-
else state.userInfo.insert(userId, demographics);
|
|
5453
|
+
persistOrderRecord(state, order, labTest, details, address);
|
|
4730
5454
|
const responseOrder = { ...order };
|
|
4731
5455
|
if (responseOrder.result_types === null) delete responseOrder.result_types;
|
|
4732
5456
|
const response = {
|
|
@@ -4745,8 +5469,7 @@ var orderHandlers = (state) => ({
|
|
|
4745
5469
|
},
|
|
4746
5470
|
cancel_order_v3_order__order_id__cancel_post: async (context) => {
|
|
4747
5471
|
const id = context.params.order_id ?? "";
|
|
4748
|
-
const order = state.orders.get(id);
|
|
4749
|
-
if (!order) notFound2("Order doesn't exist");
|
|
5472
|
+
const order = state.orders.get(id) ?? orderMissing(state, context.operation.operationId, id);
|
|
4750
5473
|
const alreadyCancelled = order.events.some(
|
|
4751
5474
|
(entry) => typeof entry.status === "string" && entry.status.startsWith("cancelled.")
|
|
4752
5475
|
);
|
|
@@ -4828,8 +5551,8 @@ var orderHandlers = (state) => ({
|
|
|
4828
5551
|
});
|
|
4829
5552
|
}
|
|
4830
5553
|
}
|
|
4831
|
-
const order = state.orders.get(id);
|
|
4832
|
-
|
|
5554
|
+
const order = state.orders.get(id) ?? orderMissing(state, context.operation.operationId, id);
|
|
5555
|
+
checkSimulateAllowed(state.limits, context.request.headers.get("x-vital-api-key"));
|
|
4833
5556
|
if (typeof finalStatus !== "string" || !FINAL_STATUSES.includes(finalStatus))
|
|
4834
5557
|
throw new HttpError(422, { detail: [finalStatusError(String(finalStatus ?? ""))] });
|
|
4835
5558
|
const flags = simulationFlagsOf(context);
|
|
@@ -4847,13 +5570,11 @@ var orderHandlers = (state) => ({
|
|
|
4847
5570
|
},
|
|
4848
5571
|
get_order_v3_order__order_id__get: async (context) => {
|
|
4849
5572
|
const id = context.params.order_id ?? "";
|
|
4850
|
-
|
|
4851
|
-
if (!order) notFound2("This order doesn't exist");
|
|
5573
|
+
if (!state.orders.has(id)) orderMissing(state, context.operation.operationId, id);
|
|
4852
5574
|
state.applyDueSimulateTransitions(context.now(), (due, finalStatus, flags) => {
|
|
4853
5575
|
applySimulateTransition(state, due, finalStatus, flags, context);
|
|
4854
5576
|
});
|
|
4855
|
-
const fresh = state.orders.get(id);
|
|
4856
|
-
if (!fresh) notFound2("This order doesn't exist");
|
|
5577
|
+
const fresh = state.orders.get(id) ?? orderMissing(state, context.operation.operationId, id);
|
|
4857
5578
|
const body = { ...fresh };
|
|
4858
5579
|
if (body.result_types === null) delete body.result_types;
|
|
4859
5580
|
return jsonRes(200, body);
|
|
@@ -4866,8 +5587,7 @@ var orderHandlers = (state) => ({
|
|
|
4866
5587
|
const userId = context.query.user_id;
|
|
4867
5588
|
if (userId !== void 0 && typeof userId !== "string")
|
|
4868
5589
|
throw new HttpError(422, { detail: "user_id must be a string" });
|
|
4869
|
-
if (userId !== void 0
|
|
4870
|
-
notFound2("User does not exist on this team");
|
|
5590
|
+
if (userId !== void 0) requireUser(state, userId, context);
|
|
4871
5591
|
let all = state.orders.list({ order: "oldest" });
|
|
4872
5592
|
if (userId !== void 0) all = all.filter((entry) => entry.value.user_id === userId);
|
|
4873
5593
|
all = [...all].sort((left, right) => {
|
|
@@ -4895,7 +5615,7 @@ var orderHandlers = (state) => ({
|
|
|
4895
5615
|
if (!order) notFound2("Order transaction not found");
|
|
4896
5616
|
return jsonRes(200, {
|
|
4897
5617
|
id,
|
|
4898
|
-
team_id:
|
|
5618
|
+
team_id: state.teamId,
|
|
4899
5619
|
status: order.order_transaction.status,
|
|
4900
5620
|
orders: [orderSummary(order)]
|
|
4901
5621
|
});
|
|
@@ -4930,6 +5650,126 @@ var orderHandlers = (state) => ({
|
|
|
4930
5650
|
});
|
|
4931
5651
|
}
|
|
4932
5652
|
});
|
|
5653
|
+
var buildOrderRecord = (state, draft, now) => {
|
|
5654
|
+
const { orderId, userId, labTest, method, billingType, icdCodes } = draft;
|
|
5655
|
+
const details = draft.patientDetails;
|
|
5656
|
+
const nowIso = state.isoNow(now);
|
|
5657
|
+
const nowMicro = new Date(now()).toISOString();
|
|
5658
|
+
const transactionId = state.transactionIdFor(orderId);
|
|
5659
|
+
const nativeMethod = typeof labTest.method === "string" && labTest.method.length > 0 ? labTest.method : method;
|
|
5660
|
+
const eventStatus = `received.${method}.ordered`;
|
|
5661
|
+
const eventId = Number.parseInt(opaqueToken(`junction:order-event:${orderId}`, 8), 16) % 1e9 || 1;
|
|
5662
|
+
const event = {
|
|
5663
|
+
id: eventId,
|
|
5664
|
+
created_at: nowIso,
|
|
5665
|
+
status: eventStatus,
|
|
5666
|
+
status_detail: null
|
|
5667
|
+
};
|
|
5668
|
+
let orderLabTest;
|
|
5669
|
+
if (method === nativeMethod) {
|
|
5670
|
+
orderLabTest = labTest;
|
|
5671
|
+
} else {
|
|
5672
|
+
const markerFingerprint = (test) => (test.markers ?? []).map((marker) => marker.id).sort((a, b) => a - b).join(",");
|
|
5673
|
+
const sourceFingerprint = markerFingerprint(labTest);
|
|
5674
|
+
const existingAuto = state.listLabTests().find(
|
|
5675
|
+
(test) => test.auto_generated === true && test.method === method && markerFingerprint(test) === sourceFingerprint
|
|
5676
|
+
);
|
|
5677
|
+
const orderLabTestKey = `${labTest.id}:${method}`;
|
|
5678
|
+
const orderLabTestName = existingAuto?.name ?? opaqueToken(`junction:order-lab-name:${orderLabTestKey}`, 16);
|
|
5679
|
+
orderLabTest = existingAuto ?? {
|
|
5680
|
+
...labTest,
|
|
5681
|
+
id: deterministicUuid(`junction:order-lab-test:${orderLabTestKey}`),
|
|
5682
|
+
method,
|
|
5683
|
+
auto_generated: true,
|
|
5684
|
+
name: orderLabTestName,
|
|
5685
|
+
slug: `afd62b39-${orderLabTestName}`
|
|
5686
|
+
};
|
|
5687
|
+
}
|
|
5688
|
+
const order = {
|
|
5689
|
+
id: orderId,
|
|
5690
|
+
user_id: userId,
|
|
5691
|
+
team_id: state.teamId,
|
|
5692
|
+
patient_details: patientDetails(details),
|
|
5693
|
+
patient_address: patientAddress(draft.patientAddress),
|
|
5694
|
+
lab_test: orderLabTest,
|
|
5695
|
+
details: METHOD_DETAILS(method, state.testkitIdFor(orderId), nowIso),
|
|
5696
|
+
sample_id: null,
|
|
5697
|
+
notes: null,
|
|
5698
|
+
clinical_notes: draft.clinicalNotes,
|
|
5699
|
+
passthrough: draft.passthrough,
|
|
5700
|
+
...draft.labAccountId !== void 0 ? { lab_account_id: draft.labAccountId } : {},
|
|
5701
|
+
created_at: nowIso,
|
|
5702
|
+
updated_at: nowIso,
|
|
5703
|
+
events: [event],
|
|
5704
|
+
status: "received",
|
|
5705
|
+
last_event: event,
|
|
5706
|
+
physician: PHYSICIAN,
|
|
5707
|
+
health_insurance_id: null,
|
|
5708
|
+
requisition_form_url: null,
|
|
5709
|
+
shipping_details: null,
|
|
5710
|
+
has_abn: false,
|
|
5711
|
+
billing_type: billingType,
|
|
5712
|
+
priority: false,
|
|
5713
|
+
activate_by: null,
|
|
5714
|
+
icd_codes: icdCodes,
|
|
5715
|
+
interpretation: null,
|
|
5716
|
+
has_missing_results: null,
|
|
5717
|
+
result_types: null,
|
|
5718
|
+
expected_result_by_date: null,
|
|
5719
|
+
worst_case_result_by_date: null,
|
|
5720
|
+
origin: "initial",
|
|
5721
|
+
order_transaction: {
|
|
5722
|
+
id: transactionId,
|
|
5723
|
+
status: "active",
|
|
5724
|
+
orders: [
|
|
5725
|
+
{
|
|
5726
|
+
id: orderId,
|
|
5727
|
+
low_level_status: "ordered",
|
|
5728
|
+
low_level_status_created_at: nowMicro,
|
|
5729
|
+
origin: "initial",
|
|
5730
|
+
parent_id: null,
|
|
5731
|
+
created_at: nowMicro,
|
|
5732
|
+
updated_at: nowMicro
|
|
5733
|
+
}
|
|
5734
|
+
]
|
|
5735
|
+
}
|
|
5736
|
+
};
|
|
5737
|
+
return order;
|
|
5738
|
+
};
|
|
5739
|
+
var persistOrderRecord = (state, order, labTest, details, address) => {
|
|
5740
|
+
const userId = order.user_id;
|
|
5741
|
+
const orderLabTest = order.lab_test;
|
|
5742
|
+
state.orders.insert(order.id, order);
|
|
5743
|
+
state.orderByTransaction.insert(order.order_transaction.id, { order_id: order.id });
|
|
5744
|
+
state.upsertLabTest(
|
|
5745
|
+
orderLabTest,
|
|
5746
|
+
orderLabTest.id === labTest.id ? void 0 : state.expectedResultsFor(labTest.id)
|
|
5747
|
+
);
|
|
5748
|
+
const demographics = {
|
|
5749
|
+
first_name: details.first_name ?? null,
|
|
5750
|
+
last_name: details.last_name ?? null,
|
|
5751
|
+
dob: details.dob ?? null,
|
|
5752
|
+
gender: details.gender ?? null,
|
|
5753
|
+
phone_number: details.phone_number ?? null,
|
|
5754
|
+
email: details.email ?? null,
|
|
5755
|
+
gender_identity: null,
|
|
5756
|
+
sexual_orientation: null,
|
|
5757
|
+
race: null,
|
|
5758
|
+
ethnicity: null,
|
|
5759
|
+
medical_proxy: null,
|
|
5760
|
+
address: {
|
|
5761
|
+
first_line: address.first_line ?? "",
|
|
5762
|
+
second_line: typeof address.second_line === "string" ? address.second_line : "",
|
|
5763
|
+
country: address.country ?? "",
|
|
5764
|
+
zip: address.zip ?? "",
|
|
5765
|
+
city: address.city ?? "",
|
|
5766
|
+
state: address.state ?? "",
|
|
5767
|
+
access_notes: null
|
|
5768
|
+
}
|
|
5769
|
+
};
|
|
5770
|
+
if (state.userInfo.get(userId)) state.userInfo.update(userId, demographics);
|
|
5771
|
+
else state.userInfo.insert(userId, demographics);
|
|
5772
|
+
};
|
|
4933
5773
|
var orderSummary = (order) => {
|
|
4934
5774
|
const transactionOrder = order.order_transaction.orders.find((entry) => entry.id === order.id);
|
|
4935
5775
|
return {
|
|
@@ -4955,6 +5795,201 @@ var biomarker = (order, created_at) => (order.lab_test.markers ?? []).map((marke
|
|
|
4955
5795
|
source_sample_id: null
|
|
4956
5796
|
}));
|
|
4957
5797
|
|
|
5798
|
+
// src/fixtures.ts
|
|
5799
|
+
var IDENTITY_MODES = ["strict", "adopt-users"];
|
|
5800
|
+
var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
5801
|
+
var isUuid3 = (value) => UUID.test(value);
|
|
5802
|
+
var FixtureError = class extends Error {
|
|
5803
|
+
constructor(status, message) {
|
|
5804
|
+
super(message);
|
|
5805
|
+
this.status = status;
|
|
5806
|
+
this.name = "FixtureError";
|
|
5807
|
+
}
|
|
5808
|
+
status;
|
|
5809
|
+
};
|
|
5810
|
+
var isRecord5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5811
|
+
var instant = (value, field, fallback) => {
|
|
5812
|
+
if (value === void 0) return fallback;
|
|
5813
|
+
if (typeof value !== "string" || Number.isNaN(Date.parse(value)))
|
|
5814
|
+
throw new FixtureError(400, `${field} must be an ISO-8601 timestamp`);
|
|
5815
|
+
return value;
|
|
5816
|
+
};
|
|
5817
|
+
var DEFAULT_PATIENT_DETAILS = {
|
|
5818
|
+
first_name: "Mockingbird",
|
|
5819
|
+
last_name: "Fixture",
|
|
5820
|
+
dob: "1990-01-01",
|
|
5821
|
+
gender: "female",
|
|
5822
|
+
phone_number: "+14155550100",
|
|
5823
|
+
email: "fixture@example.com"
|
|
5824
|
+
};
|
|
5825
|
+
var DEFAULT_PATIENT_ADDRESS = {
|
|
5826
|
+
first_line: "1 Main St",
|
|
5827
|
+
second_line: "",
|
|
5828
|
+
city: "New York",
|
|
5829
|
+
state: "NY",
|
|
5830
|
+
zip: "10001",
|
|
5831
|
+
country: "US"
|
|
5832
|
+
};
|
|
5833
|
+
var buildUser = (state, input, now) => {
|
|
5834
|
+
if (!isRecord5(input)) throw new FixtureError(400, "a user fixture must be an object");
|
|
5835
|
+
if (typeof input.client_user_id !== "string" || input.client_user_id === "")
|
|
5836
|
+
throw new FixtureError(400, "client_user_id must be a non-empty string");
|
|
5837
|
+
if (input.user_id !== void 0 && (typeof input.user_id !== "string" || !isUuid3(input.user_id)))
|
|
5838
|
+
throw new FixtureError(400, `user_id must be a UUID (got ${JSON.stringify(input.user_id)})`);
|
|
5839
|
+
const createdOn = instant(input.created_on, "created_on", state.isoNow(now));
|
|
5840
|
+
const zone = input.fallback_time_zone;
|
|
5841
|
+
const birth = input.fallback_birth_date;
|
|
5842
|
+
return {
|
|
5843
|
+
user_id: input.user_id ?? state.nextUserId(),
|
|
5844
|
+
team_id: state.teamId,
|
|
5845
|
+
client_user_id: input.client_user_id,
|
|
5846
|
+
created_on: createdOn,
|
|
5847
|
+
connected_sources: [],
|
|
5848
|
+
fallback_time_zone: typeof zone === "string" ? { id: zone, source_slug: "manual", updated_at: createdOn } : zone ?? null,
|
|
5849
|
+
fallback_birth_date: typeof birth === "string" ? { value: birth, source_slug: "manual", updated_at: createdOn } : birth ?? null,
|
|
5850
|
+
ingestion_start: input.ingestion_start ?? null,
|
|
5851
|
+
ingestion_end: input.ingestion_end ?? null
|
|
5852
|
+
};
|
|
5853
|
+
};
|
|
5854
|
+
var insertUsers = (state, inputs, now) => {
|
|
5855
|
+
const users = [];
|
|
5856
|
+
const ids = /* @__PURE__ */ new Set();
|
|
5857
|
+
const clientIds = /* @__PURE__ */ new Set();
|
|
5858
|
+
for (const input of inputs) {
|
|
5859
|
+
const user = buildUser(state, input, now);
|
|
5860
|
+
if (ids.has(user.user_id) || state.users.has(user.user_id) || state.deletedUsers.has(user.user_id))
|
|
5861
|
+
throw new FixtureError(409, `user ${user.user_id} already exists`);
|
|
5862
|
+
if (clientIds.has(user.client_user_id) || state.byClientId.has(user.client_user_id))
|
|
5863
|
+
throw new FixtureError(409, `client_user_id ${user.client_user_id} already exists`);
|
|
5864
|
+
ids.add(user.user_id);
|
|
5865
|
+
clientIds.add(user.client_user_id);
|
|
5866
|
+
users.push(user);
|
|
5867
|
+
}
|
|
5868
|
+
for (const user of users) state.insertUser(user);
|
|
5869
|
+
return users;
|
|
5870
|
+
};
|
|
5871
|
+
var hardDeleteUser = (state, userId) => {
|
|
5872
|
+
const user = state.users.get(userId);
|
|
5873
|
+
const tombstoned = state.deletedUsers.delete(userId);
|
|
5874
|
+
if (!user) return tombstoned;
|
|
5875
|
+
state.users.delete(userId);
|
|
5876
|
+
state.byClientId.delete(user.client_user_id);
|
|
5877
|
+
state.userInfo.delete(userId);
|
|
5878
|
+
return true;
|
|
5879
|
+
};
|
|
5880
|
+
var insertOrders = (state, inputs, now, options = {}) => {
|
|
5881
|
+
const prepared = [];
|
|
5882
|
+
const ids = /* @__PURE__ */ new Set();
|
|
5883
|
+
for (const input of inputs) {
|
|
5884
|
+
if (!isRecord5(input)) throw new FixtureError(400, "an order fixture must be an object");
|
|
5885
|
+
if (typeof input.user_id !== "string") throw new FixtureError(400, "user_id is required");
|
|
5886
|
+
if (typeof input.lab_test_id !== "string")
|
|
5887
|
+
throw new FixtureError(400, "lab_test_id is required");
|
|
5888
|
+
if (!state.users.has(input.user_id) && !state.deletedUsers.has(input.user_id))
|
|
5889
|
+
throw new FixtureError(404, `no user ${input.user_id} in this namespace`);
|
|
5890
|
+
const labTest = state.labTestById(input.lab_test_id);
|
|
5891
|
+
if (!labTest) throw new FixtureError(404, `no lab test ${input.lab_test_id} in the catalog`);
|
|
5892
|
+
if (input.order_id !== void 0 && (typeof input.order_id !== "string" || !isUuid3(input.order_id)))
|
|
5893
|
+
throw new FixtureError(400, `order_id must be a UUID (got ${JSON.stringify(input.order_id)})`);
|
|
5894
|
+
const orderId = input.order_id ?? state.nextOrderId();
|
|
5895
|
+
if (ids.has(orderId) || state.orders.has(orderId))
|
|
5896
|
+
throw new FixtureError(409, `order ${orderId} already exists`);
|
|
5897
|
+
ids.add(orderId);
|
|
5898
|
+
const method = typeof input.collection_method === "string" && input.collection_method !== "" ? input.collection_method : typeof labTest.method === "string" && labTest.method !== "" ? labTest.method : "at_home_phlebotomy";
|
|
5899
|
+
let status;
|
|
5900
|
+
if (input.status !== void 0) {
|
|
5901
|
+
if (typeof input.status !== "string") throw new FixtureError(400, "status must be a string");
|
|
5902
|
+
const resolved = resolveTransition(method, input.status);
|
|
5903
|
+
if ("error" in resolved) throw new FixtureError(400, resolved.error);
|
|
5904
|
+
status = resolved.status;
|
|
5905
|
+
}
|
|
5906
|
+
const details = { ...DEFAULT_PATIENT_DETAILS, ...input.patient_details };
|
|
5907
|
+
const address = { ...DEFAULT_PATIENT_ADDRESS, ...input.patient_address };
|
|
5908
|
+
const createdAt = input.created_at;
|
|
5909
|
+
const createdMs = createdAt === void 0 ? void 0 : Date.parse(instant(createdAt, "created_at", ""));
|
|
5910
|
+
const order = buildOrderRecord(
|
|
5911
|
+
state,
|
|
5912
|
+
{
|
|
5913
|
+
orderId,
|
|
5914
|
+
userId: input.user_id,
|
|
5915
|
+
labTest,
|
|
5916
|
+
method,
|
|
5917
|
+
patientDetails: details,
|
|
5918
|
+
patientAddress: address,
|
|
5919
|
+
billingType: input.billing_type ?? "client_bill",
|
|
5920
|
+
icdCodes: input.icd_codes ?? null,
|
|
5921
|
+
clinicalNotes: input.clinical_notes ?? null,
|
|
5922
|
+
passthrough: input.passthrough ?? null,
|
|
5923
|
+
...input.lab_account_id !== void 0 ? { labAccountId: input.lab_account_id } : {}
|
|
5924
|
+
},
|
|
5925
|
+
createdMs === void 0 ? now : () => createdMs
|
|
5926
|
+
);
|
|
5927
|
+
prepared.push({ input, order, labTest, details, address, status });
|
|
5928
|
+
}
|
|
5929
|
+
const run = () => {
|
|
5930
|
+
for (const { input, order, labTest, details, address, status } of prepared) {
|
|
5931
|
+
persistOrderRecord(state, order, labTest, details, address);
|
|
5932
|
+
state.publishOrderWebhook(order, "labtest.order.created", now());
|
|
5933
|
+
if (status !== void 0) {
|
|
5934
|
+
const stored = state.orders.get(order.id);
|
|
5935
|
+
if (stored) forceOrderStatus(state, stored, status, null, { now });
|
|
5936
|
+
}
|
|
5937
|
+
if (input.result_fixture !== void 0) {
|
|
5938
|
+
state.resultFixtures.insert(order.id, { name: "custom", ...input.result_fixture });
|
|
5939
|
+
if (input.result_fixture.interpretation !== void 0) {
|
|
5940
|
+
const stored = state.orders.get(order.id);
|
|
5941
|
+
if (stored) {
|
|
5942
|
+
stored.interpretation = input.result_fixture.interpretation;
|
|
5943
|
+
state.orders.update(order.id, stored);
|
|
5944
|
+
}
|
|
5945
|
+
}
|
|
5946
|
+
}
|
|
5947
|
+
}
|
|
5948
|
+
};
|
|
5949
|
+
if (options.emitWebhooks === true) run();
|
|
5950
|
+
else state.muteWebhooks(run);
|
|
5951
|
+
return prepared.flatMap(({ order }) => state.orders.get(order.id) ?? []);
|
|
5952
|
+
};
|
|
5953
|
+
var importFixtures = (state, fixtures, now, options = {}) => {
|
|
5954
|
+
if (!isRecord5(fixtures))
|
|
5955
|
+
throw new FixtureError(400, 'fixtures must be { "users": [...], "orders": [...] }');
|
|
5956
|
+
const { users = [], orders = [] } = fixtures;
|
|
5957
|
+
if (!Array.isArray(users)) throw new FixtureError(400, "users must be an array");
|
|
5958
|
+
if (!Array.isArray(orders)) throw new FixtureError(400, "orders must be an array");
|
|
5959
|
+
const inserted = insertUsers(state, users, now);
|
|
5960
|
+
try {
|
|
5961
|
+
return { users: inserted, orders: insertOrders(state, orders, now, options) };
|
|
5962
|
+
} catch (error) {
|
|
5963
|
+
for (const user of inserted) hardDeleteUser(state, user.user_id);
|
|
5964
|
+
throw error;
|
|
5965
|
+
}
|
|
5966
|
+
};
|
|
5967
|
+
var requireUser = (state, userId, context, detail = "User does not exist on this team") => {
|
|
5968
|
+
if (state.users.has(userId) || state.deletedUsers.has(userId)) return;
|
|
5969
|
+
if (state.identity === "adopt-users" && isUuid3(userId)) {
|
|
5970
|
+
insertUsers(state, [{ user_id: userId, client_user_id: userId }], context.now);
|
|
5971
|
+
state.noteAdoption(context.request);
|
|
5972
|
+
return;
|
|
5973
|
+
}
|
|
5974
|
+
missing(state, "user", userId, detail);
|
|
5975
|
+
};
|
|
5976
|
+
var fixtureErrorMessage = (error) => {
|
|
5977
|
+
if (error instanceof FixtureError) return { status: error.status, message: error.message };
|
|
5978
|
+
if (error instanceof HttpError) {
|
|
5979
|
+
const detail = isRecord5(error.body) ? error.body.detail : error.body;
|
|
5980
|
+
return {
|
|
5981
|
+
status: error.status,
|
|
5982
|
+
message: typeof detail === "string" ? detail : JSON.stringify(detail)
|
|
5983
|
+
};
|
|
5984
|
+
}
|
|
5985
|
+
throw error;
|
|
5986
|
+
};
|
|
5987
|
+
|
|
5988
|
+
// src/generated/openapi.ts
|
|
5989
|
+
var document = JSON.parse(`{"openapi":"3.1.0","info":{"title":"Junction API (Mockingbird subset)","description":"Stateful mock subset of the Junction (Vital) API.\\nDocs: https://docs.junction.com/\\nAuth: https://docs.junction.com/api-details/junction-api\\nCreate user: https://docs.junction.com/api-reference/user/create-user\\nGet user: https://docs.junction.com/api-reference/user/get-user\\nDelete user: https://docs.junction.com/api-reference/user/delete-user\\nResolve user: https://docs.junction.com/api-reference/user/resolve-user\\nUpdate user: https://docs.junction.com/api-reference/user/patch-user\\nGet users: https://docs.junction.com/api-reference/user/get-users\\nCreate order: https://docs.junction.com/api-reference/lab-testing/create-order\\nGet order: https://docs.junction.com/api-reference/lab-testing/get-order\\nGet orders: https://docs.junction.com/api-reference/lab-testing/get-orders\\nGet order transaction: https://docs.junction.com/api-reference/lab-testing/order-transactions/get-order-transaction\\nGet order transaction result: https://docs.junction.com/api-reference/lab-testing/results/get-order-transaction-results\\nLab tests: https://docs.junction.com/api-reference/lab-testing/tests-paginated\\nLab tests (deprecated, unpaged): https://docs.junction.com/api-reference/lab-testing/tests/get-lab-tests\\nAppointment availability: https://docs.junction.com/api-reference/lab-testing/appointments/get-appointment-availability\\nBook appointment: https://docs.junction.com/api-reference/lab-testing/appointments/book-appointment\\nGet appointment: https://docs.junction.com/api-reference/lab-testing/appointments/get-appointment\\nReschedule appointment: https://docs.junction.com/api-reference/lab-testing/appointments/reschedule-appointment\\nCancel appointment: https://docs.junction.com/api-reference/lab-testing/appointments/cancel-appointment\\nAppointment cancellation reasons: https://docs.junction.com/api-reference/lab-testing/appointments/get-appointment-cancellation-reasons\\nArea info: https://docs.junction.com/api-reference/lab-testing/service-areas/get-area-info\\nPSC info: https://docs.junction.com/api-reference/lab-testing/service-areas/get-psc-info\\nLab locations: https://docs.junction.com/api-reference/lab-testing/service-areas/get-lab-locations\\nRaw results: https://docs.junction.com/api-reference/lab-testing/results/get-lab-results\\nResult metadata: https://docs.junction.com/api-reference/lab-testing/results/get-lab-results-metadata\\nResult PDF: https://docs.junction.com/api-reference/lab-testing/results/get-lab-result-pdf\\nRequisition form PDF: https://docs.junction.com/api-reference/lab-testing/orders/get-requisition-form\\nList labs: https://docs.junction.com/api-reference/lab-testing/tests/get-labs\\nTest markers: https://docs.junction.com/api-reference/lab-testing/tests/get-markers-for-lab-test\\nOrder-set markers: https://docs.junction.com/api-reference/lab-testing/results/get-order-set-markers\\nLatest user info: https://docs.junction.com/api-reference/user/get-latest-user-info\\n","version":"0.4.758","x-mockingbird-upstream":{"docs":"https://docs.junction.com/","note":"Hand-authored subset from Junction public OpenAPI snippets in the docs."}},"servers":[{"url":"https://api.sandbox.us.junction.com"}],"security":[{"apiKeyAuth":[]}],"paths":{"/v2/user":{"post":{"operationId":"create_user_v2_user_post","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserCreateBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingUser"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientUserIDConflictResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"operationId":"get_teams_users_v2_user_get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedUsersResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"500":{"description":"Internal Server Error","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/v2/user/{user_id}":{"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"user","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_user_v2_user__user_id__get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingUser"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"operationId":"delete_user_v2_user__user_id__delete","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserSuccessResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"operationId":"patch_user_v2_user__user_id__patch","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserPatchBody"}}}},"responses":{"204":{"description":"Successful Response"},"400":{"description":"Nothing to patch","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"409":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/user/resolve/{client_user_id}":{"parameters":[{"name":"client_user_id","in":"path","required":true,"schema":{"type":"string","minLength":1}}],"get":{"operationId":"get_user_by_client_user_id_v2_user_resolve__client_user_id__get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ClientFacingUser"},{"$ref":"#/components/schemas/PaginatedUsersResponse"}]}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/user/{user_id}/info":{"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"user","missing":"00000000-0000-4000-8000-000000000000"}}}],"patch":{"operationId":"patch_user_info_v2_user__user_id__info_patch","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserInfoPatchBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserInfo"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/user/{user_id}/info/latest":{"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"user","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_latest_user_info_user_v2_user__user_id__info_latest_get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserInfo"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/lab_test":{"get":{"operationId":"get_paginated_lab_tests_for_team_v3_lab_test_get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LabTestResourcesResponse"}}}}}}},"/v3/lab_test/lab_account":{"get":{"operationId":"get_team_lab_accounts_v3_lab_test_lab_account_get","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"lab-account inventory is fixture-owned; the mock models the documented shape, filters and routing rules, not a live account inventory"}},"parameters":[{"name":"lab_account_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/LabAccountStatus"},{"type":"null"}]}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetTeamLabAccountsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/lab_tests":{"get":{"operationId":"get_lab_tests_for_team_v3_lab_tests_get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"summary":"Get Lab Tests For Team","description":"GET all the lab tests the team has access to.","deprecated":true,"parameters":[{"name":"generation_method","in":"query","required":false,"schema":{"$ref":"#/components/schemas/LabTestGenerationMethodFilter","description":"Filter on whether auto-generated lab tests created by Vital, manually created lab tests, or all lab tests should be returned.","default":"manual"},"description":"Filter on whether auto-generated lab tests created by Vital, manually created lab tests, or all lab tests should be returned."},{"name":"lab_slug","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by the slug of the lab for these lab tests.","title":"Lab Slug"},"description":"Filter by the slug of the lab for these lab tests."},{"name":"collection_method","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/LabTestCollectionMethod"},{"type":"null"}],"description":"Filter by the collection method for these lab tests.","title":"Collection Method"},"description":"Filter by the collection method for these lab tests."},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/LabTestStatus"},{"type":"null"}],"description":"Filter by the status of these lab tests.","title":"Status"},"description":"Filter by the status of these lab tests."},{"name":"marker_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"integer"}},{"type":"null"}],"description":"Filter to only include lab tests containing these marker IDs.","title":"Marker Ids"},"description":"Filter to only include lab tests containing these marker IDs."},{"name":"provider_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"Filter to only include lab tests containing these provider IDs.","title":"Provider Ids"},"description":"Filter to only include lab tests containing these provider IDs."},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by the name of the lab test (a case-insensitive substring search).","title":"Name"},"description":"Filter by the name of the lab test (a case-insensitive substring search)."},{"name":"order_key","in":"query","required":false,"schema":{"anyOf":[{"enum":["price","created_at","updated_at"],"type":"string"},{"type":"null"}],"title":"Order Key"}},{"name":"order_direction","in":"query","required":false,"schema":{"enum":["asc","desc"],"type":"string","default":"asc","title":"Order Direction"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingLabTest"},"title":"Response Get Lab Tests For Team V3 Lab Tests Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/lab_tests/{lab_test_id}":{"parameters":[{"name":"lab_test_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"lab_test","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_lab_test_for_team_v3_lab_tests__lab_test_id__get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingLabTest"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/lab_tests/labs":{"get":{"operationId":"get_labs_v3_lab_tests_labs_get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingLab"}}}}}}}},"/v3/lab_tests/{lab_test_id}/markers":{"parameters":[{"name":"lab_test_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"lab_test","missing":"00000000-0000-4000-8000-000000000000"}}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"provider_id","in":"query","required":false,"schema":{"type":"string"}}],"get":{"operationId":"get_markers_for_lab_test_v3_lab_tests__lab_test_id__markers_get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMarkersResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/lab_tests/list_order_set_markers":{"post":{"operationId":"list_order_set_markers_v3_lab_tests_list_order_set_markers_post","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListOrderSetMarkersRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetMarkersResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order":{"post":{"operationId":"create_order_v3_order_post","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOrderRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostOrderResponse"}}}},"400":{"description":"Bad Request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"500":{"description":"Internal Server Error"}}}},"/v3/order/area/info":{"get":{"operationId":"get_area_info_v3_order_area_info_get","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"central_labs presence, within_radius counts and getlabs market coverage are provider-owned geo data that a mock cannot replicate per-zip; covered by the client-parity scenario shape checks instead"}},"parameters":[{"name":"zip_code","in":"query","required":true,"schema":{"type":"string","pattern":"^\\\\d{5}(?:-?\\\\d{4})?$"}},{"name":"radius","in":"query","required":false,"schema":{"$ref":"#/components/schemas/AllowedRadius"}},{"name":"lab_account_id","in":"query","required":false,"description":"Lab Account ID to use for availability checks","schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AreaInfo"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/psc/info":{"get":{"operationId":"get_psc_info_v3_order_psc_info_get","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"patient_service_centers are real site inventories per zip (thousands of sites, result-capped at 30) that a fixture mock cannot replicate per-zip; covered by the client-parity scenario shape checks instead"}},"parameters":[{"name":"zip_code","in":"query","required":true,"schema":{"type":"string","pattern":"^\\\\d{5}$"}},{"name":"lab_id","in":"query","required":true,"schema":{"type":"integer"}},{"name":"radius","in":"query","required":false,"schema":{"$ref":"#/components/schemas/AllowedRadius"}},{"name":"capabilities","in":"query","required":false,"schema":{"type":"array","items":{"$ref":"#/components/schemas/LabLocationCapability"}}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PscInfo"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/phlebotomy/appointment/availability":{"post":{"operationId":"get_phlebotomy_appointment_availability_v3_order_phlebotomy_appointment_availability_post","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"availability slots are provider-side data whose values shift between sandbox calls; covered by the mock-internal scheduling property suite instead"}},"parameters":[{"name":"start_date","in":"query","required":false,"schema":{"type":"string","format":"date"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsAddress"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppointmentAvailabilitySlots"}}}},"400":{"description":"Availability not bookable for this address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"No availability found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/phlebotomy/appointment/cancellation-reasons":{"get":{"operationId":"get_phlebotomy_appointment_cancellation_reason_v3_order_phlebotomy_appointment_cancellation_reasons_get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingAppointmentCancellationReason"}}}}}}}},"/v3/order/psc/appointment/availability":{"post":{"operationId":"get_psc_appointment_availability_v3_order_psc_appointment_availability_post","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"availability slots are provider-side data whose values shift between sandbox calls; covered by the mock-internal scheduling property suite instead"}},"parameters":[{"name":"lab","in":"query","required":true,"schema":{"$ref":"#/components/schemas/AppointmentPscLabs"}},{"name":"start_date","in":"query","required":false,"schema":{"type":"string","format":"date"}},{"name":"site_codes","in":"query","required":false,"schema":{"type":"string","description":"JSON-encoded array of site codes"}},{"name":"zip_code","in":"query","required":false,"schema":{"type":"string"}},{"name":"radius","in":"query","required":false,"schema":{"$ref":"#/components/schemas/AllowedRadius"}},{"name":"allow_stale","in":"query","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppointmentAvailabilitySlots"}}}},"400":{"description":"Availability not bookable for this address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"No slots found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/psc/appointment/cancellation-reasons":{"get":{"operationId":"get_psc_appointment_cancellation_reason_v3_order_psc_appointment_cancellation_reasons_get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingAppointmentCancellationReason"}}}}}}}},"/v3/order/{order_id}/phlebotomy/appointment":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_get","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"appointment payloads embed provider-side slot data; covered by the mock-internal scheduling property suite instead"}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingAppointment"}}}},"404":{"description":"No appointment for this order","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/phlebotomy/appointment/book":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"post":{"operationId":"book_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_book_post","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"booking depends on live provider slot state; covered by the mock-internal scheduling property suite instead"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppointmentBookingRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingAppointment"}}}},"400":{"description":"Booking failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"Order not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/phlebotomy/appointment/reschedule":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"patch":{"operationId":"reschedule_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_reschedule_patch","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"rescheduling depends on live provider slot state; covered by the mock-internal scheduling property suite instead"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppointmentRescheduleRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingAppointment"}}}},"400":{"description":"Invalid or expired booking key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"No appointment for this order","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/phlebotomy/appointment/cancel":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"patch":{"operationId":"cancel_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_cancel_patch","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"cancellation depends on live provider appointment state; covered by the mock-internal scheduling property suite instead"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhlebotomyAppointmentCancelRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingAppointment"}}}},"400":{"description":"Invalid cancellation reason","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"No appointment for this order","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/psc/appointment":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_psc_appointment_v3_order__order_id__psc_appointment_get","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"appointment payloads embed provider-side slot data; covered by the mock-internal scheduling property suite instead"}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingAppointment"}}}},"404":{"description":"No appointment for this order","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/psc/appointment/book":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"post":{"operationId":"book_psc_appointment_v3_order__order_id__psc_appointment_book_post","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"booking depends on live provider slot state; covered by the mock-internal scheduling property suite instead"}},"parameters":[{"name":"x-idempotency-key","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PscAppointmentBookingRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingAppointment"}}}},"400":{"description":"Booking failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"Order not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/psc/appointment/reschedule":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"patch":{"operationId":"reschedule_psc_appointment_v3_order__order_id__psc_appointment_reschedule_patch","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"rescheduling depends on live provider slot state; covered by the mock-internal scheduling property suite instead"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppointmentRescheduleRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingAppointment"}}}},"400":{"description":"Invalid or expired booking key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"No appointment for this order","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/psc/appointment/cancel":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"patch":{"operationId":"cancel_psc_appointment_v3_order__order_id__psc_appointment_cancel_patch","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"cancellation depends on live provider appointment state; covered by the mock-internal scheduling property suite instead"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PscAppointmentCancelRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingAppointment"}}}},"400":{"description":"Invalid cancellation reason","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"No appointment for this order","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_order_v3_order__order_id__get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientFacingOrder"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/cancel":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"post":{"operationId":"cancel_order_v3_order__order_id__cancel_post","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostOrderResponse"}}}},"400":{"description":"Order is not in a cancellable status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/test":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"post":{"operationId":"simulate_order_v3_order__order_id__test_post","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"name":"final_status","in":"query","required":true,"schema":{"type":"string","enum":["received.walk_in_test.ordered","received.walk_in_test.requisition_created","received.walk_in_test.requisition_bypassed","completed.walk_in_test.completed","sample_with_lab.walk_in_test.partial_results","failed.walk_in_test.sample_error","cancelled.walk_in_test.cancelled","collecting_sample.walk_in_test.appointment_pending","collecting_sample.walk_in_test.appointment_scheduled","collecting_sample.walk_in_test.appointment_cancelled","collecting_sample.walk_in_test.redraw_available","received.at_home_phlebotomy.ordered","received.at_home_phlebotomy.requisition_created","received.at_home_phlebotomy.requisition_bypassed","collecting_sample.at_home_phlebotomy.appointment_pending","collecting_sample.at_home_phlebotomy.appointment_scheduled","collecting_sample.at_home_phlebotomy.draw_completed","collecting_sample.at_home_phlebotomy.appointment_cancelled","completed.at_home_phlebotomy.completed","sample_with_lab.at_home_phlebotomy.partial_results","cancelled.at_home_phlebotomy.cancelled","failed.at_home_phlebotomy.sample_error","received.testkit.ordered","received.testkit.awaiting_registration","received.testkit.requisition_created","received.testkit.requisition_bypassed","received.testkit.registered","collecting_sample.testkit.transit_customer","collecting_sample.testkit.out_for_delivery","collecting_sample.testkit.with_customer","collecting_sample.testkit.transit_lab","sample_with_lab.testkit.delivered_to_lab","sample_with_lab.testkit.lab_processing_blocked","completed.testkit.completed","failed.testkit.failure_to_deliver_to_customer","failed.testkit.failure_to_deliver_to_lab","failed.testkit.sample_error","failed.testkit.lost","cancelled.testkit.cancelled","cancelled.testkit.do_not_process","collecting_sample.testkit.problem_in_transit_customer","collecting_sample.testkit.problem_in_transit_lab","received.on_site_collection.ordered","received.on_site_collection.requisition_created","received.on_site_collection.requisition_bypassed","sample_with_lab.on_site_collection.draw_completed","completed.on_site_collection.completed","cancelled.on_site_collection.cancelled","sample_with_lab.on_site_collection.partial_results","failed.on_site_collection.sample_error","completed.walk_in_test.corrected","completed.at_home_phlebotomy.corrected","completed.on_site_collection.corrected","completed.testkit.corrected"]}},{"name":"delay","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Seconds to defer the status transition"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimulationFlags"}}}},"responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string","examples":["Success"]}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/result":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_result_raw_v3_order__order_id__result_get","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"results carry provider-side specimen data; covered by the mock-internal results property suite instead"}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LabResultsRaw"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/result/metadata":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_result_metadata_v3_order__order_id__result_metadata_get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LabResultsMetadata"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/result/pdf":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_result_pdf_v3_order__order_id__result_pdf_get","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"PDF bytes are provider-rendered; compared by shape (byteLength) only in the scenario script"}},"responses":{"200":{"description":"Successful Response","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order/{order_id}/requisition/pdf":{"parameters":[{"name":"order_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_order_requisition_pdf_v3_order__order_id__requisition_pdf_get","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"PDF bytes are provider-rendered; compared by shape (byteLength) only in the scenario script"}},"responses":{"200":{"description":"Successful Response","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/orders":{"get":{"operationId":"get_orders_v3_orders_get","x-mockingbird":{"supported":true,"parity":{"enabled":true,"safe":true}},"parameters":[{"name":"user_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"user","missing":"00000000-0000-4000-8000-000000000000"}}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetOrdersResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order_transaction/{transaction_id}":{"parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order_transaction","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_order_transaction_v3_order_transaction__transaction_id__get","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"order transactions are not available to the sandbox team (feature not available)"}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetOrderTransactionResponse"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v3/order_transaction/{transaction_id}/result":{"parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order_transaction","missing":"00000000-0000-4000-8000-000000000000"}}}],"get":{"operationId":"get_order_transaction_result_v3_order_transaction__transaction_id__result_get","x-mockingbird":{"supported":true,"parity":{"enabled":false,"safe":true,"reason":"lab results are not available to the sandbox team (feature not available)"}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LabResultsRaw"}}}},"404":{"description":"Not Found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"securitySchemes":{"apiKeyAuth":{"type":"apiKey","in":"header","name":"x-vital-api-key"}},"schemas":{"UserCreateBody":{"type":"object","required":["client_user_id"],"properties":{"client_user_id":{"type":"string","minLength":1,"maxLength":64,"examples":["mbr_8891","patient-1042","user.profile_52"]},"fallback_time_zone":{"type":["string","null"],"enum":["America/Los_Angeles","America/New_York","Europe/London","UTC",null]}}},"ClientFacingUser":{"type":"object","required":["user_id","team_id","client_user_id","created_on","connected_sources","fallback_time_zone"],"properties":{"user_id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"user","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"team_id":{"type":"string","format":"uuid","x-mockingbird-volatile":{"kind":"account"}},"client_user_id":{"type":"string"},"created_on":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}},"connected_sources":{"type":"array","items":{"type":"object","additionalProperties":true}},"fallback_time_zone":{"type":["object","null"],"properties":{"id":{"type":"string"},"source_slug":{"type":"string"},"updated_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}}}},"fallback_birth_date":{"type":["object","null"],"properties":{"value":{"type":"string"},"source_slug":{"type":"string"},"updated_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}}}},"ingestion_start":{"type":["string","null"]},"ingestion_end":{"type":["string","null"]}}},"UserInfoPatchBody":{"type":"object","properties":{"first_name":{"type":["string","null"]},"last_name":{"type":["string","null"]},"dob":{"type":["string","null"]},"gender":{"type":["string","null"]},"phone_number":{"type":["string","null"]},"email":{"type":["string","null"]},"address":{"type":["object","null"],"additionalProperties":true}}},"UserInfo":{"type":"object","additionalProperties":true},"ClientUserIDConflictResponse":{"type":"object","required":["detail"],"properties":{"detail":{"type":"object","required":["error_type","error_message","user_id","created_on"],"properties":{"error_type":{"type":"string"},"error_message":{"type":"string"},"user_id":{"type":"string","format":"uuid","x-mockingbird-volatile":{"kind":"id"}},"created_on":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}}}}}},"UserSuccessResponse":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean"}}},"PaginatedUsersResponse":{"type":"object","required":["users","total","offset","limit"],"properties":{"users":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingUser"}},"total":{"type":"integer"},"offset":{"type":"integer"},"limit":{"type":"integer"}}},"UserPatchBody":{"type":"object","properties":{"fallback_time_zone":{"type":["string","null"]},"fallback_birth_date":{"type":["string","null"],"format":"date"},"ingestion_start":{"type":["string","null"],"format":"date"},"ingestion_end":{"type":["string","null"],"format":"date"},"client_user_id":{"type":["string","null"]}}},"LabTestCollectionMethod":{"type":"string","enum":["testkit","walk_in_test","at_home_phlebotomy","on_site_collection"]},"LabTestGenerationMethodFilter":{"type":"string","enum":["auto","manual","all"]},"LabTestSampleType":{"type":"string","enum":["dried_blood_spot","arm_collector","serum","saliva","urine","stool"]},"LabTestStatus":{"type":"string","enum":["active","pending_approval","inactive"]},"MarkerType":{"type":"string","enum":["biomarker","panel"]},"ClientFacingLab":{"type":"object","required":["id","slug","name","first_line_address","city","zipcode","collection_methods","sample_types"],"properties":{"id":{"type":"integer","x-mockingbird-volatile":{"kind":"id"}},"slug":{"type":"string"},"name":{"type":"string"},"first_line_address":{"type":"string"},"city":{"type":"string"},"zipcode":{"type":"string"},"collection_methods":{"type":"array","items":{"$ref":"#/components/schemas/LabTestCollectionMethod"}},"sample_types":{"type":"array","items":{"$ref":"#/components/schemas/LabTestSampleType"}},"logo_url":{"type":["string","null"]}}},"ClientFacingMarker":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"integer","x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"slug":{"type":"string"},"description":{"type":["string","null"]},"lab_id":{"type":["integer","null"]},"provider_id":{"type":["string","null"]},"type":{"anyOf":[{"$ref":"#/components/schemas/MarkerType"},{"type":"null"}]},"unit":{"type":["string","null"]},"price":{"type":["string","null"]},"aoe":{"anyOf":[{"type":"object","additionalProperties":true},{"type":"null"}]},"a_la_carte_enabled":{"type":"boolean","default":false},"common_tat_days":{"type":["integer","null"]},"worst_case_tat_days":{"type":["integer","null"]},"is_orderable":{"type":["boolean","null"],"default":true}}},"ClientFacingLabTest":{"type":"object","required":["id","slug","name","sample_type","method","price","is_active","status","lab","markers"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"lab_test","identity":true}},"slug":{"type":"string","x-mockingbird-volatile":{"kind":"token"}},"name":{"type":"string","x-mockingbird-volatile":{"kind":"token"}},"sample_type":{"$ref":"#/components/schemas/LabTestSampleType"},"method":{"$ref":"#/components/schemas/LabTestCollectionMethod"},"price":{"type":"number"},"is_active":{"type":"boolean"},"status":{"$ref":"#/components/schemas/LabTestStatus"},"fasting":{"type":"boolean","default":false},"lab":{"anyOf":[{"$ref":"#/components/schemas/ClientFacingLab"},{"type":"null"}]},"markers":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingMarker"}},{"type":"null"}]},"is_delegated":{"type":"boolean","default":false},"auto_generated":{"type":"boolean","default":false},"has_collection_instructions":{"type":["boolean","null"]},"common_tat_days":{"type":["integer","null"]},"worst_case_tat_days":{"type":["integer","null"]}}},"LabTestResourcesResponse":{"type":"object","required":["data","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingLabTest"}},"next_cursor":{"type":["string","null"]}}},"LabAccountStatus":{"type":"string","enum":["active","pending","suspended","ready_to_launch"]},"LabAccountDelegatedFlow":{"type":"string","enum":["order_delegated","result_delegated","fully_delegated","not_delegated"]},"USState":{"type":"string","enum":["AL","AK","AZ","AR","CA","CO","CT","DE","FL","GA","HI","ID","IL","IN","IA","KS","KY","LA","ME","MD","MA","MI","MN","MS","MO","MT","NE","NV","NH","NJ","NM","NY","NC","ND","OH","OK","OR","PA","RI","SC","SD","TN","TX","UT","VT","VA","WA","WV","WI","WY"]},"Labs":{"type":"string","enum":["ayumetrix","spiriplex","ussl","quest","sonora_quest","labcorp","bioreference","us_biotek","manual","sanocardio","ihd","nexus","my_uti","crl","mtl"]},"ClientFacingLabAccount":{"type":"object","required":["id","lab","status","delegated_flow","provider_account_id","allowed_billing","team_id_allowlist"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"lab_account","identity":true}},"lab":{"$ref":"#/components/schemas/Labs"},"org_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"status":{"$ref":"#/components/schemas/LabAccountStatus"},"delegated_flow":{"$ref":"#/components/schemas/LabAccountDelegatedFlow"},"provider_account_id":{"type":"string"},"account_name":{"anyOf":[{"type":"string"},{"type":"null"}]},"default_clinical_notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"business_units":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"allowed_billing":{"type":"object","propertyNames":{"$ref":"#/components/schemas/Billing"},"additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/USState"}}},"team_id_allowlist":{"type":"array","items":{"type":"string","format":"uuid"}}}},"GetTeamLabAccountsResponse":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingLabAccount"}}}},"ClientFacingResult":{"type":"object","required":["name","slug","type"],"properties":{"name":{"type":"string"},"slug":{"type":"string"},"provider_id":{"type":["string","null"]},"type":{"$ref":"#/components/schemas/ResultType"},"value":{"type":["number","null"]},"unit":{"type":["string","null"]},"low_value":{"type":["number","null"]},"high_value":{"type":["number","null"]},"string_value":{"type":["string","null"]},"coded_value":{"type":["string","null"]},"is_abnormal":{"type":"boolean","default":false},"notes":{"type":["string","null"]}}},"GetMarkersResponse":{"type":"object","required":["markers"],"properties":{"markers":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingMarkerComplete"}},"total":{"type":["integer","null"]},"page":{"type":["integer","null"]},"size":{"type":["integer","null"]},"pages":{"type":["integer","null"]}}},"ClientFacingExpectedResult":{"type":"object","required":["id","name","slug","required"],"properties":{"id":{"type":"integer","x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"slug":{"type":"string"},"lab_id":{"type":["integer","null"]},"provider_id":{"type":["string","null"]},"required":{"type":"boolean"},"loinc":{"type":["object","null"],"required":["id","name","slug","code"],"properties":{"id":{"type":"integer","x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"slug":{"type":"string"},"code":{"type":"string"},"unit":{"type":["string","null"]}}}}},"ClientFacingMarkerComplete":{"type":"object","required":["id","name","slug","expected_results"],"properties":{"id":{"type":"integer","x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"slug":{"type":"string"},"description":{"type":["string","null"]},"lab_id":{"type":["integer","null"]},"provider_id":{"type":["string","null"]},"type":{"anyOf":[{"$ref":"#/components/schemas/MarkerType"},{"type":"null"}]},"unit":{"type":["string","null"]},"price":{"type":["string","null"]},"a_la_carte_enabled":{"type":"boolean","default":false},"common_tat_days":{"type":["integer","null"]},"worst_case_tat_days":{"type":["integer","null"]},"is_orderable":{"type":["boolean","null"],"default":true},"expected_results":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingExpectedResult"}}}},"ListOrderSetMarkersRequest":{"type":"object","required":["order_set_id"],"properties":{"order_set_id":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order_transaction","missing":"00000000-0000-4000-8000-000000000000"}},"provider_id":{"type":["string","null"]}}},"AllowedRadius":{"type":"integer","enum":[10,20,25,50,100]},"AppointmentPscLabs":{"type":"string","enum":["quest"]},"AppointmentProvider":{"type":"string","enum":["getlabs","phlebfinders","quest"]},"AppointmentType":{"type":"string","enum":["phlebotomy","patient_service_center"]},"AppointmentStatus":{"type":"string","enum":["confirmed","pending","reserved","in_progress","completed","cancelled"]},"AppointmentEventStatus":{"type":"string","enum":["pending","reserved","scheduled","completed","cancelled","in_progress"]},"AppointmentServiceType":{"type":"string","enum":["appointment-ready","appointment-request"]},"Billing":{"type":"string","enum":["client_bill","commercial_insurance","patient_bill_passthrough","patient_bill"]},"LabLocationCapability":{"type":"string","enum":["stat","appointment_scheduling_via_junction","appointment_scheduling_with_lab"]},"LngLat":{"type":"object","required":["lng","lat"],"properties":{"lng":{"type":"number"},"lat":{"type":"number"}}},"UsAddress":{"type":"object","required":["first_line","city","state","zip_code"],"properties":{"first_line":{"type":"string","minLength":1},"second_line":{"type":["string","null"]},"city":{"type":"string","minLength":1},"state":{"type":"string","minLength":1},"zip_code":{"type":"string","minLength":1},"unit":{"type":["string","null"]}}},"AppointmentLocation":{"type":"object","required":["location","address","code","name"],"properties":{"location":{"$ref":"#/components/schemas/LngLat"},"distance":{"type":["number","null"]},"address":{"$ref":"#/components/schemas/UsAddress"},"code":{"type":"string"},"name":{"type":"string"},"iana_timezone":{"type":["string","null"]}}},"TimeSlot":{"type":"object","required":["start","end","price","is_priority","num_appointments_available"],"properties":{"booking_key":{"type":["string","null"],"x-mockingbird-resource":{"type":"booking_key","identity":true},"x-mockingbird-volatile":{"kind":"token"}},"start":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}},"end":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}},"expires_at":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"timestamp"}},"price":{"type":"number"},"is_priority":{"type":"boolean"},"num_appointments_available":{"type":"integer"}}},"DaySlots":{"type":"object","required":["date","slots"],"properties":{"location":{"anyOf":[{"$ref":"#/components/schemas/AppointmentLocation"},{"type":"null"}]},"date":{"type":"string","format":"date"},"slots":{"type":"array","items":{"$ref":"#/components/schemas/TimeSlot"}}}},"AppointmentAvailabilitySlots":{"type":"object","required":["slots"],"properties":{"slots":{"type":"array","items":{"$ref":"#/components/schemas/DaySlots"}},"timezone":{"type":["string","null"]}}},"AppointmentBookingRequest":{"type":"object","required":["booking_key"],"properties":{"booking_key":{"type":"string","minLength":1,"x-mockingbird-resource-ref":{"type":"booking_key"}}}},"AppointmentRescheduleRequest":{"type":"object","required":["booking_key"],"properties":{"booking_key":{"type":"string","minLength":1,"x-mockingbird-resource-ref":{"type":"booking_key"}}}},"PscAppointmentBookingRequest":{"type":"object","required":["booking_key","site_code"],"properties":{"booking_key":{"type":"string","minLength":1,"x-mockingbird-resource-ref":{"type":"booking_key"}},"site_code":{"type":"string","minLength":1}}},"PhlebotomyAppointmentCancelRequest":{"type":"object","required":["cancellation_reason_id"],"properties":{"cancellation_reason_id":{"type":"string","minLength":1},"notes":{"type":["string","null"]}}},"PscAppointmentCancelRequest":{"type":"object","required":["cancellationReasonId"],"properties":{"cancellationReasonId":{"type":"string","minLength":1},"note":{"type":["string","null"]}}},"ClientFacingAppointmentEvent":{"type":"object","required":["created_at","status"],"properties":{"created_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}},"status":{"$ref":"#/components/schemas/AppointmentEventStatus"},"data":{"anyOf":[{"type":"object","additionalProperties":true},{"type":"null"}]}}},"ClientFacingAppointment":{"type":"object","required":["id","user_id","order_id","address","location","type","provider","status","provider_id","can_reschedule","event_status","events"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"appointment","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"user_id":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"user"}},"order_id":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"order"}},"address":{"$ref":"#/components/schemas/UsAddress"},"location":{"$ref":"#/components/schemas/LngLat"},"start_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"timestamp"}},"end_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"timestamp"}},"iana_timezone":{"type":["string","null"]},"type":{"$ref":"#/components/schemas/AppointmentType"},"provider":{"$ref":"#/components/schemas/AppointmentProvider"},"status":{"$ref":"#/components/schemas/AppointmentStatus"},"provider_id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"external_id":{"type":["string","null"],"x-mockingbird-volatile":{"kind":"id"}},"can_reschedule":{"type":"boolean"},"event_status":{"$ref":"#/components/schemas/AppointmentEventStatus"},"event_data":{"anyOf":[{"type":"object","additionalProperties":true},{"type":"null"}]},"order_transaction_id":{"type":["string","null"],"x-mockingbird-resource-ref":{"type":"order_transaction"}},"appointment_notes":{"type":["string","null"]},"events":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingAppointmentEvent"}}}},"ClientFacingAppointmentCancellationReason":{"type":"object","required":["id","name","is_refundable"],"properties":{"id":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"name":{"type":"string"},"is_refundable":{"type":"boolean"}}},"PhlebotomyAreaInfo":{"type":"object","required":["is_served","providers"],"properties":{"is_served":{"type":"boolean"},"providers":{"type":"array","items":{"$ref":"#/components/schemas/PhlebotomyProviderInfo"}}}},"PhlebotomyProviderInfo":{"type":"object","required":["name","service_types"],"properties":{"name":{"$ref":"#/components/schemas/AppointmentProvider"},"service_types":{"type":"array","items":{"$ref":"#/components/schemas/AppointmentServiceType"}}}},"PscAreaInfoDetails":{"type":"object","required":["appointment_with_vital","within_radius","radius"],"properties":{"appointment_with_vital":{"type":"boolean"},"within_radius":{"type":"number"},"radius":{"type":"string"},"capabilities":{"type":["array","null"],"items":{"$ref":"#/components/schemas/LabLocationCapability"}}}},"PscAreaInfo":{"type":"object","required":["patient_service_centers","supported_bill_types","lab_id"],"properties":{"patient_service_centers":{"$ref":"#/components/schemas/PscAreaInfoDetails"},"supported_bill_types":{"type":"array","items":{"$ref":"#/components/schemas/Billing"}},"lab_id":{"type":"integer"}}},"AreaInfo":{"type":"object","required":["zip_code","phlebotomy","central_labs"],"properties":{"zip_code":{"type":"string"},"phlebotomy":{"$ref":"#/components/schemas/PhlebotomyAreaInfo"},"central_labs":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/PscAreaInfo"}}}},"LabLocationMetadata":{"type":"object","required":["name","state","city","zip_code","first_line"],"properties":{"name":{"type":"string"},"state":{"type":"string"},"city":{"type":"string"},"zip_code":{"type":"string"},"first_line":{"type":"string"},"second_line":{"type":["string","null"]},"phone_number":{"type":["string","null"]},"fax_number":{"type":["string","null"]},"hours":{"type":["object","null"],"additionalProperties":true}}},"ClientFacingLabLocation":{"type":"object","required":["metadata","distance","site_code","supported_bill_types","location","capabilities"],"properties":{"metadata":{"$ref":"#/components/schemas/LabLocationMetadata"},"distance":{"type":"number"},"site_code":{"type":"string"},"supported_bill_types":{"type":"array","items":{"$ref":"#/components/schemas/Billing"}},"location":{"$ref":"#/components/schemas/LngLat"},"capabilities":{"type":"array","items":{"$ref":"#/components/schemas/LabLocationCapability"}}}},"PscInfo":{"type":"object","required":["lab_id","slug","patient_service_centers"],"properties":{"lab_id":{"type":"integer"},"slug":{"type":"string"},"patient_service_centers":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingLabLocation"}}}},"OrderTopLevelStatus":{"type":"string","enum":["received","collecting_sample","sample_with_lab","completed","cancelled","failed"]},"OrderLowLevelStatus":{"type":"string","enum":["ordered","requisition_created","requisition_bypassed","transit_customer","out_for_delivery","with_customer","transit_lab","delivered_to_lab","completed","failure_to_deliver_to_lab","failure_to_deliver_to_customer","problem_in_transit_lab","problem_in_transit_customer","sample_error","appointment_scheduled","appointment_cancelled","appointment_pending","draw_completed","cancelled","lost","do_not_process","partial_results","awaiting_registration","registered","redraw_available","corrected","lab_processing_blocked"]},"OrderStatus":{"type":"string","enum":["received.walk_in_test.ordered","received.walk_in_test.requisition_created","received.walk_in_test.requisition_bypassed","completed.walk_in_test.completed","sample_with_lab.walk_in_test.partial_results","failed.walk_in_test.sample_error","cancelled.walk_in_test.cancelled","collecting_sample.walk_in_test.appointment_pending","collecting_sample.walk_in_test.appointment_scheduled","collecting_sample.walk_in_test.appointment_cancelled","collecting_sample.walk_in_test.redraw_available","received.at_home_phlebotomy.ordered","received.at_home_phlebotomy.requisition_created","received.at_home_phlebotomy.requisition_bypassed","collecting_sample.at_home_phlebotomy.appointment_pending","collecting_sample.at_home_phlebotomy.appointment_scheduled","collecting_sample.at_home_phlebotomy.draw_completed","collecting_sample.at_home_phlebotomy.appointment_cancelled","completed.at_home_phlebotomy.completed","sample_with_lab.at_home_phlebotomy.partial_results","cancelled.at_home_phlebotomy.cancelled","failed.at_home_phlebotomy.sample_error","received.testkit.ordered","received.testkit.awaiting_registration","received.testkit.requisition_created","received.testkit.requisition_bypassed","received.testkit.registered","collecting_sample.testkit.transit_customer","collecting_sample.testkit.out_for_delivery","collecting_sample.testkit.with_customer","collecting_sample.testkit.transit_lab","sample_with_lab.testkit.delivered_to_lab","sample_with_lab.testkit.lab_processing_blocked","completed.testkit.completed","failed.testkit.failure_to_deliver_to_customer","failed.testkit.failure_to_deliver_to_lab","failed.testkit.sample_error","failed.testkit.lost","cancelled.testkit.cancelled","cancelled.testkit.do_not_process","collecting_sample.testkit.problem_in_transit_customer","collecting_sample.testkit.problem_in_transit_lab","received.on_site_collection.ordered","received.on_site_collection.requisition_created","received.on_site_collection.requisition_bypassed","sample_with_lab.on_site_collection.draw_completed","completed.on_site_collection.completed","cancelled.on_site_collection.cancelled","sample_with_lab.on_site_collection.partial_results","failed.on_site_collection.sample_error","completed.walk_in_test.corrected","completed.at_home_phlebotomy.corrected","completed.on_site_collection.corrected","completed.testkit.corrected"]},"OrderStatusDetail":{"type":"string","enum":["fulfillment_error","date_of_collection_unspecified","demographic_information_unspecified","demographic_information_mismatch","sample_quantity_not_sufficient","sample_contaminated","sample_stability_exceeded","sample_hemolyzed","sample_improper_collection"]},"OrderTransactionStatus":{"type":"string","enum":["active","completed","cancelled"]},"ClientFacingOrderEvent":{"type":"object","required":["id","created_at","status"],"properties":{"id":{"type":"integer","x-mockingbird-volatile":{"kind":"opaque"}},"created_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}},"status":{"$ref":"#/components/schemas/OrderStatus"},"status_detail":{"anyOf":[{"$ref":"#/components/schemas/OrderStatusDetail"},{"type":"null"}]}}},"ShippingAddress":{"type":"object","required":["receiver_name","first_line","city","state","zip","country","phone_number"],"properties":{"receiver_name":{"type":"string"},"first_line":{"type":"string"},"second_line":{"type":["string","null"]},"city":{"type":"string"},"state":{"type":"string"},"zip":{"type":"string"},"country":{"type":"string"},"phone_number":{"type":"string"}}},"ClientFacingPhysician":{"type":"object","required":["first_name","last_name","npi"],"properties":{"first_name":{"type":"string"},"last_name":{"type":"string"},"npi":{"type":"string"}}},"ClientFacingShipment":{"type":"object","required":["id","outbound_tracking_number","outbound_tracking_url","inbound_tracking_number","inbound_tracking_url","outbound_courier","inbound_courier","notes"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-volatile":{"kind":"id"}},"outbound_tracking_number":{"type":["string","null"]},"outbound_tracking_url":{"type":["string","null"]},"inbound_tracking_number":{"type":["string","null"]},"inbound_tracking_url":{"type":["string","null"]},"outbound_courier":{"type":["string","null"]},"inbound_courier":{"type":["string","null"]},"notes":{"type":["string","null"]}}},"ClientFacingTestkitOrder":{"type":"object","required":["id","shipment","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-volatile":{"kind":"id"}},"shipment":{"anyOf":[{"$ref":"#/components/schemas/ClientFacingShipment"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"opaque"}},"created_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}}}},"ClientFacingWalkInOrder":{"type":"object","required":["id","appointment_id","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-volatile":{"kind":"id"}},"appointment_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"created_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}}}},"ClientFacingTestKitOrderDetails":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["testkit","walk_in_test","at_home_phlebotomy","on_site_collection"]},"data":{"anyOf":[{"$ref":"#/components/schemas/ClientFacingTestkitOrder"},{"$ref":"#/components/schemas/ClientFacingWalkInOrder"},{"type":"null"}]}}},"ClientFacingPatientDetailsCompatible":{"type":"object","required":["first_name","last_name","dob","gender","phone_number","email"],"properties":{"first_name":{"type":"string","minLength":1,"pattern":"^[a-zA-Z0-9][a-zA-Z0-9 .,'-]*$","examples":["Ada","Chris","Maria","Jun"]},"last_name":{"type":"string","minLength":1,"pattern":"^[a-zA-Z0-9][a-zA-Z0-9 .,'-]*$","examples":["Lovelace","Vouga","Delgado","Park"]},"dob":{"type":"string","format":"date-time","examples":["1990-06-15T00:00:00.000Z","1983-02-02T00:00:00.000Z"]},"gender":{"type":"string","minLength":1,"pattern":"\\\\S","examples":["male","female","other","prefer_not_to_say"]},"phone_number":{"type":"string","minLength":1,"pattern":"^\\\\+1[2-9]\\\\d{9}$","examples":["+14155550123","+12125550987","+13105554444"]},"email":{"type":"string","format":"email","minLength":1,"examples":["ada@example.com","chris@example.com","maria@example.com"]}}},"PatientAddressCompatible":{"type":"object","required":["first_line","city","state","zip","country"],"properties":{"receiver_name":{"type":"string","default":"","examples":["Ada Lovelace","Chris Vouga"]},"first_line":{"type":"string","minLength":1,"pattern":"\\\\S","examples":["1 Main St","450 Market St","88 Kearny St"]},"second_line":{"type":["string","null"]},"city":{"type":"string","minLength":1,"pattern":"\\\\S","examples":["San Diego","San Francisco","New York"]},"state":{"type":"string","minLength":1,"enum":["AL","AK","AZ","AR","CA","CO","CT","DE","FL","GA","HI","ID","IL","IN","IA","KS","KY","LA","ME","MD","MA","MI","MN","MS","MO","MT","NE","NV","NH","NJ","NM","NY","NC","ND","OH","OK","OR","PA","RI","SC","SD","TN","TX","UT","VT","VA","WA","WV","WI","WY"]},"zip":{"type":"string","pattern":"^\\\\d{5}(-\\\\d{4})?$","examples":["92101","94105","10001"]},"country":{"type":"string","minLength":1,"pattern":"\\\\S","examples":["US"]},"access_notes":{"type":["string","null"],"examples":[null]},"phone_number":{"type":["string","null"],"examples":["+14155550123",null]}}},"AoeAnswerRequest":{"type":"object","required":["marker_id","question_id","answer"],"properties":{"marker_id":{"type":"integer","examples":[2075,1975]},"question_id":{"type":"integer","examples":[1]},"answer":{"type":"string","minLength":1,"examples":["No","Yes"]}}},"ClientFacingOrderInTransaction":{"type":"object","required":["id","created_at","updated_at"],"properties":{"id":{"type":"string","format":"uuid"},"low_level_status":{"anyOf":[{"$ref":"#/components/schemas/OrderLowLevelStatus"},{"type":"null"}]},"low_level_status_created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"timestamp"}},"created_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}}}},"ClientFacingOrderTransaction":{"type":"object","required":["id","status","orders"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"order_transaction","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"status":{"$ref":"#/components/schemas/OrderTransactionStatus"},"orders":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingOrderInTransaction"}}}},"OrderSummary":{"type":"object","required":["id","last_status","last_status_created_at","updated_at","created_at"],"properties":{"id":{"type":"string","format":"uuid"},"origin":{"anyOf":[{"type":"string","enum":["initial","redraw","recreation"]},{"type":"null"}]},"parent_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"last_status":{"$ref":"#/components/schemas/OrderLowLevelStatus"},"last_status_created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"}}},"GetOrderTransactionResponse":{"type":"object","required":["id","team_id","status"],"properties":{"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"order_transaction","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"team_id":{"type":"string","format":"uuid","x-mockingbird-volatile":{"kind":"account"}},"status":{"$ref":"#/components/schemas/OrderTransactionStatus"},"orders":{"type":"array","items":{"$ref":"#/components/schemas/OrderSummary"}}}},"ClientFacingOrder":{"type":"object","required":["user_id","id","team_id","patient_details","patient_address","lab_test","details","sample_id","notes","created_at","updated_at","events","last_event","health_insurance_id","requisition_form_url","shipping_details","has_abn"],"properties":{"user_id":{"type":"string","format":"uuid"},"id":{"type":"string","format":"uuid","x-mockingbird-resource":{"type":"order","identity":true},"x-mockingbird-volatile":{"kind":"id"}},"team_id":{"type":"string","format":"uuid","x-mockingbird-volatile":{"kind":"account"}},"patient_details":{"anyOf":[{"$ref":"#/components/schemas/ClientFacingPatientDetailsCompatible"},{"type":"null"}]},"patient_address":{"anyOf":[{"$ref":"#/components/schemas/PatientAddressCompatible"},{"type":"null"}]},"lab_test":{"$ref":"#/components/schemas/ClientFacingLabTest"},"details":{"$ref":"#/components/schemas/ClientFacingTestKitOrderDetails"},"sample_id":{"anyOf":[{"type":"string"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"opaque"}},"notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"clinical_notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}},"updated_at":{"type":"string","format":"date-time","x-mockingbird-volatile":{"kind":"timestamp"}},"events":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingOrderEvent"}},"status":{"anyOf":[{"$ref":"#/components/schemas/OrderTopLevelStatus"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"opaque"}},"last_event":{"$ref":"#/components/schemas/ClientFacingOrderEvent"},"physician":{"anyOf":[{"$ref":"#/components/schemas/ClientFacingPhysician"},{"type":"null"}]},"health_insurance_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"requisition_form_url":{"anyOf":[{"type":"string"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"url"}},"priority":{"type":"boolean","default":false},"shipping_details":{"anyOf":[{"$ref":"#/components/schemas/ShippingAddress"},{"type":"null"}]},"activate_by":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}]},"passthrough":{"anyOf":[{"type":"string"},{"type":"null"}]},"billing_type":{"type":"string","enum":["client_bill","commercial_insurance","patient_bill_passthrough","patient_bill","upfront_payment"],"default":"client_bill"},"icd_codes":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"has_abn":{"type":"boolean"},"interpretation":{"anyOf":[{"type":"string","enum":["normal","abnormal","critical","unknown"]},{"type":"null"}]},"has_missing_results":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"expected_result_by_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}]},"worst_case_result_by_date":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}]},"origin":{"anyOf":[{"type":"string","enum":["initial","redraw","recreation"]},{"type":"null"}]},"order_transaction":{"anyOf":[{"$ref":"#/components/schemas/ClientFacingOrderTransaction"},{"type":"null"}]}}},"OrderSetRequest":{"type":"object","required":["lab_test_ids"],"properties":{"lab_test_ids":{"type":"array","minItems":1,"items":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"lab_test","missing":"00000000-0000-4000-8000-000000000000"}}}}},"CreateOrderRequest":{"type":"object","required":["user_id","patient_details","patient_address","order_set"],"properties":{"user_id":{"type":"string","format":"uuid","x-mockingbird-resource-ref":{"type":"user","missing":"00000000-0000-4000-8000-000000000000"}},"patient_details":{"$ref":"#/components/schemas/ClientFacingPatientDetailsCompatible"},"patient_address":{"$ref":"#/components/schemas/PatientAddressCompatible"},"order_set":{"$ref":"#/components/schemas/OrderSetRequest"},"clinical_notes":{"anyOf":[{"type":"string"},{"type":"null"}]},"passthrough":{"anyOf":[{"type":"string"},{"type":"null"}]},"collection_method":{"$ref":"#/components/schemas/LabTestCollectionMethod"},"lab_account_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"idempotency_key":{"type":["string","null"]},"idempotency_error":{"type":["string","null"]},"aoe_answers":{"type":["array","null"],"items":{"$ref":"#/components/schemas/AoeAnswerRequest"}}}},"PostOrderResponse":{"type":"object","required":["order","status","message"],"properties":{"order":{"$ref":"#/components/schemas/ClientFacingOrder"},"status":{"type":"string"},"message":{"type":"string"}}},"ResultType":{"type":"string","enum":["numeric","range","comment","coded_value"]},"ParentBiomarkerData":{"type":"object","required":["marker_id","name","slug"],"properties":{"marker_id":{"type":"integer"},"name":{"type":"string"},"slug":{"type":"string"},"provider_id":{"type":["string","null"]}}},"BiomarkerResult":{"type":"object","required":["name","result","type"],"properties":{"name":{"type":"string"},"slug":{"type":"string","default":""},"value":{"anyOf":[{"type":"number"},{"type":"null"}]},"result":{"type":"string"},"type":{"$ref":"#/components/schemas/ResultType"},"unit":{"type":["string","null"]},"timestamp":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"timestamp"}},"notes":{"type":["string","null"]},"reference_range":{"type":["string","null"]},"min_range_value":{"type":["number","null"]},"max_range_value":{"type":["number","null"]},"is_above_max_range":{"type":["boolean","null"]},"is_below_min_range":{"type":["boolean","null"]},"interpretation":{"type":"string","default":"normal"},"source_interpretation":{"type":"string","default":""},"loinc":{"type":["string","null"]},"loinc_slug":{"type":["string","null"]},"provider_id":{"type":["string","null"]},"source_markers":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/ParentBiomarkerData"}},{"type":"null"}]},"performing_laboratory":{"type":["string","null"]},"source_sample_id":{"type":["string","null"]}}},"FailureType":{"type":"string","enum":["quantity_not_sufficient_failure","collection_process_failure","drop_off_failure","internal_lab_failure","order_entry_failure","non_failure","unknown_failure","patient_condition_failure","missing_result_calc_failure","missing_demo_aoe_calc_failure","insufficient_volume"]},"MissingBiomarkerResult":{"type":"object","required":["name","slug","inferred_failure_type"],"properties":{"name":{"type":"string"},"slug":{"type":"string"},"inferred_failure_type":{"$ref":"#/components/schemas/FailureType"},"note":{"type":["string","null"]},"loinc":{"type":["string","null"]},"loinc_slug":{"type":["string","null"]},"provider_id":{"type":["string","null"]},"source_markers":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/ParentBiomarkerData"}},{"type":"null"}]}}},"SampleData":{"type":"object","properties":{"sample_id":{"type":["string","null"]},"control_number":{"type":["string","null"]},"date_collected":{"type":["string","null"]},"date_received":{"type":["string","null"]},"date_reported":{"type":["string","null"]},"performing_laboratories":{"anyOf":[{"type":"object","additionalProperties":true},{"type":"null"}]},"clinical_information":{"anyOf":[{"type":"object","additionalProperties":true},{"type":"null"}]}}},"LabResultsMetadata":{"type":"object","required":["age","dob","patient","date_reported","specimen_number"],"properties":{"age":{"type":"string","x-mockingbird-volatile":{"kind":"token"}},"dob":{"type":"string","x-mockingbird-volatile":{"kind":"token"}},"clia_#":{"anyOf":[{"type":"string"},{"type":"null"}]},"patient":{"type":"string","x-mockingbird-volatile":{"kind":"token"}},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"token"}},"laboratory":{"anyOf":[{"type":"string"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"token"}},"date_reported":{"type":"string","x-mockingbird-volatile":{"kind":"timestamp"}},"date_collected":{"anyOf":[{"type":"string"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"timestamp"}},"specimen_number":{"type":"string","x-mockingbird-volatile":{"kind":"id"}},"date_received":{"anyOf":[{"type":"string"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"timestamp"}},"status":{"type":"string","default":"final"},"interpretation":{"anyOf":[{"type":"string"},{"type":"null"}]},"patient_id":{"anyOf":[{"type":"string"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"id"}},"account_id":{"anyOf":[{"type":"string"},{"type":"null"}],"x-mockingbird-volatile":{"kind":"id"}}}},"LabResultsRaw":{"type":"object","required":["metadata","results"],"properties":{"metadata":{"$ref":"#/components/schemas/LabResultsMetadata"},"results":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/BiomarkerResult"}},{"type":"object","additionalProperties":true}],"x-mockingbird-volatile":{"kind":"opaque"}},"missing_results":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/MissingBiomarkerResult"}},{"type":"null"}],"x-mockingbird-volatile":{"kind":"opaque"}},"sample_information":{"anyOf":[{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SampleData"}},{"type":"null"}],"x-mockingbird-volatile":{"kind":"opaque"}},"order_transaction":{"anyOf":[{"$ref":"#/components/schemas/ClientFacingOrderTransaction"},{"type":"null"}]}}},"SimulationFlags":{"type":"object","properties":{"interpretation":{"anyOf":[{"type":"string","enum":["normal","abnormal","critical","unknown"]},{"type":"null"}]},"result_types":{"type":"array","items":{"$ref":"#/components/schemas/ResultType"}},"has_missing_results":{"type":"boolean"}}},"GetOrdersResponse":{"type":"object","required":["orders"],"properties":{"orders":{"type":"array","items":{"$ref":"#/components/schemas/ClientFacingOrder"}},"total":{"anyOf":[{"type":"integer"},{"type":"null"}]},"page":{"anyOf":[{"type":"integer"},{"type":"null"}]},"size":{"anyOf":[{"type":"integer"},{"type":"null"}]}}},"HTTPValidationError":{"type":"object","properties":{"detail":{"title":"Detail"}}}}}}`);
|
|
5990
|
+
var operationIds = ["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"];
|
|
5991
|
+
var supportedOperationIds = ["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"];
|
|
5992
|
+
|
|
4958
5993
|
// src/results.ts
|
|
4959
5994
|
var RESULT_TYPES2 = ["numeric", "range", "comment", "coded_value"];
|
|
4960
5995
|
var INTERPRETATIONS2 = ["normal", "abnormal", "critical", "unknown"];
|
|
@@ -5103,13 +6138,13 @@ function resultsNotAvailable(orderId) {
|
|
|
5103
6138
|
var resultsHandlers = (state) => ({
|
|
5104
6139
|
get_result_raw_v3_order__order_id__result_get: async (context) => {
|
|
5105
6140
|
const orderId = context.params.order_id ?? "";
|
|
5106
|
-
const order = requireOrder(state, orderId, context
|
|
6141
|
+
const order = requireOrder(state, orderId, context);
|
|
5107
6142
|
const user = state.users.get(order.user_id);
|
|
5108
6143
|
if (!resultsReady(order)) resultsNotAvailable(order.id);
|
|
5109
6144
|
const flags = flagsOf(order);
|
|
5110
6145
|
const fixture = state.resultFixtures.get(order.id);
|
|
5111
6146
|
const results = fixture?.results ?? biomarkerLines(order, flags);
|
|
5112
|
-
const
|
|
6147
|
+
const missing2 = fixture?.missing_results !== void 0 ? fixture.missing_results : flags.hasMissingResults ? [
|
|
5113
6148
|
{
|
|
5114
6149
|
name: (order.lab_test.markers ?? [])[0]?.name ?? "Unknown marker",
|
|
5115
6150
|
slug: (order.lab_test.markers ?? [])[0]?.slug ?? "unknown-marker",
|
|
@@ -5124,7 +6159,7 @@ var resultsHandlers = (state) => ({
|
|
|
5124
6159
|
return jsonRes(200, {
|
|
5125
6160
|
metadata: metadataOf(order, user?.client_user_id ?? order.user_id),
|
|
5126
6161
|
results,
|
|
5127
|
-
missing_results:
|
|
6162
|
+
missing_results: missing2,
|
|
5128
6163
|
sample_information: {
|
|
5129
6164
|
[order.sample_id ?? opaqueToken(`junction:sample:${order.id}`, 16)]: {
|
|
5130
6165
|
sample_id: order.sample_id ?? opaqueToken(`junction:sample:${order.id}`, 16),
|
|
@@ -5141,14 +6176,14 @@ var resultsHandlers = (state) => ({
|
|
|
5141
6176
|
},
|
|
5142
6177
|
get_result_metadata_v3_order__order_id__result_metadata_get: async (context) => {
|
|
5143
6178
|
const orderId = context.params.order_id ?? "";
|
|
5144
|
-
const order = requireOrder(state, orderId, context
|
|
6179
|
+
const order = requireOrder(state, orderId, context);
|
|
5145
6180
|
if (!resultsReady(order)) resultsNotAvailable(order.id);
|
|
5146
6181
|
const user = state.users.get(order.user_id);
|
|
5147
6182
|
return jsonRes(200, metadataOf(order, user?.client_user_id ?? order.user_id));
|
|
5148
6183
|
},
|
|
5149
6184
|
get_result_pdf_v3_order__order_id__result_pdf_get: async (context) => {
|
|
5150
6185
|
const orderId = context.params.order_id ?? "";
|
|
5151
|
-
const order = requireOrder(state, orderId, context
|
|
6186
|
+
const order = requireOrder(state, orderId, context);
|
|
5152
6187
|
if (!resultsReady(order)) resultsNotAvailable(order.id);
|
|
5153
6188
|
const fixturePdf = state.resultFixtures.get(order.id)?.pdf_base64;
|
|
5154
6189
|
const bytes = fixturePdf !== void 0 ? Uint8Array.from(atob(fixturePdf), (char) => char.charCodeAt(0)) : deterministicPdf(`Lab results ${order.id}`);
|
|
@@ -5159,7 +6194,7 @@ var resultsHandlers = (state) => ({
|
|
|
5159
6194
|
},
|
|
5160
6195
|
get_order_requisition_pdf_v3_order__order_id__requisition_pdf_get: async (context) => {
|
|
5161
6196
|
const orderId = context.params.order_id ?? "";
|
|
5162
|
-
const order = requireOrder(state, orderId, context
|
|
6197
|
+
const order = requireOrder(state, orderId, context);
|
|
5163
6198
|
const bytes = deterministicPdf(`Requisition ${order.id}`);
|
|
5164
6199
|
return new Response(bytes, {
|
|
5165
6200
|
status: 200,
|
|
@@ -5624,8 +6659,8 @@ var listUsers = (state, offset, limit) => {
|
|
|
5624
6659
|
};
|
|
5625
6660
|
};
|
|
5626
6661
|
var isValidUuid = (value) => /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(value);
|
|
5627
|
-
function notFound3(detail) {
|
|
5628
|
-
|
|
6662
|
+
function notFound3(state, id, detail) {
|
|
6663
|
+
return missing(state, "user", id, detail);
|
|
5629
6664
|
}
|
|
5630
6665
|
var queryInt2 = (context, name, fallback) => {
|
|
5631
6666
|
const raw = context.query[name];
|
|
@@ -5951,7 +6986,7 @@ var userHandlers = (state) => ({
|
|
|
5951
6986
|
const body = jsonBody(context);
|
|
5952
6987
|
const errors = userInfoValidationErrors(body);
|
|
5953
6988
|
if (errors.length > 0) throw new HttpError(422, { detail: errors });
|
|
5954
|
-
if (!state.users.has(id)) notFound3("User not found");
|
|
6989
|
+
if (!state.users.has(id)) notFound3(state, id, "User not found");
|
|
5955
6990
|
const existing = state.userInfo.get(id) ?? {};
|
|
5956
6991
|
const rawAddress = typeof body.address === "object" && body.address !== null && !Array.isArray(body.address) ? body.address : void 0;
|
|
5957
6992
|
const info = {
|
|
@@ -6004,460 +7039,187 @@ var userHandlers = (state) => ({
|
|
|
6004
7039
|
const user2 = state.users.get(existing.user_id);
|
|
6005
7040
|
throw new HttpError(400, {
|
|
6006
7041
|
detail: {
|
|
6007
|
-
error_type: "INVALID_REQUEST",
|
|
6008
|
-
error_message: "Client user id already exists.",
|
|
6009
|
-
user_id: existing.user_id,
|
|
6010
|
-
created_on: user2?.created_on ?? state.isoNow(context.now)
|
|
6011
|
-
}
|
|
6012
|
-
});
|
|
6013
|
-
}
|
|
6014
|
-
const userId = state.nextUserId();
|
|
6015
|
-
const createdOn = state.isoNow(context.now);
|
|
6016
|
-
const tz = typeof body.fallback_time_zone === "string" ? { id: body.fallback_time_zone, source_slug: "manual", updated_at: createdOn } : null;
|
|
6017
|
-
const user = {
|
|
6018
|
-
user_id: userId,
|
|
6019
|
-
team_id: MOCK_TEAM_ID,
|
|
6020
|
-
client_user_id: clientUserId,
|
|
6021
|
-
created_on: createdOn,
|
|
6022
|
-
connected_sources: [],
|
|
6023
|
-
fallback_time_zone: tz,
|
|
6024
|
-
fallback_birth_date: null,
|
|
6025
|
-
ingestion_start: null,
|
|
6026
|
-
ingestion_end: null
|
|
6027
|
-
};
|
|
6028
|
-
state.users.insert(userId, user);
|
|
6029
|
-
state.byClientId.insert(clientUserId, { user_id: userId });
|
|
6030
|
-
return jsonRes(200, render(user));
|
|
6031
|
-
},
|
|
6032
|
-
get_user_v2_user__user_id__get: async (context) => {
|
|
6033
|
-
const id = context.params.user_id ?? "";
|
|
6034
|
-
if (!isValidUuid(id)) {
|
|
6035
|
-
throw new HttpError(422, {
|
|
6036
|
-
detail: `Invalid format for parameter user_id: error unmarshaling '${id}' text as *uuid.UUID: invalid UUID length: ${id.length}`
|
|
6037
|
-
});
|
|
6038
|
-
}
|
|
6039
|
-
const user = state.users.get(id);
|
|
6040
|
-
if (user) return jsonRes(200, render(user));
|
|
6041
|
-
if (state.deletedUsers.has(id)) {
|
|
6042
|
-
throw new HttpError(404, { detail: "You have scheduled this user for deletion." });
|
|
6043
|
-
}
|
|
6044
|
-
notFound3("Not found");
|
|
6045
|
-
},
|
|
6046
|
-
delete_user_v2_user__user_id__delete: async (context) => {
|
|
6047
|
-
const id = context.params.user_id ?? "";
|
|
6048
|
-
const user = state.users.get(id);
|
|
6049
|
-
if (!user) {
|
|
6050
|
-
if (state.deletedUsers.has(id)) {
|
|
6051
|
-
throw new HttpError(404, {
|
|
6052
|
-
detail: "The user has been scheduled for deletion as per your previous request"
|
|
6053
|
-
});
|
|
6054
|
-
}
|
|
6055
|
-
notFound3("The user does not or no longer exists in this team");
|
|
6056
|
-
}
|
|
6057
|
-
state.users.delete(id);
|
|
6058
|
-
state.byClientId.delete(user.client_user_id);
|
|
6059
|
-
state.deletedUsers.insert(id, { user_id: id });
|
|
6060
|
-
return jsonRes(200, { success: true });
|
|
6061
|
-
},
|
|
6062
|
-
get_user_by_client_user_id_v2_user_resolve__client_user_id__get: async (context) => {
|
|
6063
|
-
const clientUserId = context.params.client_user_id ?? "";
|
|
6064
|
-
const binding = state.byClientId.get(clientUserId);
|
|
6065
|
-
if (!binding) notFound3("User not found");
|
|
6066
|
-
const user = state.users.get(binding.user_id);
|
|
6067
|
-
if (!user) notFound3("User not found");
|
|
6068
|
-
return jsonRes(200, render(user));
|
|
6069
|
-
},
|
|
6070
|
-
patch_user_v2_user__user_id__patch: async (context) => {
|
|
6071
|
-
const id = context.params.user_id ?? "";
|
|
6072
|
-
const user = state.users.get(id);
|
|
6073
|
-
if (!user) {
|
|
6074
|
-
if (state.deletedUsers.has(id)) {
|
|
6075
|
-
throw new HttpError(404, {
|
|
6076
|
-
detail: "The user has been scheduled for deletion as per your previous request"
|
|
6077
|
-
});
|
|
6078
|
-
}
|
|
6079
|
-
notFound3("The user does not or no longer exists in this team");
|
|
6080
|
-
}
|
|
6081
|
-
const body = jsonBody(context);
|
|
6082
|
-
const now = state.isoNow(context.now);
|
|
6083
|
-
const patchable = [
|
|
6084
|
-
"client_user_id",
|
|
6085
|
-
"fallback_time_zone",
|
|
6086
|
-
"fallback_birth_date",
|
|
6087
|
-
"ingestion_start",
|
|
6088
|
-
"ingestion_end"
|
|
6089
|
-
];
|
|
6090
|
-
if (!patchable.some((key) => body[key] !== void 0)) {
|
|
6091
|
-
throw new HttpError(400, { detail: "Nothing to patch" });
|
|
6092
|
-
}
|
|
6093
|
-
const validationError = () => {
|
|
6094
|
-
const tz = body.fallback_time_zone;
|
|
6095
|
-
if (tz !== void 0 && tz !== null) {
|
|
6096
|
-
if (typeof tz !== "string") return stringError("fallback_time_zone", tz);
|
|
6097
|
-
if (!isValidIanaTimezone(tz)) {
|
|
6098
|
-
return {
|
|
6099
|
-
type: "value_error",
|
|
6100
|
-
loc: ["body", "fallback_time_zone"],
|
|
6101
|
-
msg: `Value error, Invalid IANA time zone: ${tz}`,
|
|
6102
|
-
input: tz,
|
|
6103
|
-
ctx: { error: {} }
|
|
6104
|
-
};
|
|
6105
|
-
}
|
|
6106
|
-
}
|
|
6107
|
-
const birth = body.fallback_birth_date;
|
|
6108
|
-
if (birth !== void 0 && birth !== null) {
|
|
6109
|
-
if (typeof birth !== "string") return stringError("fallback_birth_date", birth);
|
|
6110
|
-
if (!isValidDate(birth)) return dateError("fallback_birth_date", birth);
|
|
6111
|
-
}
|
|
6112
|
-
const start = body.ingestion_start;
|
|
6113
|
-
if (start !== void 0 && start !== null) {
|
|
6114
|
-
if (typeof start !== "string") return stringError("ingestion_start", start);
|
|
6115
|
-
if (!isValidDate(start)) return dateError("ingestion_start", start);
|
|
6116
|
-
}
|
|
6117
|
-
const end = body.ingestion_end;
|
|
6118
|
-
if (end !== void 0 && end !== null) {
|
|
6119
|
-
if (typeof end !== "string") return stringError("ingestion_end", end);
|
|
6120
|
-
if (!isValidDate(end)) return dateError("ingestion_end", end);
|
|
6121
|
-
}
|
|
6122
|
-
const cid = body.client_user_id;
|
|
6123
|
-
if (cid !== void 0) {
|
|
6124
|
-
if (cid === null) {
|
|
6125
|
-
return {
|
|
6126
|
-
type: "value_error",
|
|
6127
|
-
loc: ["body"],
|
|
6128
|
-
msg: "Value error, client_user_id is not a field that can be reset to null.",
|
|
6129
|
-
input: body,
|
|
6130
|
-
ctx: { error: {} }
|
|
6131
|
-
};
|
|
6132
|
-
}
|
|
6133
|
-
if (typeof cid !== "string") return stringError("client_user_id", cid);
|
|
6134
|
-
}
|
|
6135
|
-
return void 0;
|
|
6136
|
-
};
|
|
6137
|
-
const error = validationError();
|
|
6138
|
-
if (error) throw new HttpError(422, { detail: [error] });
|
|
6139
|
-
if (body.client_user_id !== void 0) {
|
|
6140
|
-
const raw = body.client_user_id;
|
|
6141
|
-
const taken = state.byClientId.get(raw);
|
|
6142
|
-
if (taken && taken.user_id !== id)
|
|
6143
|
-
throw new HttpError(409, { detail: "Client user id already exists" });
|
|
6144
|
-
state.byClientId.delete(user.client_user_id);
|
|
6145
|
-
state.byClientId.insert(raw, { user_id: id });
|
|
6146
|
-
user.client_user_id = raw;
|
|
6147
|
-
}
|
|
6148
|
-
if (body.fallback_time_zone !== void 0) {
|
|
6149
|
-
const raw = body.fallback_time_zone;
|
|
6150
|
-
user.fallback_time_zone = typeof raw === "string" ? { id: raw, source_slug: "manual", updated_at: now } : null;
|
|
6151
|
-
}
|
|
6152
|
-
if (body.fallback_birth_date !== void 0) {
|
|
6153
|
-
const raw = body.fallback_birth_date;
|
|
6154
|
-
user.fallback_birth_date = typeof raw === "string" ? { value: raw, source_slug: "manual", updated_at: now } : null;
|
|
6155
|
-
}
|
|
6156
|
-
const startProvided = body.ingestion_start !== void 0;
|
|
6157
|
-
const endProvided = body.ingestion_end !== void 0;
|
|
6158
|
-
if (startProvided) {
|
|
6159
|
-
const raw = body.ingestion_start;
|
|
6160
|
-
user.ingestion_start = typeof raw === "string" ? raw : null;
|
|
6161
|
-
}
|
|
6162
|
-
if (endProvided) {
|
|
6163
|
-
const rawEnd = body.ingestion_end;
|
|
6164
|
-
user.ingestion_end = typeof rawEnd === "string" ? rawEnd : null;
|
|
7042
|
+
error_type: "INVALID_REQUEST",
|
|
7043
|
+
error_message: "Client user id already exists.",
|
|
7044
|
+
user_id: existing.user_id,
|
|
7045
|
+
created_on: user2?.created_on ?? state.isoNow(context.now)
|
|
7046
|
+
}
|
|
7047
|
+
});
|
|
6165
7048
|
}
|
|
6166
|
-
state.users.
|
|
6167
|
-
|
|
7049
|
+
checkUserQuota(state.limits, state.users.count());
|
|
7050
|
+
const userId = state.nextUserId();
|
|
7051
|
+
const createdOn = state.isoNow(context.now);
|
|
7052
|
+
const tz = typeof body.fallback_time_zone === "string" ? { id: body.fallback_time_zone, source_slug: "manual", updated_at: createdOn } : null;
|
|
7053
|
+
const user = {
|
|
7054
|
+
user_id: userId,
|
|
7055
|
+
team_id: state.teamId,
|
|
7056
|
+
client_user_id: clientUserId,
|
|
7057
|
+
created_on: createdOn,
|
|
7058
|
+
connected_sources: [],
|
|
7059
|
+
fallback_time_zone: tz,
|
|
7060
|
+
fallback_birth_date: null,
|
|
7061
|
+
ingestion_start: null,
|
|
7062
|
+
ingestion_end: null
|
|
7063
|
+
};
|
|
7064
|
+
state.users.insert(userId, user);
|
|
7065
|
+
state.byClientId.insert(clientUserId, { user_id: userId });
|
|
7066
|
+
return jsonRes(200, render(user));
|
|
6168
7067
|
},
|
|
6169
|
-
|
|
7068
|
+
get_user_v2_user__user_id__get: async (context) => {
|
|
6170
7069
|
const id = context.params.user_id ?? "";
|
|
6171
7070
|
if (!isValidUuid(id)) {
|
|
6172
7071
|
throw new HttpError(422, {
|
|
6173
7072
|
detail: `Invalid format for parameter user_id: error unmarshaling '${id}' text as *uuid.UUID: invalid UUID length: ${id.length}`
|
|
6174
7073
|
});
|
|
6175
7074
|
}
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
if (
|
|
6179
|
-
|
|
6180
|
-
},
|
|
6181
|
-
get_teams_users_v2_user_get: async (context) => {
|
|
6182
|
-
const offset = queryInt2(context, "offset", 0);
|
|
6183
|
-
const limit = queryInt2(context, "limit", 100);
|
|
6184
|
-
if (offset < 0 || limit < 0 || limit > 500) {
|
|
6185
|
-
throw new HttpError(500, "Internal Server Error", { "content-type": "text/plain" });
|
|
7075
|
+
const user = state.users.get(id);
|
|
7076
|
+
if (user) return jsonRes(200, render(user));
|
|
7077
|
+
if (state.deletedUsers.has(id)) {
|
|
7078
|
+
throw new HttpError(404, { detail: "You have scheduled this user for deletion." });
|
|
6186
7079
|
}
|
|
6187
|
-
|
|
6188
|
-
}
|
|
6189
|
-
});
|
|
6190
|
-
|
|
6191
|
-
// src/admin.ts
|
|
6192
|
-
var ORDER_STATUSES_BY_METHOD = {
|
|
6193
|
-
at_home_phlebotomy: [
|
|
6194
|
-
"received.ordered",
|
|
6195
|
-
"received.requisition_created",
|
|
6196
|
-
"received.requisition_bypassed",
|
|
6197
|
-
"collecting_sample.appointment_pending",
|
|
6198
|
-
"collecting_sample.appointment_scheduled",
|
|
6199
|
-
"collecting_sample.appointment_cancelled",
|
|
6200
|
-
"collecting_sample.draw_completed",
|
|
6201
|
-
"sample_with_lab.partial_results",
|
|
6202
|
-
"completed.completed",
|
|
6203
|
-
"completed.corrected",
|
|
6204
|
-
"cancelled.cancelled",
|
|
6205
|
-
"failed.sample_error"
|
|
6206
|
-
],
|
|
6207
|
-
on_site_collection: [
|
|
6208
|
-
"received.ordered",
|
|
6209
|
-
"received.requisition_created",
|
|
6210
|
-
"received.requisition_bypassed",
|
|
6211
|
-
"sample_with_lab.draw_completed",
|
|
6212
|
-
"sample_with_lab.partial_results",
|
|
6213
|
-
"completed.completed",
|
|
6214
|
-
"completed.corrected",
|
|
6215
|
-
"cancelled.cancelled",
|
|
6216
|
-
"failed.sample_error"
|
|
6217
|
-
],
|
|
6218
|
-
testkit: [
|
|
6219
|
-
"received.ordered",
|
|
6220
|
-
"received.awaiting_registration",
|
|
6221
|
-
"received.registered",
|
|
6222
|
-
"received.requisition_created",
|
|
6223
|
-
"received.requisition_bypassed",
|
|
6224
|
-
"collecting_sample.transit_customer",
|
|
6225
|
-
"collecting_sample.out_for_delivery",
|
|
6226
|
-
"collecting_sample.with_customer",
|
|
6227
|
-
"collecting_sample.transit_lab",
|
|
6228
|
-
"collecting_sample.problem_in_transit_customer",
|
|
6229
|
-
"collecting_sample.problem_in_transit_lab",
|
|
6230
|
-
"sample_with_lab.delivered_to_lab",
|
|
6231
|
-
"sample_with_lab.lab_processing_blocked",
|
|
6232
|
-
"completed.completed",
|
|
6233
|
-
"completed.corrected",
|
|
6234
|
-
"cancelled.cancelled",
|
|
6235
|
-
"cancelled.do_not_process",
|
|
6236
|
-
"failed.sample_error",
|
|
6237
|
-
"failed.failure_to_deliver_to_customer",
|
|
6238
|
-
"failed.failure_to_deliver_to_lab",
|
|
6239
|
-
"failed.lost"
|
|
6240
|
-
],
|
|
6241
|
-
walk_in_test: [
|
|
6242
|
-
"received.ordered",
|
|
6243
|
-
"received.requisition_created",
|
|
6244
|
-
"received.requisition_bypassed",
|
|
6245
|
-
"collecting_sample.appointment_pending",
|
|
6246
|
-
"collecting_sample.appointment_scheduled",
|
|
6247
|
-
"collecting_sample.appointment_cancelled",
|
|
6248
|
-
"collecting_sample.redraw_available",
|
|
6249
|
-
"sample_with_lab.partial_results",
|
|
6250
|
-
"completed.completed",
|
|
6251
|
-
"completed.corrected",
|
|
6252
|
-
"cancelled.cancelled",
|
|
6253
|
-
"failed.sample_error"
|
|
6254
|
-
]
|
|
6255
|
-
};
|
|
6256
|
-
var TRANSITION_ALIASES = {
|
|
6257
|
-
at_home_phlebotomy: {
|
|
6258
|
-
requisition_created: "received.requisition_created",
|
|
6259
|
-
scheduled: "collecting_sample.appointment_scheduled",
|
|
6260
|
-
collected: "collecting_sample.draw_completed",
|
|
6261
|
-
partial_results: "sample_with_lab.partial_results",
|
|
6262
|
-
completed: "completed.completed",
|
|
6263
|
-
corrected: "completed.corrected",
|
|
6264
|
-
cancelled: "cancelled.cancelled",
|
|
6265
|
-
failed: "failed.sample_error"
|
|
6266
|
-
},
|
|
6267
|
-
on_site_collection: {
|
|
6268
|
-
requisition_created: "received.requisition_created",
|
|
6269
|
-
collected: "sample_with_lab.draw_completed",
|
|
6270
|
-
at_lab: "sample_with_lab.draw_completed",
|
|
6271
|
-
partial_results: "sample_with_lab.partial_results",
|
|
6272
|
-
completed: "completed.completed",
|
|
6273
|
-
corrected: "completed.corrected",
|
|
6274
|
-
cancelled: "cancelled.cancelled",
|
|
6275
|
-
failed: "failed.sample_error"
|
|
6276
|
-
},
|
|
6277
|
-
testkit: {
|
|
6278
|
-
requisition_created: "received.requisition_created",
|
|
6279
|
-
shipped: "collecting_sample.transit_customer",
|
|
6280
|
-
delivered: "collecting_sample.with_customer",
|
|
6281
|
-
collected: "collecting_sample.transit_lab",
|
|
6282
|
-
at_lab: "sample_with_lab.delivered_to_lab",
|
|
6283
|
-
completed: "completed.completed",
|
|
6284
|
-
corrected: "completed.corrected",
|
|
6285
|
-
cancelled: "cancelled.cancelled",
|
|
6286
|
-
failed: "failed.sample_error"
|
|
7080
|
+
notFound3(state, id, "Not found");
|
|
6287
7081
|
},
|
|
6288
|
-
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
}
|
|
6297
|
-
};
|
|
6298
|
-
var RESULT_FIXTURES = {
|
|
6299
|
-
normal: { interpretation: "normal" },
|
|
6300
|
-
abnormal: { interpretation: "abnormal" },
|
|
6301
|
-
critical: { interpretation: "critical" },
|
|
6302
|
-
missing_results: { interpretation: "normal", has_missing_results: true }
|
|
6303
|
-
};
|
|
6304
|
-
var FAULT_PRESETS = {
|
|
6305
|
-
sandbox_user_quota: {
|
|
6306
|
-
operationId: "create_user_v2_user_post",
|
|
6307
|
-
status: 400,
|
|
6308
|
-
body: {
|
|
6309
|
-
detail: {
|
|
6310
|
-
error_type: "INVALID_REQUEST",
|
|
6311
|
-
error_message: "You have reached the maximum of 50 Sandbox users"
|
|
7082
|
+
delete_user_v2_user__user_id__delete: async (context) => {
|
|
7083
|
+
const id = context.params.user_id ?? "";
|
|
7084
|
+
const user = state.users.get(id);
|
|
7085
|
+
if (!user) {
|
|
7086
|
+
if (state.deletedUsers.has(id)) {
|
|
7087
|
+
throw new HttpError(404, {
|
|
7088
|
+
detail: "The user has been scheduled for deletion as per your previous request"
|
|
7089
|
+
});
|
|
6312
7090
|
}
|
|
7091
|
+
notFound3(state, id, "The user does not or no longer exists in this team");
|
|
6313
7092
|
}
|
|
7093
|
+
state.users.delete(id);
|
|
7094
|
+
state.byClientId.delete(user.client_user_id);
|
|
7095
|
+
state.deletedUsers.insert(id, { user_id: id });
|
|
7096
|
+
return jsonRes(200, { success: true });
|
|
6314
7097
|
},
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
|
|
6318
|
-
|
|
7098
|
+
get_user_by_client_user_id_v2_user_resolve__client_user_id__get: async (context) => {
|
|
7099
|
+
const clientUserId = context.params.client_user_id ?? "";
|
|
7100
|
+
const binding = state.byClientId.get(clientUserId) ?? notFound3(state, `client:${clientUserId}`, "User not found");
|
|
7101
|
+
const user = state.users.get(binding.user_id) ?? notFound3(state, binding.user_id, "User not found");
|
|
7102
|
+
return jsonRes(200, render(user));
|
|
6319
7103
|
},
|
|
6320
|
-
|
|
6321
|
-
|
|
6322
|
-
|
|
6323
|
-
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
|
|
6327
|
-
|
|
6328
|
-
const alias = TRANSITION_ALIASES[method]?.[target];
|
|
6329
|
-
const short = alias ?? (target.split(".").length === 3 ? null : target);
|
|
6330
|
-
if (short !== null && allowed.includes(short)) {
|
|
6331
|
-
const [phase, event] = short.split(".");
|
|
6332
|
-
return { status: `${phase}.${method}.${event}` };
|
|
6333
|
-
}
|
|
6334
|
-
if (target.split(".").length === 3) {
|
|
6335
|
-
const [phase, targetMethod, event] = target.split(".");
|
|
6336
|
-
if (targetMethod === method && allowed.includes(`${phase}.${event}`)) return { status: target };
|
|
6337
|
-
}
|
|
6338
|
-
const names = Object.keys(TRANSITION_ALIASES[method] ?? {});
|
|
6339
|
-
return {
|
|
6340
|
-
error: `${JSON.stringify(target)} is not a ${method} status. Use one of: ${names.join(", ")}, or a full status such as ${allowed.slice(0, 2).map((s) => `${s.split(".")[0]}.${method}.${s.split(".")[1]}`).join(", ")}`
|
|
6341
|
-
};
|
|
6342
|
-
};
|
|
6343
|
-
var adminError2 = (status, message) => jsonRes(status, { error: { type: "mockingbird_admin", message } });
|
|
6344
|
-
var isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6345
|
-
var junctionAdminRoutes = (options) => (runtime) => {
|
|
6346
|
-
const api = (request2) => runtime.instance(request2.namespace);
|
|
6347
|
-
return {
|
|
6348
|
-
"GET /orders": (request2) => jsonRes(200, {
|
|
6349
|
-
orders: api(request2).orders().map((order) => ({
|
|
6350
|
-
id: order.id,
|
|
6351
|
-
user_id: order.user_id,
|
|
6352
|
-
method: methodOf(order),
|
|
6353
|
-
status: order.last_event.status,
|
|
6354
|
-
updated_at: order.updated_at
|
|
6355
|
-
}))
|
|
6356
|
-
}),
|
|
6357
|
-
"POST /orders/:id/transition": (request2) => {
|
|
6358
|
-
const body = isRecord4(request2.body) ? request2.body : {};
|
|
6359
|
-
const order = api(request2).order(request2.params.id);
|
|
6360
|
-
if (!order) return adminError2(404, `no order ${request2.params.id} in ${request2.namespace}`);
|
|
6361
|
-
if (typeof body.to !== "string") {
|
|
6362
|
-
return adminError2(400, 'body needs "to": a status like "completed" or "at_lab"');
|
|
7104
|
+
patch_user_v2_user__user_id__patch: async (context) => {
|
|
7105
|
+
const id = context.params.user_id ?? "";
|
|
7106
|
+
const user = state.users.get(id);
|
|
7107
|
+
if (!user) {
|
|
7108
|
+
if (state.deletedUsers.has(id)) {
|
|
7109
|
+
throw new HttpError(404, {
|
|
7110
|
+
detail: "The user has been scheduled for deletion as per your previous request"
|
|
7111
|
+
});
|
|
6363
7112
|
}
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
6374
|
-
|
|
7113
|
+
notFound3(state, id, "The user does not or no longer exists in this team");
|
|
7114
|
+
}
|
|
7115
|
+
const body = jsonBody(context);
|
|
7116
|
+
const now = state.isoNow(context.now);
|
|
7117
|
+
const patchable = [
|
|
7118
|
+
"client_user_id",
|
|
7119
|
+
"fallback_time_zone",
|
|
7120
|
+
"fallback_birth_date",
|
|
7121
|
+
"ingestion_start",
|
|
7122
|
+
"ingestion_end"
|
|
7123
|
+
];
|
|
7124
|
+
if (!patchable.some((key) => body[key] !== void 0)) {
|
|
7125
|
+
throw new HttpError(400, { detail: "Nothing to patch" });
|
|
7126
|
+
}
|
|
7127
|
+
const validationError = () => {
|
|
7128
|
+
const tz = body.fallback_time_zone;
|
|
7129
|
+
if (tz !== void 0 && tz !== null) {
|
|
7130
|
+
if (typeof tz !== "string") return stringError("fallback_time_zone", tz);
|
|
7131
|
+
if (!isValidIanaTimezone(tz)) {
|
|
7132
|
+
return {
|
|
7133
|
+
type: "value_error",
|
|
7134
|
+
loc: ["body", "fallback_time_zone"],
|
|
7135
|
+
msg: `Value error, Invalid IANA time zone: ${tz}`,
|
|
7136
|
+
input: tz,
|
|
7137
|
+
ctx: { error: {} }
|
|
7138
|
+
};
|
|
6375
7139
|
}
|
|
6376
|
-
flags = { ...named, ...flags };
|
|
6377
|
-
}
|
|
6378
|
-
const updated = api(request2).transitionOrder(order.id, resolved.status, {
|
|
6379
|
-
now: runtime.clock.now,
|
|
6380
|
-
flags
|
|
6381
|
-
});
|
|
6382
|
-
return jsonRes(200, {
|
|
6383
|
-
id: order.id,
|
|
6384
|
-
status: updated?.last_event.status,
|
|
6385
|
-
events: updated?.events
|
|
6386
|
-
});
|
|
6387
|
-
},
|
|
6388
|
-
"GET /result-fixtures": () => jsonRes(200, { fixtures: RESULT_FIXTURES }),
|
|
6389
|
-
"GET /results/:id": (request2) => {
|
|
6390
|
-
const fixture = api(request2).resultFixture(request2.params.id);
|
|
6391
|
-
return fixture ? jsonRes(200, fixture) : adminError2(404, "no result fixture for that order");
|
|
6392
|
-
},
|
|
6393
|
-
"PUT /results/:id": (request2) => {
|
|
6394
|
-
if (!isRecord4(request2.body)) return adminError2(400, "expected a result fixture object");
|
|
6395
|
-
const fixture = { name: "custom", ...request2.body };
|
|
6396
|
-
if (fixture.results !== void 0 && !Array.isArray(fixture.results)) {
|
|
6397
|
-
return adminError2(400, "results must be an array of result lines");
|
|
6398
7140
|
}
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
const body = isRecord4(request2.body) ? request2.body : {};
|
|
6404
|
-
if (body.accounts !== null && !Array.isArray(body.accounts)) {
|
|
6405
|
-
return adminError2(400, 'body needs "accounts": an array, or null to restore the default');
|
|
7141
|
+
const birth = body.fallback_birth_date;
|
|
7142
|
+
if (birth !== void 0 && birth !== null) {
|
|
7143
|
+
if (typeof birth !== "string") return stringError("fallback_birth_date", birth);
|
|
7144
|
+
if (!isValidDate(birth)) return dateError("fallback_birth_date", birth);
|
|
6406
7145
|
}
|
|
6407
|
-
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
|
|
6411
|
-
return adminError2(400, error instanceof Error ? error.message : String(error));
|
|
7146
|
+
const start = body.ingestion_start;
|
|
7147
|
+
if (start !== void 0 && start !== null) {
|
|
7148
|
+
if (typeof start !== "string") return stringError("ingestion_start", start);
|
|
7149
|
+
if (!isValidDate(start)) return dateError("ingestion_start", start);
|
|
6412
7150
|
}
|
|
6413
|
-
|
|
6414
|
-
|
|
6415
|
-
|
|
6416
|
-
|
|
6417
|
-
}),
|
|
6418
|
-
"PUT /geo": (request2) => {
|
|
6419
|
-
const mode = isRecord4(request2.body) ? request2.body.mode : void 0;
|
|
6420
|
-
if (mode !== "corpus" && mode !== "synthetic") {
|
|
6421
|
-
return adminError2(400, 'body needs "mode": "corpus" or "synthetic"');
|
|
7151
|
+
const end = body.ingestion_end;
|
|
7152
|
+
if (end !== void 0 && end !== null) {
|
|
7153
|
+
if (typeof end !== "string") return stringError("ingestion_end", end);
|
|
7154
|
+
if (!isValidDate(end)) return dateError("ingestion_end", end);
|
|
6422
7155
|
}
|
|
6423
|
-
|
|
6424
|
-
|
|
6425
|
-
|
|
6426
|
-
|
|
6427
|
-
|
|
6428
|
-
|
|
6429
|
-
|
|
6430
|
-
|
|
6431
|
-
|
|
6432
|
-
|
|
6433
|
-
|
|
6434
|
-
|
|
6435
|
-
},
|
|
6436
|
-
"POST /webhooks/flush": async () => {
|
|
6437
|
-
if (!options.webhooks) return adminError2(409, "webhook delivery is off");
|
|
6438
|
-
await options.webhooks.flush();
|
|
6439
|
-
return jsonRes(200, { status: "ok" });
|
|
6440
|
-
},
|
|
6441
|
-
"GET /faults/presets": () => jsonRes(200, { presets: FAULT_PRESETS }),
|
|
6442
|
-
"POST /faults/presets/:name": (request2) => {
|
|
6443
|
-
const preset = FAULT_PRESETS[request2.params.name];
|
|
6444
|
-
if (!preset) {
|
|
6445
|
-
return adminError2(
|
|
6446
|
-
404,
|
|
6447
|
-
`no preset ${request2.params.name}; one of ${Object.keys(FAULT_PRESETS).join(", ")}`
|
|
6448
|
-
);
|
|
7156
|
+
const cid = body.client_user_id;
|
|
7157
|
+
if (cid !== void 0) {
|
|
7158
|
+
if (cid === null) {
|
|
7159
|
+
return {
|
|
7160
|
+
type: "value_error",
|
|
7161
|
+
loc: ["body"],
|
|
7162
|
+
msg: "Value error, client_user_id is not a field that can be reset to null.",
|
|
7163
|
+
input: body,
|
|
7164
|
+
ctx: { error: {} }
|
|
7165
|
+
};
|
|
7166
|
+
}
|
|
7167
|
+
if (typeof cid !== "string") return stringError("client_user_id", cid);
|
|
6449
7168
|
}
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
7169
|
+
return void 0;
|
|
7170
|
+
};
|
|
7171
|
+
const error = validationError();
|
|
7172
|
+
if (error) throw new HttpError(422, { detail: [error] });
|
|
7173
|
+
if (body.client_user_id !== void 0) {
|
|
7174
|
+
const raw = body.client_user_id;
|
|
7175
|
+
const taken = state.byClientId.get(raw);
|
|
7176
|
+
if (taken && taken.user_id !== id)
|
|
7177
|
+
throw new HttpError(409, { detail: "Client user id already exists" });
|
|
7178
|
+
state.byClientId.delete(user.client_user_id);
|
|
7179
|
+
state.byClientId.insert(raw, { user_id: id });
|
|
7180
|
+
user.client_user_id = raw;
|
|
7181
|
+
}
|
|
7182
|
+
if (body.fallback_time_zone !== void 0) {
|
|
7183
|
+
const raw = body.fallback_time_zone;
|
|
7184
|
+
user.fallback_time_zone = typeof raw === "string" ? { id: raw, source_slug: "manual", updated_at: now } : null;
|
|
7185
|
+
}
|
|
7186
|
+
if (body.fallback_birth_date !== void 0) {
|
|
7187
|
+
const raw = body.fallback_birth_date;
|
|
7188
|
+
user.fallback_birth_date = typeof raw === "string" ? { value: raw, source_slug: "manual", updated_at: now } : null;
|
|
7189
|
+
}
|
|
7190
|
+
const startProvided = body.ingestion_start !== void 0;
|
|
7191
|
+
const endProvided = body.ingestion_end !== void 0;
|
|
7192
|
+
if (startProvided) {
|
|
7193
|
+
const raw = body.ingestion_start;
|
|
7194
|
+
user.ingestion_start = typeof raw === "string" ? raw : null;
|
|
7195
|
+
}
|
|
7196
|
+
if (endProvided) {
|
|
7197
|
+
const rawEnd = body.ingestion_end;
|
|
7198
|
+
user.ingestion_end = typeof rawEnd === "string" ? rawEnd : null;
|
|
7199
|
+
}
|
|
7200
|
+
state.users.update(id, user);
|
|
7201
|
+
return new Response(null, { status: 204 });
|
|
7202
|
+
},
|
|
7203
|
+
get_latest_user_info_user_v2_user__user_id__info_latest_get: async (context) => {
|
|
7204
|
+
const id = context.params.user_id ?? "";
|
|
7205
|
+
if (!isValidUuid(id)) {
|
|
7206
|
+
throw new HttpError(422, {
|
|
7207
|
+
detail: `Invalid format for parameter user_id: error unmarshaling '${id}' text as *uuid.UUID: invalid UUID length: ${id.length}`
|
|
6456
7208
|
});
|
|
6457
|
-
return jsonRes(201, rule);
|
|
6458
7209
|
}
|
|
6459
|
-
|
|
6460
|
-
|
|
7210
|
+
if (!state.users.has(id) && !state.deletedUsers.has(id)) notFound3(state, id, "User not found");
|
|
7211
|
+
const info = state.userInfo.get(id) ?? notFound3(state, id, "User demographics data not found");
|
|
7212
|
+
return jsonRes(200, info);
|
|
7213
|
+
},
|
|
7214
|
+
get_teams_users_v2_user_get: async (context) => {
|
|
7215
|
+
const offset = queryInt2(context, "offset", 0);
|
|
7216
|
+
const limit = queryInt2(context, "limit", 100);
|
|
7217
|
+
if (offset < 0 || limit < 0 || limit > 500) {
|
|
7218
|
+
throw new HttpError(500, "Internal Server Error", { "content-type": "text/plain" });
|
|
7219
|
+
}
|
|
7220
|
+
return jsonRes(200, listUsers(state, offset, limit));
|
|
7221
|
+
}
|
|
7222
|
+
});
|
|
6461
7223
|
|
|
6462
7224
|
// src/coverage-corpus.ts
|
|
6463
7225
|
var PSC_AVAILABILITY_ZIPS = [
|
|
@@ -6899,8 +7661,6 @@ var recordSandboxCorpus = async (args) => {
|
|
|
6899
7661
|
|
|
6900
7662
|
// src/corpus-tools.ts
|
|
6901
7663
|
var DEFAULT_JUNCTION_BASE_URL = "https://api.sandbox.tryvital.io";
|
|
6902
|
-
var SANDBOX_KEY_PREFIXES = ["sk_us_", "sk_eu_"];
|
|
6903
|
-
var isSandboxKey = (key) => SANDBOX_KEY_PREFIXES.some((prefix) => key.startsWith(prefix));
|
|
6904
7664
|
var asRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
6905
7665
|
var listOf = (body) => {
|
|
6906
7666
|
const items = Array.isArray(body) ? body : asRecord2(body)?.data;
|
|
@@ -6917,11 +7677,32 @@ var fingerprintCorpus = async (corpus) => {
|
|
|
6917
7677
|
const content = canonicalJson({
|
|
6918
7678
|
observations: corpus.observations,
|
|
6919
7679
|
catalog: corpus.catalog,
|
|
6920
|
-
labAccounts: corpus.labAccounts
|
|
7680
|
+
labAccounts: corpus.labAccounts,
|
|
7681
|
+
// Absent from version-1 corpora, whose fingerprints stay what they were.
|
|
7682
|
+
...corpus.teamId !== void 0 ? { teamId: corpus.teamId } : {}
|
|
6921
7683
|
});
|
|
6922
7684
|
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(content));
|
|
6923
7685
|
return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
6924
7686
|
};
|
|
7687
|
+
var UUID2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
7688
|
+
var readTeamId = async (real, labAccounts) => {
|
|
7689
|
+
const headers = { ...await real.headers(), accept: "application/json" };
|
|
7690
|
+
const response = await real.fetch(new Request(`${real.baseUrl}/v2/user?offset=0&limit=1`, { headers })).catch(() => void 0);
|
|
7691
|
+
if (response?.ok) {
|
|
7692
|
+
const body = asRecord2(await response.json().catch(() => void 0));
|
|
7693
|
+
const first = Array.isArray(body?.users) ? asRecord2(body.users[0]) : void 0;
|
|
7694
|
+
if (typeof first?.team_id === "string" && UUID2.test(first.team_id)) return first.team_id;
|
|
7695
|
+
}
|
|
7696
|
+
const named = /* @__PURE__ */ new Set();
|
|
7697
|
+
for (const account2 of labAccounts) {
|
|
7698
|
+
const allowlist = account2.team_id_allowlist;
|
|
7699
|
+
if (!Array.isArray(allowlist) || allowlist.length === 0) continue;
|
|
7700
|
+
const ids = allowlist.filter((id) => typeof id === "string");
|
|
7701
|
+
if (named.size === 0) for (const id of ids) named.add(id);
|
|
7702
|
+
else for (const id of [...named]) if (!ids.includes(id)) named.delete(id);
|
|
7703
|
+
}
|
|
7704
|
+
return named.size === 1 ? [...named][0] : void 0;
|
|
7705
|
+
};
|
|
6925
7706
|
var pullCorpus = async (options) => {
|
|
6926
7707
|
const baseUrl = (options.baseUrl ?? DEFAULT_JUNCTION_BASE_URL).replace(/\/$/, "");
|
|
6927
7708
|
const send = options.fetch ?? ((request2) => fetch(request2));
|
|
@@ -6973,10 +7754,12 @@ var pullCorpus = async (options) => {
|
|
|
6973
7754
|
([a], [b]) => a < b ? -1 : a > b ? 1 : 0
|
|
6974
7755
|
)
|
|
6975
7756
|
);
|
|
7757
|
+
const teamId = await readTeamId(real, labAccounts) ?? options.base?.teamId;
|
|
6976
7758
|
const corpus = {
|
|
6977
7759
|
version: SEALED_CORPUS_VERSION,
|
|
6978
7760
|
recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6979
7761
|
source: baseUrl,
|
|
7762
|
+
...teamId !== void 0 ? { teamId } : {},
|
|
6980
7763
|
observations,
|
|
6981
7764
|
catalog,
|
|
6982
7765
|
labAccounts
|
|
@@ -7022,8 +7805,10 @@ var diffCorpus = (before, after) => {
|
|
|
7022
7805
|
removed: [...beforeZips].filter((zip) => !afterZips.has(zip)).sort()
|
|
7023
7806
|
};
|
|
7024
7807
|
const empty = (d) => d.added.length + d.removed.length + d.changed.length === 0;
|
|
7808
|
+
const teamChanged = (before.teamId ?? null) !== (after.teamId ?? null);
|
|
7025
7809
|
return {
|
|
7026
|
-
identical: empty(observations) && empty(labTests) && empty(labAccounts),
|
|
7810
|
+
identical: empty(observations) && empty(labTests) && empty(labAccounts) && !teamChanged,
|
|
7811
|
+
...teamChanged ? { teamId: { before: before.teamId ?? null, after: after.teamId ?? null } } : {},
|
|
7027
7812
|
observations,
|
|
7028
7813
|
labTests,
|
|
7029
7814
|
labAccounts,
|
|
@@ -7214,6 +7999,7 @@ var createRuntime2 = (options = {}) => {
|
|
|
7214
7999
|
...options.seed !== void 0 ? { seed: options.seed } : {},
|
|
7215
8000
|
...options.adminKey !== void 0 ? { adminKey: options.adminKey } : {},
|
|
7216
8001
|
...options.onLog ? { onLog: options.onLog } : {},
|
|
8002
|
+
...options.journalSize !== void 0 ? { journalSize: options.journalSize } : {},
|
|
7217
8003
|
create: ({ namespace, publicNamespace, sqlite, clock, rng }) => {
|
|
7218
8004
|
const api = new JunctionAPI({
|
|
7219
8005
|
sqlite,
|
|
@@ -7223,6 +8009,10 @@ var createRuntime2 = (options = {}) => {
|
|
|
7223
8009
|
...options.corpus ? { corpus: options.corpus } : {},
|
|
7224
8010
|
...options.geo ? { geo: options.geo } : {},
|
|
7225
8011
|
...options.labAccounts ? { labAccounts: options.labAccounts } : {},
|
|
8012
|
+
...options.teamId !== void 0 ? { teamId: options.teamId } : {},
|
|
8013
|
+
...options.limits ? { limits: options.limits } : {},
|
|
8014
|
+
...options.identity ? { identity: options.identity } : {},
|
|
8015
|
+
...options.fixtures ? { fixtures: options.fixtures } : {},
|
|
7226
8016
|
onWebhook: (event) => {
|
|
7227
8017
|
options.onWebhook?.(event, publicNamespace);
|
|
7228
8018
|
webhooks?.publish(event, publicNamespace);
|
|
@@ -7240,6 +8030,7 @@ var createRuntime2 = (options = {}) => {
|
|
|
7240
8030
|
return {
|
|
7241
8031
|
corpus: info?.label ?? null,
|
|
7242
8032
|
geo: runtime.instance().geoMode,
|
|
8033
|
+
teamId: runtime.instance().teamId,
|
|
7243
8034
|
webhooks: webhooks ? "on" : "off"
|
|
7244
8035
|
};
|
|
7245
8036
|
},
|
|
@@ -7284,6 +8075,95 @@ var firstDifference = (a, b, path = "$") => {
|
|
|
7284
8075
|
}
|
|
7285
8076
|
return path;
|
|
7286
8077
|
};
|
|
8078
|
+
var orderScopedCalls = (orderId) => {
|
|
8079
|
+
const base = `/v3/order/${orderId}`;
|
|
8080
|
+
const key = { booking_key: "00000000-0000-4000-8000-00000000b00c" };
|
|
8081
|
+
const reason = { cancellation_reason_id: "00000000-0000-4000-8000-00000000c0de" };
|
|
8082
|
+
return {
|
|
8083
|
+
get_order_v3_order__order_id__get: { method: "GET", path: base },
|
|
8084
|
+
cancel_order_v3_order__order_id__cancel_post: { method: "POST", path: `${base}/cancel` },
|
|
8085
|
+
simulate_order_v3_order__order_id__test_post: {
|
|
8086
|
+
method: "POST",
|
|
8087
|
+
path: `${base}/test?final_status=completed.at_home_phlebotomy.completed`,
|
|
8088
|
+
body: {}
|
|
8089
|
+
},
|
|
8090
|
+
get_order_requisition_pdf_v3_order__order_id__requisition_pdf_get: {
|
|
8091
|
+
method: "GET",
|
|
8092
|
+
path: `${base}/requisition/pdf`
|
|
8093
|
+
},
|
|
8094
|
+
get_result_raw_v3_order__order_id__result_get: { method: "GET", path: `${base}/result` },
|
|
8095
|
+
get_result_metadata_v3_order__order_id__result_metadata_get: {
|
|
8096
|
+
method: "GET",
|
|
8097
|
+
path: `${base}/result/metadata`
|
|
8098
|
+
},
|
|
8099
|
+
get_result_pdf_v3_order__order_id__result_pdf_get: {
|
|
8100
|
+
method: "GET",
|
|
8101
|
+
path: `${base}/result/pdf`
|
|
8102
|
+
},
|
|
8103
|
+
get_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_get: {
|
|
8104
|
+
method: "GET",
|
|
8105
|
+
path: `${base}/phlebotomy/appointment`
|
|
8106
|
+
},
|
|
8107
|
+
book_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_book_post: {
|
|
8108
|
+
method: "POST",
|
|
8109
|
+
path: `${base}/phlebotomy/appointment/book`,
|
|
8110
|
+
body: key
|
|
8111
|
+
},
|
|
8112
|
+
reschedule_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_reschedule_patch: {
|
|
8113
|
+
method: "PATCH",
|
|
8114
|
+
path: `${base}/phlebotomy/appointment/reschedule`,
|
|
8115
|
+
body: key
|
|
8116
|
+
},
|
|
8117
|
+
cancel_phlebotomy_appointment_v3_order__order_id__phlebotomy_appointment_cancel_patch: {
|
|
8118
|
+
method: "PATCH",
|
|
8119
|
+
path: `${base}/phlebotomy/appointment/cancel`,
|
|
8120
|
+
body: reason
|
|
8121
|
+
},
|
|
8122
|
+
get_psc_appointment_v3_order__order_id__psc_appointment_get: {
|
|
8123
|
+
method: "GET",
|
|
8124
|
+
path: `${base}/psc/appointment`
|
|
8125
|
+
},
|
|
8126
|
+
book_psc_appointment_v3_order__order_id__psc_appointment_book_post: {
|
|
8127
|
+
method: "POST",
|
|
8128
|
+
path: `${base}/psc/appointment/book`,
|
|
8129
|
+
body: key
|
|
8130
|
+
},
|
|
8131
|
+
reschedule_psc_appointment_v3_order__order_id__psc_appointment_reschedule_patch: {
|
|
8132
|
+
method: "PATCH",
|
|
8133
|
+
path: `${base}/psc/appointment/reschedule`,
|
|
8134
|
+
body: key
|
|
8135
|
+
},
|
|
8136
|
+
cancel_psc_appointment_v3_order__order_id__psc_appointment_cancel_patch: {
|
|
8137
|
+
method: "PATCH",
|
|
8138
|
+
path: `${base}/psc/appointment/cancel`,
|
|
8139
|
+
body: reason
|
|
8140
|
+
}
|
|
8141
|
+
};
|
|
8142
|
+
};
|
|
8143
|
+
var orderBody = (userId, labTestId, extra = {}) => ({
|
|
8144
|
+
user_id: userId,
|
|
8145
|
+
patient_details: {
|
|
8146
|
+
first_name: "Mockingbird",
|
|
8147
|
+
last_name: "Verify",
|
|
8148
|
+
dob: "1990-01-01",
|
|
8149
|
+
gender: "female",
|
|
8150
|
+
phone_number: "+14155551234",
|
|
8151
|
+
email: "verify@example.com"
|
|
8152
|
+
},
|
|
8153
|
+
patient_address: {
|
|
8154
|
+
first_line: "1 Main St",
|
|
8155
|
+
city: "San Diego",
|
|
8156
|
+
state: "CA",
|
|
8157
|
+
zip: "92101",
|
|
8158
|
+
country: "US"
|
|
8159
|
+
},
|
|
8160
|
+
order_set: { lab_test_ids: [labTestId] },
|
|
8161
|
+
...extra
|
|
8162
|
+
});
|
|
8163
|
+
var captureExtraOrder = (reply, ctx) => {
|
|
8164
|
+
const id = reply.body?.order?.id;
|
|
8165
|
+
if (typeof id === "string") ctx.extraOrders.push(id);
|
|
8166
|
+
};
|
|
7287
8167
|
var scenario = (corpus, withOrders) => {
|
|
7288
8168
|
const zip = Object.keys(corpus.observations).map((key) => /\/v3\/order\/area\/info\?.*zip_code=(\d{5})/.exec(key)?.[1]).find((found) => found !== void 0) ?? "92101";
|
|
7289
8169
|
const labTestId = corpus.catalog.labTests[0]?.id;
|
|
@@ -7335,6 +8215,11 @@ var scenario = (corpus, withOrders) => {
|
|
|
7335
8215
|
compare: "shape",
|
|
7336
8216
|
request: () => ({ method: "GET", path: "/v3/lab_tests/labs" })
|
|
7337
8217
|
},
|
|
8218
|
+
{
|
|
8219
|
+
name: "lab tests (bare array)",
|
|
8220
|
+
compare: "shape",
|
|
8221
|
+
request: () => ({ method: "GET", path: "/v3/lab_tests" })
|
|
8222
|
+
},
|
|
7338
8223
|
{
|
|
7339
8224
|
name: `area info ${zip}`,
|
|
7340
8225
|
compare: "exact",
|
|
@@ -7349,25 +8234,7 @@ var scenario = (corpus, withOrders) => {
|
|
|
7349
8234
|
request: (ctx) => ({
|
|
7350
8235
|
method: "POST",
|
|
7351
8236
|
path: "/v3/order",
|
|
7352
|
-
body:
|
|
7353
|
-
user_id: ctx.userId,
|
|
7354
|
-
patient_details: {
|
|
7355
|
-
first_name: "Mockingbird",
|
|
7356
|
-
last_name: "Verify",
|
|
7357
|
-
dob: "1990-01-01",
|
|
7358
|
-
gender: "female",
|
|
7359
|
-
phone_number: "+14155551234",
|
|
7360
|
-
email: "verify@example.com"
|
|
7361
|
-
},
|
|
7362
|
-
patient_address: {
|
|
7363
|
-
first_line: "1 Main St",
|
|
7364
|
-
city: "San Diego",
|
|
7365
|
-
state: "CA",
|
|
7366
|
-
zip: "92101",
|
|
7367
|
-
country: "US"
|
|
7368
|
-
},
|
|
7369
|
-
order_set: { lab_test_ids: [labTestId] }
|
|
7370
|
-
}
|
|
8237
|
+
body: orderBody(ctx.userId, labTestId)
|
|
7371
8238
|
}),
|
|
7372
8239
|
capture: (reply, ctx) => {
|
|
7373
8240
|
const id = reply.body?.order?.id;
|
|
@@ -7388,6 +8255,47 @@ var scenario = (corpus, withOrders) => {
|
|
|
7388
8255
|
}
|
|
7389
8256
|
);
|
|
7390
8257
|
}
|
|
8258
|
+
const unknownOrder = crypto.randomUUID();
|
|
8259
|
+
const calls = orderScopedCalls(unknownOrder);
|
|
8260
|
+
for (const operationId of Object.keys(ORDER_NOT_FOUND)) {
|
|
8261
|
+
const call = calls[operationId];
|
|
8262
|
+
if (!call) continue;
|
|
8263
|
+
steps.push({
|
|
8264
|
+
name: `unknown order 404 ${operationId}`,
|
|
8265
|
+
compare: "exact",
|
|
8266
|
+
request: () => call
|
|
8267
|
+
});
|
|
8268
|
+
}
|
|
8269
|
+
const openAccount = corpus.labAccounts.find(
|
|
8270
|
+
(account2) => Array.isArray(account2.team_id_allowlist) && account2.team_id_allowlist.length === 0 && account2.status === "active"
|
|
8271
|
+
);
|
|
8272
|
+
const openLabTest = openAccount ? corpus.catalog.labTests.find(
|
|
8273
|
+
(test) => String(test.lab?.slug ?? "").toLowerCase() === String(openAccount.lab).toLowerCase()
|
|
8274
|
+
) : void 0;
|
|
8275
|
+
if (withOrders && openAccount && openLabTest) {
|
|
8276
|
+
steps.push(
|
|
8277
|
+
{
|
|
8278
|
+
name: `order.create via empty-allowlist account ${String(openAccount.id)}`,
|
|
8279
|
+
compare: "shape",
|
|
8280
|
+
request: (ctx) => ({
|
|
8281
|
+
method: "POST",
|
|
8282
|
+
path: "/v3/order",
|
|
8283
|
+
body: orderBody(ctx.userId, openLabTest.id, { lab_account_id: openAccount.id })
|
|
8284
|
+
}),
|
|
8285
|
+
capture: captureExtraOrder
|
|
8286
|
+
},
|
|
8287
|
+
{
|
|
8288
|
+
name: `order.create for ${String(openAccount.lab)} with lab_account_id omitted`,
|
|
8289
|
+
compare: "shape",
|
|
8290
|
+
request: (ctx) => ({
|
|
8291
|
+
method: "POST",
|
|
8292
|
+
path: "/v3/order",
|
|
8293
|
+
body: orderBody(ctx.userId, openLabTest.id)
|
|
8294
|
+
}),
|
|
8295
|
+
capture: captureExtraOrder
|
|
8296
|
+
}
|
|
8297
|
+
);
|
|
8298
|
+
}
|
|
7391
8299
|
steps.push({
|
|
7392
8300
|
name: "user.delete",
|
|
7393
8301
|
compare: "shape",
|
|
@@ -7463,7 +8371,10 @@ var verifyAgainstReal = async (options) => {
|
|
|
7463
8371
|
}
|
|
7464
8372
|
}
|
|
7465
8373
|
const clientUserId = `mockingbird-verify-${Date.now().toString(36)}`;
|
|
7466
|
-
const ctx = {
|
|
8374
|
+
const ctx = {
|
|
8375
|
+
real: { clientUserId, extraOrders: [] },
|
|
8376
|
+
mock: { clientUserId, extraOrders: [] }
|
|
8377
|
+
};
|
|
7467
8378
|
const steps = scenario(options.corpus, options.orders === true);
|
|
7468
8379
|
let ran = 0;
|
|
7469
8380
|
let divergent = 0;
|
|
@@ -7506,8 +8417,9 @@ var verifyAgainstReal = async (options) => {
|
|
|
7506
8417
|
await sleep(gap);
|
|
7507
8418
|
}
|
|
7508
8419
|
} finally {
|
|
7509
|
-
|
|
7510
|
-
|
|
8420
|
+
for (const orderId of [ctx.real.orderId, ...ctx.real.extraOrders]) {
|
|
8421
|
+
if (orderId === void 0) continue;
|
|
8422
|
+
await call("real", "POST", `/v3/order/${orderId}/cancel`).catch(() => void 0);
|
|
7511
8423
|
}
|
|
7512
8424
|
if (ctx.real.userId) {
|
|
7513
8425
|
await call("real", "DELETE", `/v2/user/${ctx.real.userId}`).catch(() => void 0);
|
|
@@ -7557,6 +8469,10 @@ var JunctionAPI = class {
|
|
|
7557
8469
|
sqlite;
|
|
7558
8470
|
service;
|
|
7559
8471
|
state;
|
|
8472
|
+
now;
|
|
8473
|
+
explicitTeamId;
|
|
8474
|
+
fixtures;
|
|
8475
|
+
rateWindow = new RateWindow();
|
|
7560
8476
|
corpus;
|
|
7561
8477
|
labAccountConfig;
|
|
7562
8478
|
constructor(options = {}) {
|
|
@@ -7564,6 +8480,13 @@ var JunctionAPI = class {
|
|
|
7564
8480
|
const namespace = options.namespace ?? JUNCTION_NAMESPACE;
|
|
7565
8481
|
const state = new JunctionState(sqlite, namespace, options.onWebhook, options.webhook);
|
|
7566
8482
|
this.state = state;
|
|
8483
|
+
this.now = options.now ?? (() => Date.now());
|
|
8484
|
+
this.explicitTeamId = options.teamId;
|
|
8485
|
+
state.teamId = options.teamId ?? options.corpus?.teamId ?? MOCK_TEAM_ID;
|
|
8486
|
+
state.limits = mergeLimits(DEFAULT_LIMITS, options.limits ?? {});
|
|
8487
|
+
if (options.identity !== void 0 && !IDENTITY_MODES.includes(options.identity))
|
|
8488
|
+
throw new TypeError(`identity must be one of ${IDENTITY_MODES.join(", ")}`);
|
|
8489
|
+
state.identity = options.identity ?? "strict";
|
|
7567
8490
|
const handlers = defineOperations({
|
|
7568
8491
|
...userHandlers(state),
|
|
7569
8492
|
...orderHandlers(state),
|
|
@@ -7585,22 +8508,34 @@ var JunctionAPI = class {
|
|
|
7585
8508
|
});
|
|
7586
8509
|
this.app = this.service.app;
|
|
7587
8510
|
this.sqlite = this.service.sqlite;
|
|
7588
|
-
this.labAccountConfig = options.labAccounts
|
|
8511
|
+
this.labAccountConfig = options.labAccounts ? expandLabAccountLayout(options.labAccounts, state.teamId) : void 0;
|
|
7589
8512
|
if (options.corpus) this.installCorpus(options.corpus);
|
|
7590
8513
|
else this.seedLabAccounts();
|
|
7591
8514
|
state.geoMode = options.geo ?? (options.corpus ? "corpus" : "synthetic");
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
8515
|
+
this.fixtures = options.fixtures;
|
|
8516
|
+
if (this.fixtures) importFixturesInto(state, this.fixtures, this.now);
|
|
8517
|
+
}
|
|
8518
|
+
async fetch(request2) {
|
|
8519
|
+
if (!this.rateWindow.take(this.state.limits.rateLimitPerSecond)) {
|
|
8520
|
+
return jsonRes(429, { detail: "Too Many Requests" }, { "retry-after": "1" });
|
|
8521
|
+
}
|
|
8522
|
+
const normalized = normalizePath(request2);
|
|
8523
|
+
const sent = requestJson(normalized);
|
|
8524
|
+
const response = await this.service.fetch(normalized);
|
|
8525
|
+
const ids = await touchedIds(normalized, await sent, response);
|
|
8526
|
+
return annotateResponse(response, {
|
|
8527
|
+
...Object.keys(ids).length > 0 ? { ids } : {},
|
|
8528
|
+
...this.state.adopted(normalized) ? { adopted: true } : {}
|
|
8529
|
+
});
|
|
7595
8530
|
}
|
|
7596
8531
|
async reset() {
|
|
7597
8532
|
await this.service.reset();
|
|
7598
|
-
if (this.corpus)
|
|
7599
|
-
|
|
7600
|
-
|
|
8533
|
+
if (this.corpus) this.installCorpus(this.corpus);
|
|
8534
|
+
else {
|
|
8535
|
+
this.state.seedDefaultCatalog();
|
|
8536
|
+
this.seedLabAccounts();
|
|
7601
8537
|
}
|
|
7602
|
-
this.state.
|
|
7603
|
-
this.seedLabAccounts();
|
|
8538
|
+
if (this.fixtures) importFixturesInto(this.state, this.fixtures, this.now);
|
|
7604
8539
|
}
|
|
7605
8540
|
/**
|
|
7606
8541
|
* Install a sealed sandbox recording: seed the observation cache and replace the catalog,
|
|
@@ -7612,6 +8547,7 @@ var JunctionAPI = class {
|
|
|
7612
8547
|
this.state.replaceCatalog(corpus.catalog);
|
|
7613
8548
|
}
|
|
7614
8549
|
this.corpus = corpus;
|
|
8550
|
+
this.state.teamId = this.explicitTeamId ?? corpus.teamId ?? MOCK_TEAM_ID;
|
|
7615
8551
|
this.state.coveredZips = coveredZipsOf(corpus);
|
|
7616
8552
|
this.state.corpusLabel = corpusLabel(corpus);
|
|
7617
8553
|
this.seedLabAccounts();
|
|
@@ -7622,20 +8558,93 @@ var JunctionAPI = class {
|
|
|
7622
8558
|
* recorded from a team with no accounts leaves in place).
|
|
7623
8559
|
*/
|
|
7624
8560
|
seedLabAccounts() {
|
|
7625
|
-
const recorded = (this.corpus?.labAccounts ?? []).map(labAccountFromClientFacing).filter((entry) => entry !== void 0);
|
|
8561
|
+
const recorded = (this.corpus?.labAccounts ?? []).map((entry) => labAccountFromClientFacing(entry, this.corpus?.teamId)).filter((entry) => entry !== void 0);
|
|
7626
8562
|
this.state.replaceLabAccounts(
|
|
7627
8563
|
this.labAccountConfig ?? (recorded.length > 0 ? recorded : [...TEAM_LAB_ACCOUNTS])
|
|
7628
8564
|
);
|
|
7629
8565
|
}
|
|
7630
|
-
/**
|
|
8566
|
+
/** The team this namespace answers as. */
|
|
8567
|
+
get teamId() {
|
|
8568
|
+
return this.state.teamId;
|
|
8569
|
+
}
|
|
8570
|
+
/**
|
|
8571
|
+
* Replace the team's lab accounts (a list, or `{ presets, accounts }`); `undefined`
|
|
8572
|
+
* restores the default. Kept across `reset()`, per namespace.
|
|
8573
|
+
*/
|
|
7631
8574
|
configureLabAccounts(accounts) {
|
|
7632
|
-
this.labAccountConfig = accounts
|
|
8575
|
+
this.labAccountConfig = accounts ? expandLabAccountLayout(accounts, this.state.teamId) : void 0;
|
|
7633
8576
|
this.seedLabAccounts();
|
|
7634
8577
|
return this.state.listLabAccounts();
|
|
7635
8578
|
}
|
|
7636
8579
|
labAccounts() {
|
|
7637
8580
|
return this.state.listLabAccounts();
|
|
7638
8581
|
}
|
|
8582
|
+
/** Apply one change to the effective account list and keep it as this namespace's config. */
|
|
8583
|
+
editLabAccounts(edit) {
|
|
8584
|
+
this.labAccountConfig = edit([...this.labAccountConfig ?? this.state.listLabAccounts()]);
|
|
8585
|
+
this.seedLabAccounts();
|
|
8586
|
+
}
|
|
8587
|
+
/** Add one account. Throws `LabAccountConflict` when the id is taken. Kept across resets. */
|
|
8588
|
+
addLabAccount(input) {
|
|
8589
|
+
const record = labAccountFromInput(input, this.state.teamId);
|
|
8590
|
+
if (this.state.labAccounts.has(record.id)) throw new LabAccountConflict(record.id);
|
|
8591
|
+
this.editLabAccounts((accounts) => [...accounts, record]);
|
|
8592
|
+
return record;
|
|
8593
|
+
}
|
|
8594
|
+
/** Add a named preset (see `LAB_ACCOUNT_PRESETS`); `undefined` for an unknown name. */
|
|
8595
|
+
addLabAccountPreset(name, id) {
|
|
8596
|
+
const record = labAccountFromPreset(name, {
|
|
8597
|
+
teamId: this.state.teamId,
|
|
8598
|
+
...id !== void 0 ? { id } : {}
|
|
8599
|
+
});
|
|
8600
|
+
return record ? this.addLabAccount(record) : void 0;
|
|
8601
|
+
}
|
|
8602
|
+
/** Merge fields into an account; `undefined` when there is none with that id. */
|
|
8603
|
+
patchLabAccount(id, patch) {
|
|
8604
|
+
const existing = this.state.labAccounts.get(id);
|
|
8605
|
+
if (!existing) return void 0;
|
|
8606
|
+
const next = patchLabAccount(existing, patch, this.state.teamId);
|
|
8607
|
+
this.editLabAccounts((accounts) => accounts.map((entry) => entry.id === id ? next : entry));
|
|
8608
|
+
return next;
|
|
8609
|
+
}
|
|
8610
|
+
removeLabAccount(id) {
|
|
8611
|
+
if (!this.state.labAccounts.has(id)) return false;
|
|
8612
|
+
this.editLabAccounts((accounts) => accounts.filter((entry) => entry.id !== id));
|
|
8613
|
+
return true;
|
|
8614
|
+
}
|
|
8615
|
+
/** The sandbox limits this namespace enforces. Every one is off unless configured. */
|
|
8616
|
+
get limits() {
|
|
8617
|
+
return { ...this.state.limits };
|
|
8618
|
+
}
|
|
8619
|
+
/** Change some limits (`null` lifts a numeric one); kept across `reset()`. */
|
|
8620
|
+
configureLimits(input) {
|
|
8621
|
+
this.state.limits = mergeLimits(this.state.limits, input);
|
|
8622
|
+
return this.limits;
|
|
8623
|
+
}
|
|
8624
|
+
get identity() {
|
|
8625
|
+
return this.state.identity;
|
|
8626
|
+
}
|
|
8627
|
+
set identity(mode) {
|
|
8628
|
+
if (!IDENTITY_MODES.includes(mode))
|
|
8629
|
+
throw new TypeError(`identity must be one of ${IDENTITY_MODES.join(", ")}`);
|
|
8630
|
+
this.state.identity = mode;
|
|
8631
|
+
}
|
|
8632
|
+
/** Insert users with chosen ids, all or none. Throws `FixtureError` (400/404/409). */
|
|
8633
|
+
insertUsers(users) {
|
|
8634
|
+
return insertUsers(this.state, users, this.now);
|
|
8635
|
+
}
|
|
8636
|
+
/** Remove a user outright, leaving no deletion tombstone. */
|
|
8637
|
+
hardDeleteUser(userId) {
|
|
8638
|
+
return hardDeleteUser(this.state, userId);
|
|
8639
|
+
}
|
|
8640
|
+
/** Insert orders, optionally already in a status. No webhook fires unless asked. */
|
|
8641
|
+
insertOrders(orders, options = {}) {
|
|
8642
|
+
return insertOrders(this.state, orders, this.now, options);
|
|
8643
|
+
}
|
|
8644
|
+
/** Load users, then orders, in one call. */
|
|
8645
|
+
importFixtures(fixtures, options = {}) {
|
|
8646
|
+
return importFixtures(this.state, fixtures, this.now, options);
|
|
8647
|
+
}
|
|
7639
8648
|
corpusInfo() {
|
|
7640
8649
|
const corpus = this.corpus;
|
|
7641
8650
|
if (!corpus) return void 0;
|
|
@@ -7646,7 +8655,8 @@ var JunctionAPI = class {
|
|
|
7646
8655
|
observations: Object.keys(corpus.observations).length,
|
|
7647
8656
|
labTests: corpus.catalog.labTests.length,
|
|
7648
8657
|
labAccounts: corpus.labAccounts.length,
|
|
7649
|
-
zips: this.state.coveredZips.size
|
|
8658
|
+
zips: this.state.coveredZips.size,
|
|
8659
|
+
...corpus.teamId !== void 0 ? { teamId: corpus.teamId } : {}
|
|
7650
8660
|
};
|
|
7651
8661
|
}
|
|
7652
8662
|
get geoMode() {
|
|
@@ -7706,6 +8716,59 @@ var JunctionAPI = class {
|
|
|
7706
8716
|
return this.state.webhookDeliveryAttemptsInOrder();
|
|
7707
8717
|
}
|
|
7708
8718
|
};
|
|
8719
|
+
var LabAccountConflict = class extends Error {
|
|
8720
|
+
constructor(id) {
|
|
8721
|
+
super(`lab account ${id} already exists`);
|
|
8722
|
+
this.id = id;
|
|
8723
|
+
this.name = "LabAccountConflict";
|
|
8724
|
+
}
|
|
8725
|
+
id;
|
|
8726
|
+
};
|
|
8727
|
+
var importFixturesInto = (state, fixtures, now) => {
|
|
8728
|
+
try {
|
|
8729
|
+
importFixtures(state, fixtures, now);
|
|
8730
|
+
} catch (error) {
|
|
8731
|
+
const { message } = fixtureErrorMessage(error);
|
|
8732
|
+
throw new Error(`junction fixtures: ${message}`);
|
|
8733
|
+
}
|
|
8734
|
+
};
|
|
8735
|
+
var asRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
8736
|
+
var isJson = (headers) => (headers.get("content-type") ?? "").toLowerCase().includes("json");
|
|
8737
|
+
var requestJson = async (request2) => {
|
|
8738
|
+
if (request2.method === "GET" || request2.method === "HEAD" || !isJson(request2.headers))
|
|
8739
|
+
return void 0;
|
|
8740
|
+
return asRecord3(
|
|
8741
|
+
await request2.clone().json().catch(() => void 0)
|
|
8742
|
+
);
|
|
8743
|
+
};
|
|
8744
|
+
var UUID_SEGMENT = "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}";
|
|
8745
|
+
var USER_PATH = new RegExp(`^/v2/user/(${UUID_SEGMENT})(?:/|$)`);
|
|
8746
|
+
var ORDER_PATH = new RegExp(`^/v3/order/(${UUID_SEGMENT})(?:/|$)`);
|
|
8747
|
+
var touchedIds = async (request2, body, response) => {
|
|
8748
|
+
const ids = {};
|
|
8749
|
+
const put2 = (key, value) => {
|
|
8750
|
+
if (typeof value === "string" && value !== "" && ids[key] === void 0) ids[key] = value;
|
|
8751
|
+
};
|
|
8752
|
+
const url = new URL(request2.url);
|
|
8753
|
+
put2("userId", USER_PATH.exec(url.pathname)?.[1]);
|
|
8754
|
+
put2("orderId", ORDER_PATH.exec(url.pathname)?.[1]);
|
|
8755
|
+
put2("userId", url.searchParams.get("user_id"));
|
|
8756
|
+
put2("orderId", url.searchParams.get("order_id"));
|
|
8757
|
+
put2("labAccountId", url.searchParams.get("lab_account_id"));
|
|
8758
|
+
put2("userId", body?.user_id);
|
|
8759
|
+
put2("labAccountId", body?.lab_account_id);
|
|
8760
|
+
if (request2.method === "POST" && response.ok && isJson(response.headers)) {
|
|
8761
|
+
const created = asRecord3(
|
|
8762
|
+
await response.clone().json().catch(() => void 0)
|
|
8763
|
+
);
|
|
8764
|
+
const order = asRecord3(created?.order);
|
|
8765
|
+
put2("orderId", order?.id);
|
|
8766
|
+
put2("userId", order?.user_id);
|
|
8767
|
+
put2("labAccountId", order?.lab_account_id);
|
|
8768
|
+
put2("userId", created?.user_id);
|
|
8769
|
+
}
|
|
8770
|
+
return ids;
|
|
8771
|
+
};
|
|
7709
8772
|
var normalizePath = (request2) => {
|
|
7710
8773
|
if (!request2.url.includes("/./") && !request2.url.includes("/../") && !/%2f/i.test(request2.url)) {
|
|
7711
8774
|
return request2;
|
|
@@ -7731,20 +8794,36 @@ var normalizePath = (request2) => {
|
|
|
7731
8794
|
};
|
|
7732
8795
|
|
|
7733
8796
|
export {
|
|
7734
|
-
|
|
7735
|
-
|
|
7736
|
-
|
|
8797
|
+
SANDBOX_KEY_PREFIXES,
|
|
8798
|
+
isSandboxKey,
|
|
8799
|
+
DEFAULT_LIMITS,
|
|
8800
|
+
sandboxUserQuotaBody,
|
|
7737
8801
|
observationCacheKey,
|
|
8802
|
+
MOCK_TEAM_ID,
|
|
7738
8803
|
US_STATES,
|
|
8804
|
+
OTHER_TEAM_ID,
|
|
7739
8805
|
TEAM_LAB_ACCOUNTS,
|
|
8806
|
+
isLinkedToTeam,
|
|
7740
8807
|
labAccountFromInput,
|
|
7741
|
-
|
|
7742
|
-
|
|
8808
|
+
PLATFORM_ACCOUNT_STATES,
|
|
8809
|
+
DELEGATED_ACCOUNT_STATES,
|
|
8810
|
+
LAB_ACCOUNT_PRESETS,
|
|
8811
|
+
presetAccountId,
|
|
7743
8812
|
ORDER_STATUSES_BY_METHOD,
|
|
7744
8813
|
TRANSITION_ALIASES,
|
|
7745
8814
|
RESULT_FIXTURES,
|
|
7746
8815
|
FAULT_PRESETS,
|
|
7747
8816
|
resolveTransition,
|
|
8817
|
+
ORDER_NOT_FOUND,
|
|
8818
|
+
MISS_HEADER,
|
|
8819
|
+
KNOWN_HEADER,
|
|
8820
|
+
UNKNOWN_ZIP_STATUS,
|
|
8821
|
+
UNKNOWN_ZIP_ERROR_TYPE,
|
|
8822
|
+
IDENTITY_MODES,
|
|
8823
|
+
FixtureError,
|
|
8824
|
+
document,
|
|
8825
|
+
operationIds,
|
|
8826
|
+
supportedOperationIds,
|
|
7748
8827
|
PSC_AVAILABILITY_ZIPS,
|
|
7749
8828
|
PHLEBOTOMY_AVAILABILITY_ZIPS,
|
|
7750
8829
|
COVERAGE_ZIPS,
|
|
@@ -7754,8 +8833,6 @@ export {
|
|
|
7754
8833
|
reshapeCoverageGeoCommand,
|
|
7755
8834
|
prefetchCoverageObservations,
|
|
7756
8835
|
DEFAULT_JUNCTION_BASE_URL,
|
|
7757
|
-
SANDBOX_KEY_PREFIXES,
|
|
7758
|
-
isSandboxKey,
|
|
7759
8836
|
fingerprintCorpus,
|
|
7760
8837
|
pullCorpus,
|
|
7761
8838
|
diffCorpus,
|
|
@@ -7766,6 +8843,7 @@ export {
|
|
|
7766
8843
|
verifyAgainstReal,
|
|
7767
8844
|
JUNCTION_NAMESPACE,
|
|
7768
8845
|
corpusLabel,
|
|
7769
|
-
JunctionAPI
|
|
8846
|
+
JunctionAPI,
|
|
8847
|
+
LabAccountConflict
|
|
7770
8848
|
};
|
|
7771
|
-
//# sourceMappingURL=chunk-
|
|
8849
|
+
//# sourceMappingURL=chunk-NFWUEPW4.js.map
|