@crvouga/mockingbird-service-twilio

中文文档
3.11.0发布于 2026/11/11MITTypeScriptES Module构建来源已验证近 30 天下载 1.5万

Twilio 的状态仿真器, Lookup v2, Messageing and Recordings 在一个端口上, 并有签名的收发短信和语音网呼(Mockingbird 服务合同).

中文使用文档
文档目录10 节
  1. 安装
  2. 使用量
  3. 对准应用软件(G-T1)
  4. 在测试中读取检察官办公室
  5. 路线
  6. 网络呼声(S8.4)
  7. 管理员(超过标准合同)
  8. 命名空间
  9. 故意不模拟
  10. API 密码

@crvouga/mockingbird-service-twilio (英语)

本地模拟器。 真正的API合同. 部分 嘲笑鸟。 。 。 .

状态模拟器 特维利奥 测试套房: 查看 v2 手机验证, 校验 v2 手机 OTP (与真实的状态机器:错误的代码,尝试限制,在模拟器时钟上10分钟的过期), 可编程事件与发件箱,并呼叫录音。 也签下Twilio的字 输入短消息和语音网呼到你的应用程序。 每个产品都在一个港口上服务。 一个套房读取 检察官办公室来自行政飞机,而不是绕过核查(E2E_OTP_BYPASS_*) (中文(简体) ).

  • 行动范围: 支助
  • 合同openapi.yaml由Twilio的API 引用我们的消费者 打电话 搜索 v2 响应会被对照活的 API 检查字节 (单位:千美元)scripts/parity.ts,录入 test/fixtures/lookups.live.json) (中文(简体) ).

安装

npm install -D @crvouga/mockingbird-service-twilio

仅限无害环境管理。 节点 22或 Bun 1.2. 查询验证用途 libphonenumber-js (Twilio的电话) 寻找是libphone数字。 给它服务 npx mockingbird-twilio serve,与 createServer 从 ./server (节点),或与 createRuntime 在任何获取服务器中.

使用量

npx mockingbird-twilio serve --port 8798 \
  --app-url http://127.0.0.1:3000 \
  --public-base-url "$TWILIO_VOICE_WEBHOOK_BASE_URL" \
  --account-sid "$TWILIO_ACCOUNT_SID" --auth-token "$TWILIO_AUTH_TOKEN" \
  --caller-id "$TWILIO_VOICE_CALLER_ID"

对准应用软件(G-T1)

twilio-node为每种产品建立主机(api.twilio.com, (中文(简体) ), verify.twilio.com, (中文(简体) ), lookups.twilio.com) (中文(简体) ). 模拟器将主机作为第一个路径段 : {emulator}/api/2010-04-01/…, (中文(简体) ), {emulator}/verify/v2/…, (中文(简体) ), {emulator}/lookups/v2/…。通过时 new Twilio(...) a 一个 httpClient 重写 URL. twilioMockUrl 重写 :

import twilio from "twilio"
import { twilioMockUrl } from "@crvouga/mockingbird-service-twilio"
import { createServer } from "@crvouga/mockingbird-service-twilio/server"

const server = await createServer() // or process.env.TWILIO_API_BASE_URL, e.g. http://127.0.0.1:8798

type RequestOptions = Parameters<twilio.RequestClient["request"]>[0]

/** https://verify.twilio.com/v2/Services/VA…/Verifications → {base}/verify/v2/Services/VA…/Verifications */
class MockRequestClient extends twilio.RequestClient {
  override request(opts: RequestOptions): Promise<never> {
    const uri = twilioMockUrl(opts.uri, server.url)
    return super.request({ ...opts, uri }) as Promise<never>
  }
}

// The app's own Twilio client. Only its HTTP client changes.
const client = twilio("AC00000000000000000000000000000000", "fixture-token", {
  httpClient: new MockRequestClient(),
})
const lookup = await client.lookups.v2.phoneNumbers("+12025550123").fetch()
// lookup.valid === true, lookup.nationalFormat === "(202) 555-0123"
await server.close()

