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

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

版本：3\.11\.0
npm 元数据更新时间：2026-11-11T02:50:59.812Z
中文译文更新时间：2026-11-11T09:56:08.720Z
软件包许可：MIT

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

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

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

- 包体积（解压后）：4.5 MB，18 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：2 个
- 首次发布：2026-09-23T00:03:15.239Z
- 最新版本发布：2026-11-11T02:50:59.428Z
- 近 30 天下载量：2319（2026-10-11 至 2026-11-09，npm 官方下载统计）
- 已发布版本数：38（近 12 个月 38 个）

## 中文简介

VPI复合药店API的邦化仿真器:JWT认证,产品,诊所,病人,提供者,保存"新处方"草稿和三页处方状态清单.

## 安装

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

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

## README

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

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

> \[尖叫声\] **我们的应用程序 `VPI_API_URL` 默认生产** (单位:千美元)`https://api.vpicompounding.net`,参见 `apps/backend/src/modules/erx/clients/vpi-api.client.ts`) (中文(简体) ). 未设置的变量发送真实 给真正的药店开处方 堆叠 **必须** 设定 `VPI_API_URL` 给此模拟器( 例如 ). `http://127.0.0.1:8802`只要VPI铁路可以到达.

国家模拟器 **妇女** 我们的后端驱动器是一个 只有草案的eRx铁路:JWT认证,产品分类/细节/折扣,日用品, 运输状况和费率、诊所地点、提供者、病人名册和详细情况, 供应商签名重复检查, `saveNewPrescription`,以及三页处方 状况列表 我们的传票人读取。 处方只在测试时才移动( 管理员) 页:1 我们的后端民意调查第1页(限制5).

-   行动范围: [支助](https://github.com/crvouga/mockingbird/blob/main/packages/service/vpi/SUPPORT.md)
-   供应商不公布具体内容:合同`openapi.yaml`)是从我们的客户手取出 佐德计划( zod schemas )`vpi-api.contracts.ts` 外加客户端- 本地策略 `vpi-api.client.ts`) (中文(简体) ). 接收测试用这些图案的逐字端口来分析每个模拟器的反应.

## 安装

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

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

## 使用量

