# @crvouga/mockingbird-service-aha 中文文档

规范地址：https://npmcn.com/package/%40crvouga/mockingbird-service-aha/

版本：3\.11\.0
npm 元数据更新时间：2026-11-11T01:59:55.289Z
中文译文更新时间：2026-11-11T02:11:23.804Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40crvouga/mockingbird-service-aha
原文对照：https://npmcn.com/package/%40crvouga/mockingbird-service-aha/?lang=original
项目主页：https://github.com/crvouga/mockingbird/tree/main/packages/service/aha#readme
源码仓库：https://github.com/crvouga/mockingbird

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：4.4 MB，21 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：3 个
- 首次发布：2026-09-22T23:52:23.269Z
- 最新版本发布：2026-11-11T01:59:54.928Z
- 近 30 天下载量：16247（2026-10-11 至 2026-11-09，npm 官方下载统计）
- 已发布版本数：42（近 12 个月 42 个）

## 中文简介

状态 AHA phlebotomy 仿真器, 上面有签名的 HTTP 命令, 状态 webhooks, 和真正的确定性 SSH/ SFTP 结果服务器 .

## 安装

```sh
npm install @crvouga/mockingbird-service-aha
```

也可以使用：`pnpm add @crvouga/mockingbird-service-aha`、`yarn add @crvouga/mockingbird-service-aha`、`bun add @crvouga/mockingbird-service-aha`

## README

# @crvouga/ mockingbird-service-aha (英语)

> 本地模拟器。 真正的API合同. 部分 [嘲笑鸟](https://github.com/crvouga/mockingbird)。 。 。 .

国家模拟器 **AHA (高级卫生学院) 在家理发** 用于测试的 API 套接字:HMAC署名的创建顺序并取消,以及——其主要工作——订单状态webhooks AHA 邮递员 销售商没有拉API,所以每个下游效应(EMR预约, storefront status, "blood draw") 起始为 webhook; 仿真器按需发出一个, 每一个 字段,我们的处理器读取, 所以ZIP路线的血液工作路径 终于可以测试.

-   行动范围: [支助](https://github.com/crvouga/mockingbird/blob/main/packages/service/aha/SUPPORT.md)
-   供应商不公布具体内容:合同`openapi.yaml`由我们手写 消费者的zod计划 和电线形状.

## 安装

```bash
npm install -D @crvouga/mockingbird-service-aha
```

仅限无害环境管理。 节点 22或 Bun 1.2. 无土生属地. 给它服务 `npx mockingbird-aha serve`, (中文(简体) ), `createServer` 从 `./server` (节点),或 `createRuntime` 带有任意 获取服务器 .

## 使用量

将应用程序指向模拟器:

| 信封 | 数值 |
| --- | --- |
| `AHA_API_URL` | `http://127.0.0.1:8799` (实验室提供者路径已经允许回回回回;); `AhaService` 需要 http 例外,参见 G-A1 / S10.2) |
| `AHA_API_KEY` 编号 : `AHA_API_SECRET` | 什么都行,否则一对就成了 `--api-key` 编号 : `--api-secret` 准确验证签名 |
| `AHA_USE_LEGACY_AUTH` | `true` 开关到 `X-<Partner>-Auth-Key` (例如:. `X-Acme-Auth-Key`); 两种模式都被接受 |
| `AHA_WEBHOOK_SECRET` | 与 `--webhook-secret` |

```bash
npx mockingbird-aha serve --port 8799 \
  --webhook-url http://127.0.0.1:3000/bloodwork/aha-webhook \
  --webhook-secret "$AHA_WEBHOOK_SECRET" \
  --api-key "$AHA_API_KEY" --api-secret "$AHA_API_SECRET" \
  --envelope raw --auto-schedule 2000
```

```ts
import { createHmac } from "node:crypto"
import { createServer } from "@crvouga/mockingbird-service-aha/server"

// Test setup: the emulator, posting order-status webhooks to the app's handler.
const server = await createServer({
  webhooks: { url: "http://127.0.0.1:3000/bloodwork/aha-webhook", secret: "aha-webhook-secret" },
})

// Application code: its usual signed request, with AHA_API_URL set to server.url.
const [apiUrl, apiKey, apiSecret] = [server.url, "aha-key", "aha-secret"]
const path = "/v1/acme/create-order"
const timestamp = Date.now().toString()
const signature = createHmac("sha256", apiSecret)
  .update(`${apiKey}:${path}:${timestamp}`)
  .digest("base64")
const created = await fetch(`${apiUrl}${path}`, {
  method: "POST",
  headers: {
    "content-type": "application/json",
    "X-API-KEY": apiKey,
    "X-TIMESTAMP": timestamp,
    "X-SIGNATURE": signature,
  },
  body: JSON.stringify({
    partner_order_id: "AC-101", patient_id: "pat-1", biological_sex: "Female",
    patient_first_name: "Ada", patient_last_name: "Lovelace", patient_dob: "1990-12-10",
    patient_phone_number: "5555550100", patient_address_line1: "501 N 5th St",
    patient_city: "Phoenix", patient_state: "AZ", patient_zipcode: "85004",
    service_type: "Full Service", npi: "1234567893", ordering_physician: "Dr. Grace Hopper",
    test_codes: [{ test_code: "CBC", test_description: "Complete blood count" }],
  }),
})
// → {content: {partner_order_id: "AC-101", order_number: "AHA-…"}, message, status: "SUCCESS"}

// Test control: move the order as AHA would. Each transition posts a webhook to the app.
const transition = (body: unknown) =>
  fetch(`${server.url}/__admin/orders/AC-101/transition`, {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify(body),
  })
// AHA books the draw: our handler books the EMR appointment for 10:30 Denver time.
await transition({
  status: "Scheduled",
  scheduledAt: "2026-10-01T16:30:00Z",
  timeZone: "America/Denver",
})
// The phlebotomist checks out with a sample: our handler sets vitalBloodDrawn.
await transition({ status: "Check Out", drawStatus: "Sample Collected" })
await server.close()
```

### 路线

这个 `{partner}` 路径段是您的账户的 sult( 例如) . `acme`);模拟器接受任何.