示例类型检查用twilio 5.13.1 或 后; 5.1.0 运行方式相同,但是它的 exports 地图隐藏打字方式 moduleResolution: nodenext。 。 。 .

模拟器也通过 Host 头曰. 满足它的要求 lookups.twilio.com (通过 DNS 覆盖或代理) 且没有前缀 /lookups/…。录音 适配器为生 fetch 联 合 国 https://api.twilio.com/2010-04-01/… 变成 twilioMockUrl(url, TWILIO_API_BASE_URL)。 。 。 . RecordingUrl 在网络呼声中保持犬形 https://api.twilio.com 格式,适配器检查.

在测试中读取检察官办公室

import twilio from "twilio"
import { twilioMockUrl } from "@crvouga/mockingbird-service-twilio"
import { createServer } from "@crvouga/mockingbird-service-twilio/server"

// Test setup: the emulator, and the app's Twilio client pointed at it as above.
const server = await createServer()
type RequestOptions = Parameters<twilio.RequestClient["request"]>[0]
class MockRequestClient extends twilio.RequestClient {
  override request(opts: RequestOptions): Promise<never> {
    const uri = twilioMockUrl(opts.uri, server.url)
    return super.request({ ...opts, uri }) as Promise<never>
  }
}
const client = twilio("AC00000000000000000000000000000000", "fixture-token", {
  httpClient: new MockRequestClient(),
})
const verify = client.verify.v2.services("VA00000000000000000000000000000000")

// The app sends the code.
const verification = await verify.verifications.create({ to: "+12025550123", channel: "sms" })

// The test reads it from the admin plane, the way a user reads the SMS.
const latest = await fetch(`${server.url}/__admin/verify/+12025550123/latest`)
const { code } = (await latest.json()) as { code: string; sid: string; status: string }

// The app checks it.
const check = await verify.verificationChecks.create({ verificationSid: verification.sid, code })
// check.status === "approved"
await server.close()

路线