将应用程序指向模拟器并给予其任何证书(任何对日志,除非 `accounts` 已设定 :

```bash
npx mockingbird-vpi serve --port 8802
# app env:
#   VPI_API_URL=http://127.0.0.1:8802           (REQUIRED: the default is production)
#   VPI_API_EMAIL=clinic@example.com  VPI_API_PASSWORD=anything
#   VPI_CLINIC_LOCATION_ID=65a1c0de00000000000000d1
```

```ts
import { createServer } from "@crvouga/mockingbird-service-vpi/server"

// Test setup: a local VPI.
const server = await createServer()
const baseUrl = server.url // the app's VPI_API_URL
const post = (path: string, body: unknown, headers: Record<string, string> = {}) =>
  fetch(`${baseUrl}${path}`, {
    method: "POST",
    headers: { "content-type": "application/json", ...headers },
    body: JSON.stringify(body),
  })

// Application code: the requests it sends to VPI.
const { jwtToken } = (await (
  await post("/accounts/authenticate", { email: "clinic@example.com", password: "x" })
).json()) as { jwtToken: string }
// …then POST /clinic/rxOrdering/saveNewPrescription (Bearer jwtToken) saves a draft…

// Test control: move it the way the pharmacy would; our poller maps each status.
await post("/__admin/prescriptions/66b200000000000000000001/transition", {
  to: "Order Completed",
  trackingNumber: "1Z999",
})

await server.close()
```

### 种子数据

每个命名空间开始于: 用户 `65a1c0de00000000000000a1` (每个登录都决定,除非 `accounts` 诊所 `65a1c0de00000000000000c1`,诊所位置 `65a1c0de00000000000000d1` ("Acme Main"),供货商格蕾丝·霍珀(NPI) `1234567893`编号 `65a1c0de00000000000000e1`)和艾伦·图灵(NPI) `1987654320`),患者艾达·洛芙蕾丝 (单位:千美元)`65a1c0de00000000000000f1`, DOB 1985-02-14, 1 Main St, Phoenix AZ 8504,并有4个产品: 睾丸酮 丙酮酸`64f1c2a9e4b0a1b2c3d4e5f6` 编号 : `2185_INJ`(a) 无菌,10%的门诊折扣, Se/ B6 特罗切(`3097_POW`,冷运), Enclomiphene(`4410_CAP`没有复合 和南德罗罗内(`5120_INJ`, (中文(简体) ), **控制**: 被拒绝 `saveNewPrescription`) (中文(简体) ). 将其中任何一项替换为 `createRuntime({ data: { products, providers, clinicLocations, patients } })`。 。 。 .

### 路线

| 路线 | 行为 |
| --- | --- |
| `POST /accounts/authenticate` | `{email, password, isPatientLogin: false}` → `{id, jwtToken, refreshToken}`. JWT有效载荷 `sub` (用户编号), `email`, (中文(简体) ), `iat` 财务报告和审定财务报表 `exp` = 模拟器- 时钟现在 + `tokenTtlSeconds` (默认360). 我们的客户缓存它直到 `exp` – 30 s,并在401上重新校正一次. `isPatientLogin: true` 被拒绝. |
| 其它路线 | 要求数 `Authorization: Bearer <jwtToken>`\- 失踪或被篡改 `Unauthorized`; 在模拟时钟上过期 ~ 401 `jwt expired`。 。 。 . |
| `GET /products/getAllFamiliesAndCategories` | `[{family, categories: [subCategory1…]}]`。 。 。 . |
| `POST /products/getProductsByCategory` | `{category, subCategory1}` → `[{subCategory2_item, commonNames: [{commonName, products: [...]}]}]`。 。 。 . |
| `GET /products/getProductDetailsByProductId/{id}` | 依据创用CC授权使用. `sigOptions`, (中文(简体) ), `reasonForCompoundedMedication`, (中文(简体) ), `patientPayAmount`, (中文(简体) ), `ndc` (数字) 404 如果未知的话. |
| `POST /products/getProductDiscountByProductIds` | `{clinicId, productIds}` → `[{id, productId, discountedPrice, unitPrice, discountedPercentage, controlledSubstance}]` 对已知产品. |
| `POST /products/calculateDaySupply` | `{productId, quantity, sig}` → `{daySupply, daySupplyReason}` (每个产品:每天1个;否则30个). |
| `GET /admin/rxOrdering/getShippingStates` | `{data: [{states: [{name: "Arizona", booleanCheck, nonSterile, sterile}]}]}` (全名;无无菌运输至阿拉巴马州或华盛顿特区). |
| `POST /portal/getShippingRate` | `{clinicId, clinicLocationId, patientId, productIds, shippingState: "AZ", isRushOrder}` → `{shippingMethod, rushOrderCost, rushOrderMethod, isSignatureRequired}`; 州级VPI的400不向. |
| `POST /clinic/rxOrdering/checkProviderSignatureNeededDuplicate` | `isDuplicate` 当同一病人和同一产品存在活性(未存档)处方时,则属实; `isProviderSignatureNeeded` 从设置( 默认为真) . |
| `POST /clinic/rxOrdering/saveNewPrescription` | 根据合同验证整个有效载荷(运输国必须是 **犬科全名**, (中文(简体) ), `controlledSubstance` 必须是 `"0"`——400个 `{message, errors: [{path, message}]}`(a) 未知的诊所/地点/提供者/病人/产品; 成功:草案 `Provider Signature Needed` 在不完整的清单中 `{message, prescriptionId, isRefillRequest: false, refillFromPrescriptionId: null}`。 。 。 . |
| `POST /patients/getPatientByPatientId`, (中文(简体) ), `…/getPatientAddressesByPatientId` | `{patientId, userId}` - 患者(`dateOfBirth`, (中文(简体) ), `phoneNumber`, (中文(简体) ), `cellPhone`),或 `{addresses: [...]}`。 。 。 . |
| `POST /patients/getPatientsInClinic` | `{clinicId, userId, limit, currentPage}` → `{pagination: {hasNextPage, currentPage, limit, totalCount}, patients}`。 。 。 . |
| `POST /staffs/getAllProvidersByClinicLocationId` | `{clinicLocationId, clinicId}` \* 供应商 `npi`。 。 。 . |
| `POST /clinicLocations/getClinicLocationByClinicLocationId` | `{clinicLocationId}` → `{id, clinicId, locationName, …}`。 。 。 . |
| `POST /clinic/rxOrdering/getIncompleteSavedPrescriptionsInClinicLocation`, (中文(简体) ), `…/getSubmittedPrescriptionsInClinicLocation`, (中文(简体) ), `…/getArchivedPrescriptionsInClinic` | `{clinicLocationId, userId, limit, currentPage}` 一页,最新一页 `{prescriptionId, prescriptionStatus, trackingNumber, patientId, createdAt}`每个信封 `statusEnvelope` (默认) `vendor`: 已提交 `{message: {prescriptions}}`,存档 `{message: [...]}` 有行键 `id`,不完整的光线阵列). |

### 生命周期和状况清单

| 过渡 `to` | 列表 | 我们的消费者地图 |
| --- | --- | --- |
| `Provider Signature Needed` (草案), `Signature Needed`, (中文(简体) ), `New Formula Pending` | 不完整 | 处理 |
| `Received`, (中文(简体) ), `Order Received` | 提交的 | 提交的 |
| `In Process`, (中文(简体) ), `Order In Process`, (中文(简体) ), `Prescriptions In Process`, (中文(简体) ), `On Hold`, (中文(简体) ), `Order On Hold` | 提交的 | 处理 |
| `Completed`, (中文(简体) ), `Order Complete`, (中文(简体) ), `Order Completed` (增加一个) `1Z…` 当未给出时跟踪编号) | 提交的 | 已运出 |
| `Cancelled`, (中文(简体) ), `Order Cancelled` | 存档 | 已取消 |
| `Archived`,或任何其他字符串(已使用逐字记录) | 存档/ 提交 | 未刷新( 无刷新) |