| 路线 | 行为 |
| --- | --- |
| `POST /v1/{partner}/create-order` | 鉴定尸体(`partner_order_id`病人的田园, `biological_sex`, (中文(简体) ), `service_type`, (中文(简体) ), `npi`, (中文(简体) ), `ordering_physician`, (中文(简体) ), `test_codes`选项 `preferred_schedule_date/time`, (中文(简体) ), `patient_timezone`。创建 **或更新**: 重复 `partner_order_id` 保留它 `order_number`答复 `{content: {partner_order_id, order_number}, message, status: "SUCCESS"}`。 。 。 . |
| `POST /v1/{partner}/cancel` | `{partner_order_id, notes: [{note_type: "CANCELLATION", notes}]}` → `{message, status}`显示 a `Cancelled` webhook( 关闭为 `cancelWebhook: false`) (中文(简体) ). 未知的id → 404;采集样本的命令 → 200 `status: "ERROR"`AHA协会 `order_number` 已接受为 `partner_order_id` 因为我们的实验室提供客户端 把它送到那里(G -A1). |

**奥特.** HMAC 模式 : `X-API-KEY`, (中文(简体) ), `X-TIMESTAMP` (划时代,在相隔5分钟后), `X-SIGNATURE` = 基数64 HMAC-SHA256(机密, `"<apiKey>:<path>:<timestamp>"`),在其中 `path` 这是 请求没有主机、正机或路径 `/__admin/ns/<name>` 前缀。 带有已知密钥 + 密钥 (单位:千美元)`--api-key/--api-secret` 或者说 `credentials` (b) 准确核实签名; 未配置任何密钥的签名会被接受,签名只检查形状。 遗产 模式 : `X-<Partner>-Auth-Key` (+ 数) `X-API-Version: 1.0`),例如. `X-Acme-Auth-Key`; 任何伙伴名称为 已接受。 失败者为401人 `{status: "ERROR", message}`。 。 。 .

