@crvouga/mockingbird-service-全写
本地模拟器。 真正的API合同. 部分 嘲笑鸟。 。 。 .
国家模拟器 正式标注 测试套房的实验室订购API:每名练习生 OAuth
(同意重新定向, authorization_code 旋转 refresh_token 赠款、撤销、
诊所、可嵌入式会诊补助金、附有检测结果的实验室订单、实验室订单事件,到期
结果PDF,以及 Fullscript-Signature 面对挑战,我们接收者
执行。 实验室命令只能通过 完全的全写状态前进 当测试表明
所以说.
- 行动范围: 支助
- 合同
openapi.yaml) 由EMR消费者亲笔撰写 (单位:千美元)fullscript-api-client.ts, (中文(简体) ),fullscript-event-model.ts, (中文(简体) ),fullscript-webhook-signature.ts, (中文(简体) ),routers/v1/fullscript/webhook-controller.ts, (中文(简体) ),fullscript-result-storage.ts) (中文(简体) ).
安装
npm install -D @crvouga/mockingbird-service-fullscript
仅限无害环境管理。 节点 22或 Bun 1.2. 无土生属地. 给它服务
npx mockingbird-fullscript serve, (中文(简体) ), createServer 从 ./server (节点),或 createRuntime
与任何获取服务器.
使用量
与 FEATURE_FULLSCRIPT_LABS_ENABLED=true点 FULLSCRIPT_API_URL 在模拟者那里
FULLSCRIPT_OAUTH_AUTHORIZE_URL 联合国 /oauth/authorize; 设置 FULLSCRIPT_WEBHOOK_SECRET 财务报告和审定财务报表
FULLSCRIPT_WEBHOOK_CHALLENGE_KEY 并传递与 --webhook-secret 编号 :
--webhook-challenge。EMR将这些 URL 验证为 网页 而下载结果仅为 PDF
从允许的列表主机覆盖 https (默认情况下) fullscript.com, (中文(简体) ), fullscript.io 财务报告和审定财务报表
FULLSCRIPT_API_URL模拟器所在的宿主,所以在模拟器前用 TLS 或
设定 --results-base-url。 。 。 .
npx mockingbird-fullscript serve --port 8819 \
--webhook-url http://127.0.0.1:4000/v1/fullscript/webhooks \
--webhook-secret "$FULLSCRIPT_WEBHOOK_SECRET" --webhook-challenge "$FULLSCRIPT_WEBHOOK_CHALLENGE_KEY"
import { createServer } from "@crvouga/mockingbird-service-fullscript/server"
// Test setup: the emulator, a lab order moved to results, and the code an OAuth redirect delivers.
const server = await createServer({
webhooks: { url: "http://127.0.0.1:4000/v1/fullscript/webhooks", secret: "whsec", challenge: "chal" },
})
const admin = (path: string, body: unknown) =>
fetch(`${server.url}/__admin${path}`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(body),
})
const order = (await (await admin("/lab-orders", { patientId: "fs_pat_1", treatmentPlanId: "tp_1" })).json()) as { id: string }
await admin(`/lab-orders/${order.id}/transition`, { to: "purchased" }) // order.placed + lab_order.updated
await admin(`/lab-orders/${order.id}/transition`, { to: "results_ready" }) // results + PDF URLs
const { code } = (await (await admin("/oauth/codes", { clientId: "emr-client" })).json()) as { code: string }
// Application code: FULLSCRIPT_API_URL is server.url. Exchange the code, then read the order.
const apiUrl = server.url
const token = await fetch(`${apiUrl}/api/oauth/token`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
grant_type: "authorization_code",
client_id: "emr-client",
client_secret: "emr-secret",
code,
}),
})
const { oauth } = (await token.json()) as { oauth: { access_token: string } }
const read = await fetch(`${apiUrl}/api/clinic/labs/orders/${order.id}`, {
headers: { authorization: `Bearer ${oauth.access_token}` },
})
const { order: labOrder } = (await read.json()) as { order: { state: string } }
// labOrder.state is "results_ready"; labOrder.results[].pdf_url are served by the emulator.
await server.close()
路线
| 路线 | 行为 |
|---|---|
GET /oauth/authorize | 自动同意为 practitioner_id (默认) prac_mock_1)并重定向到 redirect_uri?code=…&state=…。 。 。 . |
POST /api/oauth/token | 贾森 {grant_type, client_id, client_secret, code | refresh_token, redirect_uri} → {oauth: {access_token, token_type: "Bearer", expires_in: 7200, refresh_token, scope, created_at, resource_owner: {id, type, clinic_id}}}。代码是单用,10分钟后到期,必须匹配重定向的 URI;刷新符号旋转(一个用完的符号是 invalid_grant。错误: 400 {error: "invalid_grant" | "invalid_request"}, 401 (中文(简体) ) invalid_client。 。 。 . |
POST /api/oauth/revoke | {client_id, client_secret, token} - 200个 {}; 符号停止工作. |
GET /api/clinic | {clinic: {id, name}} 给信物的从业者. |
POST /api/clinic/embeddable/session_grants | 201 (韩语) {secret_token, expires_at}。 。 。 . |
GET /api/clinic/labs/orders | ?patient_id=&page[number]=&page[size]= → {orders: [{id, state, treatment_plan_id, …}], meta: {current_page, next_page, …}}。 。 。 . |
GET /api/clinic/labs/orders/{id} | {order: {…, collection_method, tests, results: [{id, name, state, pdf_url}], latest_aggregated_result: {id, artifact_id, pdf_url, status}}}。 。 。 . |
GET /api/events/lab_orders | ?order_by=DESC|ASC&page[number]=&page[size]= - 诊所的 lab_order.updated 事件. |
GET /api/events/{id} | {event: {id, type, clinic_id, created_at, data}}。 。 。 . |
GET /results/{artifact}?expires&signature | 结果 PDF(application/pdf,一个真实的一页PDF),直到URL到期(15分钟),然后403. |
API 错误是 {errors: [{code, message}]} (401美元) unauthorized 编号 : invalid_token 编号 :
token_expired页:1 not_found));我们的客户阅读了代码.
国家 (向前只允许跳出): not_purchased → purchased →
schedule_appointment → upcoming_appointment → processing → partial_results (第一届)
试验结果) results_ready (每项结果+一项综合结果) + interpretation_shared
→ results_amended (一出新的综合文物).
网络呼号
每个动作都发出 lab_order.updated (单位:千美元)data.lab_order: {id, state, treatment_plan_id, patient_id})),以及离开 not_purchased 还发出 order.placed (单位:千美元)data: {id, treatment_plan_ids, patient_id, line_items: [{type: "labs"}]}) (中文(简体) ). 交付员额
{event_payload: {event}} 与 Fullscript-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, "<t>." + body)> (墙上小时) t) (中文(简体) ). 带有挑战键,只有在
接收回复 {challenge: <key>} (否则记录为502并重审).
POST /__admin/webhooks/verify 发送全字标的空机名
每个终点是否都与挑战相呼应. GET /__admin/webhooks, (中文(简体) ), …/events, (中文(简体) ), …/replay, (中文(简体) ),
…/flush 和往常一样.
管理员(超过标准合同)
| 路线 | 效果 |
|---|---|
POST /__admin/lab-orders | {patientId, id?, clinicId?, treatmentPlanId?, name?, collectionMethod?, tests?: [names]} − a 个 not_purchased 秩序。 秩序. |
POST /__admin/lab-orders/:id/transition | {to: <state>};后或同态为409. |
GET /__admin/lab-orders, (中文(简体) ), GET /__admin/events | 名字空间的命令与事件. |
POST /__admin/oauth/codes | {practitionerId?, clientId?, redirectUri?} → {code} 没有浏览器重定向. |
POST /__admin/practitioners | {id, clinicId, type?, clinicName?}。 。 。 . |
POST /__admin/webhooks/verify | 注册电话(见Webhooks). |
GET/PUT /__admin/settings | {clients?, accessTokenTtlSeconds?, codeTtlSeconds?, pdfUrlTtlSeconds?, resultsBaseUrl?}。 。 。 . |
错误预设( E)POST /__admin/faults {"preset": "<name>", "count"?: n}: token_expired, (中文(简体) ),
invalid_grant, (中文(简体) ), rate_limited, (中文(简体) ), server_error, (中文(简体) ), events_schema_drift, (中文(简体) ), pdf_not_pdf, (中文(简体) ),
pdf_redirect, (中文(简体) ), pdf_expired, (中文(简体) ), connection_drop, (中文(简体) ), slow, (中文(简体) ), webhook_duplicate, (中文(简体) ),
webhook_reorder, (中文(简体) ), webhook_drop。 。 。 .
命名空间
A 类 /__admin/ns/<name>/ 打开后缀 FULLSCRIPT_API_URL (我们的客户解决相对 api/… 路径,所以
前缀存活下来,PDF URL保存它), x-mockingbird-namespace,或 OAuth 客户端为
API 调用 (PUT /__admin/credentials {"credentials": {"<FULLSCRIPT_CLIENT_ID>": "<ns>"}}· ;
代币背负着被发行给的客户. 托肯请求只包含客户端
身体,所以他们需要前缀或头.
故意不模拟
- 分类、治疗计划、病人、药房订单和每个非实验室终点 嵌入式部件本身(会议赠款是不透明的符号).
- 实验室结果值(仅限PDF),请购和预约.
- 真实同意屏幕 :
/oauth/authorize立即批准 立即批准.
API 密码
| 导出 | 仁爱 | 说明 |
|---|---|---|
FullscriptAPI | 类 | 进程模拟器 : fetch(request), (中文(简体) ), reset(), (中文(简体) ), issueCode(practitionerId, clientId, redirectUri), (中文(简体) ), createOrder(input), (中文(简体) ), transition(orderId, state), (中文(简体) ), seedOrder(seed), (中文(简体) ), labOrders(), (中文(简体) ), eventsList()选项: sqlite, (中文(简体) ), now, (中文(简体) ), namespace, (中文(简体) ), publicNamespace, (中文(简体) ), settings, (中文(简体) ), orders, (中文(简体) ), onEvent。 。 。 . |
createRuntime | 函数 | 全面服务合同的仿真器(健康、管理、命名空间、证书、预设、网络呼号)。 选项 : webhooks: {url, secret, challenge?, retryDelaysMs?, fetch?}, (中文(简体) ), settings, (中文(简体) ), orders, (中文(简体) ), clock, (中文(简体) ), seed, (中文(简体) ), adminKey, (中文(简体) ), onLog, (中文(简体) ), sqlite。 。 。 . |
FULLSCRIPT_PRESETS | 对象 | 每个命名的断层预设. |
FULLSCRIPT_NAMESPACE | 字符串 | 服务名称, "fullscript"。 。 。 . |
SIGNATURE_HEADER | 字符串 | Fullscript-Signature。 。 。 . |
LAB_ORDER_STATES, (中文(简体) ), isLabOrderState | 数值 | 远出所出所出所出所出所出所出所出所出所出所出所出所出所出所出所出所出. |
DEFAULT_CLINIC, (中文(简体) ), DEFAULT_PRACTITIONER | 对象 | 种子诊所和医生. |
RESULT_PDF | 字节 | PDF 每个结果 URL 服务. |
issueAccessToken | 函数 | 薄荷(用于测试和对等)自我验证访问符. |
tokenCredential | 函数 | OAuth 客户端被发给了无记名符号(如何将证书映射到命名空间). |
envelope, (中文(简体) ), publicEvent | 函数 | 事件"网钩"身体和API形状. |
apiErrors, (中文(简体) ), oauthError | 函数 | Build Fullscript的API和OAuth错误响应. |
document, (中文(简体) ), operationIds, (中文(简体) ), supportedOperationIds | 数值 | OpenAPI合同及其操作代号. |
createServer, (中文(简体) ), serveTarget, (中文(简体) ), DEFAULT_PORT (单位:千美元)./server(中文(简体) ) | 节点 | 服务过来 node:http; 数据 serve CLI目标(--webhook-url, (中文(简体) ), --webhook-secret, (中文(简体) ), --webhook-challenge, (中文(简体) ), --client, (中文(简体) ), --results-base-url; 港号8819. |
部分 嘲笑鸟。 。 。 .