我们的消费者 **无已交付状态** vPI和铁路草案开始于 `processing`,所以一个 (b) 支付这种铁路运输的加工/发运(或取消).

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

| 路线 | 效果 |
| --- | --- |
| `POST /__admin/prescriptions/:id/transition` | `{to, trackingNumber?, list?: "incomplete" | "submitted" | "archived"}`。 。 。 . |
| `GET /__admin/prescriptions` | 取名空间的处方(只有标识和状态). |
| `POST /__admin/patients` | 种子诊所病人 `{firstName, lastName, dateOfBirth, email?, phoneNumber?, cellPhone?, id?, clinicId?, addresses?: [{addressLine1, addressLine2?, city, state, zipcode}]}` (VPI病人的创作不属于我们的客户). `GET` 列出他们. |
| `GET /__admin/catalog` | 产品、供应商和诊所地点. |
| `PUT /__admin/settings` | `{tokenTtlSeconds?, accounts?: [{email, password, id}], statusEnvelope?, isProviderSignatureNeeded?}`。 。 。 . |

错误预设( E)`POST /__admin/faults {"preset": "<name>", "count"?: n}`· ; `GET /__admin/faults/presets`: `token_expired` (401次授权电话 `count: 1` 我们的客户重新认证准确 一次复试成功, `unauthorized_twice` (重试也失败了), `auth_rejected`, (中文(简体) ), `server_error`, (中文(简体) ), `duplicate_prescription`, (中文(简体) ), `save_ambiguous_409` (保存草案,然后409:我们) 分类员说需要审查, `save_rate_limited` (429,未保存:需要 审查),, `save_400` (通过浏览器代理重试), `response_drift` (分类和产品细节字段更改类型: 我们的zod剖析失败关闭.

### 命名空间

`x-mockingbird-namespace`页:1 `/__admin/ns/<name>` 前缀在 `VPI_API_URL`,或者通过登录电子邮件: `PUT /__admin/credentials {"credentials": {"<VPI_API_EMAIL>": "<namespace>"}}` (JWT携带 电子邮件。 认证本身在默认名称空间( 或 `/__admin/ns/` 1); 符号 在每个命名空间进行校验.

### 故意不模拟

-   Webhooks:VPI没有;我们的后端民调.
-   患者创建、诊所违约卡计费(`encryptedBillingInfo`)和提供者签名: 我们的客户没有抓住这些合同, 通过行政API的种子病人.
-   刷新交换(我们的客户端用电子邮件/密码重新认证) .
-   实际定价、税费和运费率表:每名冷冻/消毒/冲刷的费率固定不变.
-   活目录:种子被合成到我们的客户端的域名中(没有沙盒记录).

## API 密码

| 导出 | 仁爱 | 说明 |
| --- | --- | --- |
| `VpiAPI` | 类 | 进程模拟器 : `fetch(request)`, (中文(简体) ), `reset()`, (中文(简体) ), `transition(id, {to, trackingNumber?, list?})`, (中文(简体) ), `addPatient(input)`, (中文(简体) ), `prescriptions()`选项: `sqlite`, (中文(简体) ), `now`, (中文(简体) ), `namespace`, (中文(简体) ), `seed`, (中文(简体) ), `settings`。 。 。 . |
| `createRuntime` | 函数 | 全面服务合同的仿真器(保健、管理、命名空间、证书、预设和日记)。 选项 : `data`, (中文(简体) ), `settings`, (中文(简体) ), `clock`, (中文(简体) ), `seed`, (中文(简体) ), `adminKey`, (中文(简体) ), `onLog`, (中文(简体) ), `sqlite`。 。 。 . |
| `VPI_PRESETS` | 对象 | 每个命名的断层预设. |
| `VPI_NAMESPACE` | 字符串 | 服务名称, `"vpi"`。 。 。 . |
| `tokenCredential` | 函数 | 无记名 JWT 携带的登录电子邮件( 如何绘制命名空间的证书地图 ). |
| `issueJwt` | 函数 | 模拟器接受的 JWT 薄荷 `{sub, email, iat, exp}`。 。 。 . |
| `DEFAULT_USER_ID`, (中文(简体) ), `DEFAULT_CLINIC_ID`, (中文(简体) ), `DEFAULT_CLINIC_LOCATION_ID`, (中文(简体) ), `DEFAULT_PROVIDER_ID`, (中文(简体) ), `DEFAULT_PATIENT_ID` | 字符串 | 被种子的标识. |
| `DEFAULT_PRODUCTS`, (中文(简体) ), `DEFAULT_PROVIDERS`, (中文(简体) ), `DEFAULT_PATIENTS`, (中文(简体) ), `DEFAULT_CLINIC_LOCATION`, (中文(简体) ), `SHIPPING_STATES` | 数值 | 种子数据. |
| `document`, (中文(简体) ), `operationIds`, (中文(简体) ), `supportedOperationIds` | 数值 | 销售商为OpenAPI合同及其业务代号. |
| `createServer`, (中文(简体) ), `serveTarget`, (中文(简体) ), `DEFAULT_PORT` (单位:千美元)`./server`(中文(简体) ) | 节点 | 服务过来 `node:http`; 数据 `serve` CLI目标(`--token-ttl`; 第8802号口. |

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

## 常见问题

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

VPI复合药店API的邦化仿真器:JWT认证,产品,诊所,病人,提供者,保存"新处方"草稿和三页处方状态清单\.

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

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

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

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

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

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

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

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

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

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

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

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