**信封 (G- A1).** `AhaService` 期待原始数据 `{content, message, status}`· ; `AhaLabProvider` 预期 `{success: true, data: {…}}`。 Raw 是默认值;选择使用 `--envelope raw|wrapped` 或每个命名空间 `PUT /__admin/settings {"envelope": "wrapped"}`。 。 。 .

**引证无能.** `X-Idempotency-Key` (实验室提供路径):同一键和身体重放 存储的响应( e)`idempotent-replayed: true`; 不同身体的同一键为409.

### 网络呼号

`POST <webhook-url>` (我们的路线 : `POST /bloodwork/aha-webhook`与 `Authorization: Token <AHA_WEBHOOK_SECRET>`每一个身体都有 `status`, (中文(简体) ), `partnerOrderId`, (中文(简体) ), `ahaOrderId`, (中文(简体) ), 加上,按地位(顺序的IANA区所有当地时间):

| `status` | 额外字段 |
| --- | --- |
| `Scheduled`, (中文(简体) ), `Rescheduled` | **`scheduleServiceTime`** (单位:千美元)`YYYY-MM-DDTHH:mm:ss`,瞬间可解析)和 **`scheduleServiceTimeZone`** (IANA)——由我们的处理者要求,尽管没有参加DTO——加 `scheduledServiceDate/Time/TimeZone` 财务报告和审定财务报表 `scheduleConfirmationDate/Time/TimeZone` |
| `Check In` | `checkInDate`, (中文(简体) ), `checkInTime`, (中文(简体) ), `checkInTimeZone` |
| `Check Out` | `drawStatus` (默认) `Sample Collected`, (中文(简体) ), `drawStatusDate/Time/TimeZone` |
| `Lab Testing In Progress` | `dropOffDate`, (中文(简体) ), `dropOffTime`, (中文(简体) ), `dropOffTimeZone` |
| `Cancelled`, (中文(简体) ), `Non Scheduled Update` | —— 说 |

`drawStatus` 值 : `Sample Collected`, (中文(简体) ), `Completed` (拖动), `Patient Refused`, (中文(简体) ), `UTO`, (中文(简体) ), `Patient Not Home`, (中文(简体) ), `Patient Rescheduled`, (中文(简体) ), `Order Cancelled`, (中文(简体) ), `Others`, (中文(简体) ), `Patient Asked to Reschedule` (拖曳失败). 非-2xx 的答案被重审(立即,5 s, 5分30分2小时); `GET /__admin/webhooks`, (中文(简体) ), `…/events`, (中文(简体) ), `…/replay`, (中文(简体) ), `…/flush` 和往常一样.

### 管理员(超过标准合同)

| 路线 | 效果 |
| --- | --- |
| `POST /__admin/orders/:partnerOrderId/transition` | `{status, drawStatus?, scheduledAt?, timeZone?}` 发出网钩. `status` 以上为任何值(例和 `_` 原谅;未知值被逐字发送). `scheduledAt` (ISO 或 ocho ms) 默认命令的首选位置, 否则在接下来的 24 h出局 ; `Rescheduled` 默认为一天后. `timeZone` 默认命令 `patient_timezone`,则 `America/New_York`。 。 。 . `:partnerOrderId` 也可能是 `order_number`。 。 。 . |
| `PUT /__admin/settings` | `{envelope?, credentials?: [{apiKey, apiSecret?}], allowLegacy?, timestampToleranceMs?, defaultTimeZone?, cancelWebhook?, autoSchedule?: {afterMs, leadMs?} | ms | null}` 呼叫的命名空间. `GET` 让他们看到隐藏的秘密. |
| `POST /__admin/tick` | 释放所有 `autoSchedule` 在模拟器时钟上到期的 webhook( 已安装的模拟器每100 mss) . |
| `GET /__admin/orders` | 取名空间的命令(编号,状态,预约,区-没有病人数据). |