路线行为
GET /lookups/v2/PhoneNumbers/{PhoneNumber}验证活 API 的编号( libphone number ) : valid, (中文(简体) ), validation_errors (单位:千美元)TOO_SHORT, (中文(简体) ), TOO_LONG, (中文(简体) ), INVALID_BUT_POSSIBLE, (中文(简体) ), INVALID_COUNTRY_CODE, (中文(简体) ), INVALID_LENGTH, (中文(简体) ), NOT_A_NUMBER, (中文(简体) ), phone_number, (中文(简体) ), national_format, (中文(简体) ), calling_country_code, (中文(简体) ), country_code, (中文(简体) ), url。每个数据包都是 null国家编号,无 CountryCode 必须是有效的美国号码,否则答案是 INVALID_COUNTRY_CODE. 虚构555-01xx数字有效.
POST /verify/v2/Services/{VA}/VerificationsTo (有效E.164,或 Channel=email, (中文(简体) ), Channel选项 CustomCode创建 VE… 使用6位码(或 fixedCode) (中文(简体) ). 再次发送到同一待核查的核查中,保留其编号和代码,并添加一个 send_code_attempts 输入。 第6局在10分钟内发送到一个号码是429 60203一个坏 To 为 400 60200不明服务编号(不是) VA + 32 十六进制)为 404 20404。 。 。 .
POST /verify/v2/Services/{VA}/VerificationCheckCode 加号 VerificationSid 或者说 To。右侧代码返回 200 approved, (中文(简体) ), valid: true。错误的代码返回 200 pending 并计数尝试。 第六张支票是429 60202。缺失、核准、取消或过期(模拟钟上10分钟)的核查为404 20404。 。 。 .
GET 编号 : POST /verify/v2/Services/{VA}/Verifications/{VE}获取验证,或设置 Status=canceled|approved 在一个.
POST /api/2010-04-01/Accounts/{AC}/Messages.jsonTo, (中文(简体) ), Body 或者说 MediaUrl,以及 From 或者说 MessagingServiceSid返回 201 SM… 锡德 (MM… rFC 2822 日期. MessagingServiceSid 只有状态 accepted, (中文(简体) ), from: null, (中文(简体) ), num_segments: "0" (尚未选择发件人). From 只有状态 queued。两者均保留,状态为 queued (Twilio在特定的发送器上排队). 没有一能键:同一体产生出另一个自相id. 出错:21604(无到发),21602(无到发),21603(无到发),21211(无效到发),21617(超过1600个字符). 消息被录入收发箱.
GET /api/2010-04-01/Accounts/{AC}/Messages/{SM}.json读取回函.
GET /api/2010-04-01/Accounts/{AC}/Messages.json该账户的最新第一信息资源 . PageSize 默认为50 (1-1000), PageToken 如下 next_page_uri编号 :previous_page_uri· ; Page 是客户状态。 链接保持供应商路径没有 /api,因此应用普通产品前缀重写. To 财务报告和审定财务报表 From 过滤存储的资源 .
GET /api/2010-04-01/Accounts/{AC}/Recordings/{RE}.wav录音为RIFF WAV. 与 RequestedChannels=2 你有两个渠道 否则双道录音被混为一谈,就像Twilio那样.
GET 编号 : DELETE /api/2010-04-01/Accounts/{AC}/Recordings/{RE}.json元数据,或删除(204;第二个删除是404,我们的消费者容忍它).

错误使用Twilio的身体, {code, message, more_info, status},与 X-Twilio-Error-Code。 。 。 . 认证为 HTTP Basic: a AC… (或 SK…)用户名和不空密码. 与 accounts (或 --account-sid 加号 --auth-token只有这些对被接受。 失踪或 错误的证书是401 20003。对于错误的符号,信息匹配活的: authentication failed, auth token is not valid for account AC…。 。 。 .

网络呼声(S8.4)

模拟器标志进入了网络 X-Twilio-Signature。签名为基数64 HMAC- SHA1( 自动令牌, 公共 URL + 排序) key+value 参数),与 twilio.validateRequest它的标志反对 公共基础 URL 应用程序配置 (单位:千美元)--public-base-url,也就是说. TWILIO_VOICE_WEBHOOK_BASE_URL),而不是本地主机地址它帖子 改为: Twilio不重试这些webhooks,所以仿真器每发一次.

触发员额有效载荷
POST /__admin/inbound/sms {from, body, to?, media?, messageSid?, params?}/messaging/inbound/smsMessageSid编号 :SmsSid (单位:千美元)SM…,或 MM… 与媒体), AccountSid, (中文(简体) ), From, (中文(简体) ), To (默认 : --caller-id, (中文(简体) ), Body, (中文(简体) ), NumMedia, (中文(简体) ), MediaUrl{i}, (中文(简体) ), MediaContentType{i}, (中文(简体) ), SmsStatus=received,, , , , , , , ,
POST /__admin/voice/twiml/admin/messaging/voice/twimlCallSid, (中文(简体) ), From=client:<uuid>, (中文(简体) ), To, (中文(简体) ), CallStatus=ringing 外加身体的田地(如:. conversationId(中文(简体) )
POST /__admin/voice/disclosure/admin/messaging/voice/disclosureCallSid, (中文(简体) ), CallStatus=in-progress
POST /__admin/voice/status/admin/messaging/voice/statusCallSid, (中文(简体) ), CallStatus=completed, (中文(简体) ), CallDuration
POST /__admin/voice/recording/admin/messaging/voice/recordingRecordingSid,犬类 RecordingUrl, (中文(简体) ), RecordingStatus=completed, (中文(简体) ), RecordingDuration, (中文(简体) ), RecordingChannels=2。它也存储一个双通道的WAV,所以下载工作.

每个体域都覆盖默认值. 管理员的回答列出了每个发送的应用程序状态 和反应机构(如:. <Response/>) (中文(简体) ). 事件类型 PUT /__admin/webhook-endpoints 过滤器是 sms.inbound 财务报告和审定财务报表 voice.{twiml,disclosure,status,recording}。 。 。 .

管理员(超过标准合同)

路线效果
GET /__admin/verify/:e164/latest{code, sid, status, to, channel, serviceSid, attempts, sendAttempts, createdAt, expiresAt} 最新核查到这个号码 这是测试如何读取检察官办公室.
GET 编号 : PUT /__admin/verify{fixedCode: "000000" | null, ttlSeconds, maxCheckAttempts, maxSendAttempts, sendWindowSeconds} 呼叫的命名空间.
PUT /__admin/lookups/:e164{valid, validationErrors?} 覆盖该号码的搜索( 验证和信件也使用它) . DELETE 删除覆盖 .
PUT /__admin/recordings/:RE上传一段录音:一个生的WAV体(content-type: audio/wav, (中文(简体) ), {"wavBase64": …},或 {channels?, seconds?} 用于合成8千赫16位音调.
GET /__admin/outbox?to=&since=&kind=sms|verify所有"同意":简讯{to, from, messagingServiceSid, body, sid})和每一次验证代码发送({code, body: "Your verification code is: …"}) (中文(简体) ).
GET /__admin/messages命名空间中的信件资源 .

错误预设( E)POST /__admin/faults {"preset": "<name>", "count"?: n, "latencyMs"?: n}; 以 GET /__admin/faults/presets,并读 hits 编号 : remaining 从 GET /__admin/faults) (中文(简体) ). 预设适用于调用命名空间. verify_5xx (开始和检查答案) 20500, (中文(简体) ), sms_drop_before_accept (Messages.json在信件存在前将套接字放下;仍然注册为 sms_socket_drop, (中文(简体) ), sms_accepted_then_socket_drop (信件和发件箱项被存储,然后套接字在任何响应字节之前关闭), sms_4xx (400个) 21211, (中文(简体) ), sms_429 (429个) 20429 与 Retry-After: 1, (中文(简体) ), sms_5xx (500个) 20500,没有 Retry-After, (中文(简体) ), sms_missing_sid (201人,其身体省略) sid收发箱里还有留言, lookup_5xx (503个) 20503; EMR 未打开), webhook_duplicate, (中文(简体) ), webhook_drop. Messages.json上的503是同一个有代码的信封 20503 财务报告和审定财务报表 Retry-After (标准过失,不是单独的预设). 状态断层没有存储信息.

命名空间

Twilio SDK 无法添加信头, 所以套房会选择命名空间 账户数字 : PUT /__admin/credentials {"credentials": {"<TWILIO_ACCOUNT_SID>": "<namespace>"}}名称空间 也可以来自 x-mockingbird-namespace 标题或一个 /__admin/ns/<name> 基础 URL 前缀 (单位:千美元)twilioMockUrl 保留前缀).

故意不模拟

  • 发送: 保留信息 queued编号 :accepted,没有发送状态回调(我们的消费者集没有) statusCallback),并且没有出现语音通话,会议或媒体流.
  • 信件收藏 DateSent 过滤器(模拟器从未发送消息).
  • 付费的搜索数据包( E)Fields=line_type_intelligence, (中文(简体) ), caller_name,)总是 null。 。 。 .
  • 接受和记录除短信以外的核查频道,但无任何消息。 校验 服务配置(代码长度、友好名称、速率限制桶)是全局的,设置为 PUT /__admin/verify。 。 。 .
  • 账户:任何 AC… sid是它自己的账户,而路径的 {AccountSid} 没有 与证书核对.
  • libphonenumber-js从它的元数据中去掉"局部"长度. 模拟器恢复它们 NANP (7)和 GB (4–6,8),这足以用于虚构的数字测试. 其他国家 可能回答 TOO_SHORT 特维利奥回答的地方 INVALID_BUT_POSSIBLE。 。 。 .

API 密码