错误预设( E)`POST /__admin/faults {"preset": "<name>", "count"?: n}`: `bad_signature` (401个), `rate_limited` (429个) `rate_limit`, (中文(简体) ), `server_error` (500个), `order_error` (200个带内 `status: "ERROR"`, (中文(简体) ), `invalid_response` (200个身体,zod计划不接受), `webhook_duplicate`, (中文(简体) ), `webhook_reorder`, (中文(简体) ), `webhook_drop`。 。 。 .

### 命名空间

`x-mockingbird-namespace`页:1 `/__admin/ns/<name>` 前缀在 `AHA_API_URL` (签名仍涵盖 或 API 键: `PUT /__admin/credentials {"credentials": {"<AHA_API_KEY>": "<namespace>"}}`。 。 。 .

### SFTP 结果交付

`createAhaSftpServer` 从 `./sftp` 在麻黄端口启动真实的SSH/SFTP服务器并共享命令状态 `createRuntime`它支持密码或公用钥匙认证,主机钥匙验证, `list`编号 :`stat`, 二进制上下载, 原子临时文件重命名, 删除, 嵌入目录, 稳定的 POSIX 权限和仿真器时钟时间戳 。 决定性的 Ed25519 主机密钥在运行间稳定.

```ts
import { Client } from "ssh2"
import { createRuntime } from "@crvouga/mockingbird-service-aha"
import { createAhaSftpServer } from "@crvouga/mockingbird-service-aha/sftp"

// Test setup: the SFTP endpoint, sharing order state with the HTTP emulator, and one result.
const runtime = createRuntime()
const sftp = await createAhaSftpServer({
  runtime,
  accounts: [{ username: "aha", password: "local-test-password" }],
})
sftp.seed("/outbox/AHA-1001_result.pdf", new TextEncoder().encode("%PDF-1.4"))

// Application code: the ssh2 client it already uses. Only host, port and host key change.
const client = new Client()
await new Promise<void>((resolve, reject) =>
  client.once("ready", resolve).once("error", reject).connect({
    host: sftp.host,
    port: sftp.port,
    username: "aha",
    password: "local-test-password",
    hostVerifier: (key: Buffer) => key.equals(sftp.hostPublicKey),
  }),
)
const pdf = await new Promise<Buffer>((resolve, reject) =>
  client.sftp((error, session) => {
    if (error) return reject(error)
    session.readFile("/outbox/AHA-1001_result.pdf", (error, bytes) =>
      error ? reject(error) : resolve(bytes),
    )
  }),
)
client.end()
await sftp.close()
```

使用 `seed()` 安装任意的二进制固定件或 `publishResult(orderId, bytes)` 摆放一个稳定 `AHA-…_result.pdf` 内 `/outbox`。第一个完整的下载将链接的 HTTP 命令移动到 `Lab Testing In Progress` 并发布其网页;重复投票/倒数不重复这一过渡. `fault()` 强制下一场行动断开、拒绝许可、报告磁盘完整或只接受部分写入. `journal()` 曝光路径、 操作名称、 字节计数和结果—— 绝不是证书或文件内容 . `reset(namespace?)` 清除决定性文件系统状态。 复制目的地名称失败, 所以 `.tmp` ——最终更名为原子.

### 故意不模拟

-   下游S3摄入和 `aha_results_queue` sFTP 交接后处理.
-   真正的调度: AHA 联系病人; 除非测试转换顺序, 任何动作都不要动 或组合 `autoSchedule`。 。 。 .
-   可用- ZIP 列表(我们的应用程序在呼叫 AHA 之前,先决定资格).
-   患者细节经过验证,从未被存储或回放.
-   真正销售商使用的哪个信封(G-A1):两者都得到服务,每个命名空间一个.

## API 密码

| 导出 | 仁爱 | 说明 |
| --- | --- | --- |
| `AhaAPI` | 类 | 进程模拟器 : `fetch(request)`, (中文(简体) ), `reset()`, (中文(简体) ), `transition(id, {status, drawStatus?, scheduledAt?, timeZone?})`, (中文(简体) ), `tick()`, (中文(简体) ), `orders()`选项: `sqlite`, (中文(简体) ), `now`, (中文(简体) ), `namespace`, (中文(简体) ), `settings`, (中文(简体) ), `onWebhook`, (中文(简体) ), `wallClock`。 。 。 . |
| `createRuntime` | 函数 | 服务合同的模拟者。 选项 : `webhooks: {url, secret, retryDelaysMs?, fetch?}`, (中文(简体) ), `settings`, (中文(简体) ), `tickMs`, (中文(简体) ), `wallClock`, (中文(简体) ), `clock`, (中文(简体) ), `seed`, (中文(简体) ), `adminKey`, (中文(简体) ), `onLog`。 。 。 . |
| `AHA_PRESETS` | 对象 | 每个命名的断层预设. |
| `AHA_NAMESPACE` | 字符串 | 服务名称, `"aha"`。 。 。 . |
| `WEBHOOK_PATH` | 字符串 | `"/bloodwork/aha-webhook"`接收器的路线. |
| `ORDER_STATUSES`, (中文(简体) ), `DRAW_STATUSES` | 数组 | 销售商状况拼写了webhooks使用. |
| `verifyAuth` | 函数 | HMAC / 仿真器的遗留验证( 错误消息, 或 `undefined`) (中文(简体) ). |
| `apiKeyCredential` | 函数 | 请求所携带的 API 密钥( 如何使用证书映射来命名空间 ) . |
| `isTimeZone`, (中文(简体) ), `zonedParts`, (中文(简体) ), `zonedToEpoch` | 函数 | IANA-zone帮助器曾填补了本地日期/时间字段. |
| `document`, (中文(简体) ), `operationIds`, (中文(简体) ), `supportedOperationIds` | 数值 | 销售商为OpenAPI合同及其业务代号. |
| `createServer`, (中文(简体) ), `serveTarget`, (中文(简体) ), `DEFAULT_PORT` (单位:千美元)`./server`(中文(简体) ) | 节点 | 服务过来 `node:http` (表单每100毫秒勾出) `serve` CLI目标; 第8799口. |
| `createAhaSftpServer` (单位:千美元)`./sftp`(中文(简体) ) | 节点 | Real SSH/ SFTP 端点带有决定主机密钥/文件系统,共享顺序状态,传输控制,以及一个等离子端口. |

部分 [嘲笑鸟](https://github.com/crvouga/mockingbird)。 。 。 .

## 常见问题

### @crvouga/mockingbird-service-aha 是什么？

状态 AHA phlebotomy 仿真器, 上面有签名的 HTTP 命令, 状态 webhooks, 和真正的确定性 SSH/ SFTP 结果服务器 \.

### 如何安装 @crvouga/mockingbird-service-aha？

在项目目录运行 npm install @crvouga/mockingbird-service-aha，或使用 pnpm add / yarn add / bun add。它还提供命令行工具 mockingbird-aha，可以用 npx mockingbird-aha 直接运行。

### @crvouga/mockingbird-service-aha 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @crvouga/mockingbird-service-aha 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @crvouga/mockingbird-service-aha 可以商用吗？

@crvouga/mockingbird-service-aha 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @crvouga/mockingbird-service-aha 的下载量有多少？

根据 npm 官方下载统计，@crvouga/mockingbird-service-aha 在 2026/10/11 – 2026/11/09 这 30 天内被下载 16,247 次，日均约 542 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @crvouga/mockingbird-service-aha 还在维护吗？

最新版本 3\.11\.0 发布于 2026/11/11（今天）；至今共发布 42 个版本，其中过去 12 个月发布了 42 个；首次发布于 2026/09/23。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