导出仁爱说明
TwilioAPI类进程模拟器 : fetch(request), (中文(简体) ), reset(), (中文(简体) ), latestVerification(to), (中文(简体) ), resolveLookup(raw, country?), (中文(简体) ), setLookup(e164, override), (中文(简体) ), putRecording(sid, input), (中文(简体) ), outbox(), (中文(简体) ), messages()选项: sqlite, (中文(简体) ), now, (中文(简体) ), namespace, (中文(简体) ), verify, (中文(简体) ), accounts。 。 。 .
createRuntime函数具有完整服务合同的仿真器(健康,管理员,取名空间,证书,预设,出柜,网络呼号),外加主机路由. 选项 : app: {url, publicBaseUrl?, authToken, accountSid?, callerId?, messagingServiceSid?}, (中文(简体) ), verify, (中文(简体) ), accounts, (中文(简体) ), retryDelaysMs, (中文(简体) ), fetch, (中文(简体) ), clock, (中文(简体) ), seed, (中文(简体) ), adminKey, (中文(简体) ), onLog。返回的运行时间也有 inboundSms(input) 财务报告和审定财务报表 voiceWebhook(kind, params)。 。 。 .
TWILIO_PRESETS对象每个命名的断层预设.
TWILIO_WEBHOOK_EVENTS对象Webhook 事件类型 – 它所张贴的应用路径 .
twilioMockUrl函数重写上游 https://<product>.twilio.com/… URL 在模拟器基址上( 对于 G- T1 ) httpClient) (中文(简体) ).
TWILIO_PRODUCTS数组产品前缀服务于: api, (中文(简体) ), verify, (中文(简体) ), lookups。 。 。 .
lookup函数查找 v2 原始输入的验证( 选择在 a 中) CountryCode (b) 建立区域网络.
e164Key函数+ 和数字 : 管理员超过使用的密钥.
twilioError函数Twilio错误反应, {code, message, more_info, status}。 。 。 .
DEFAULT_VERIFY_SETTINGS对象验证缺省:10分钟过期,5次核对,每10分钟发出5个,随机编码.
DEFAULT_ACCOUNT_SID字符串证书为 API 密钥时使用的账户 .
TWILIO_NAMESPACE字符串服务名称, "twilio"。 。 。 .
synthesizeWav, (中文(简体) ), readWav, (中文(简体) ), mixDownToMono函数制作一款PCM WAV,读取其格式,将多通道的WAV混合到单相.
document, (中文(简体) ), operationIds, (中文(简体) ), supportedOperationIds数值销售商为OpenAPI合同及其业务代号.
createServer, (中文(简体) ), serveTarget, (中文(简体) ), DEFAULT_PORT (单位:千美元)./server(中文(简体) )节点服务过来 node:http; 数据 serve CLI目标; 第8798口.

部分 嘲笑鸟。 。 。 .

版本与发布记录

@crvouga/mockingbird-service-twilio 共发布 38 个版本,首次发布于 2026/09/23;过去 12 个月发布了 38 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
3.11.0latest2026/11/11今天
3.10.52026/11/038 天前
3.10.42026/11/038 天前
3.10.32026/11/038 天前
3.10.22026/11/038 天前
3.10.12026/11/038 天前

关于 @crvouga/mockingbird-service-twilio 的常见问题

@crvouga/mockingbird-service-twilio 是什么?

Twilio 的状态仿真器, Lookup v2, Messageing and Recordings 在一个端口上, 并有签名的收发短信和语音网呼(Mockingbird 服务合同).

如何安装 @crvouga/mockingbird-service-twilio?

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

@crvouga/mockingbird-service-twilio 支持 TypeScript 吗?

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

@crvouga/mockingbird-service-twilio 支持 ESM 还是 CommonJS?

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

@crvouga/mockingbird-service-twilio 可以商用吗?

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

@crvouga/mockingbird-service-twilio 的下载量有多少?

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

@crvouga/mockingbird-service-twilio 还在维护吗?

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