@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}/Verifications | To (有效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}/VerificationCheck | Code 加号 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.json | To, (中文(简体) ), 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/sms | MessageSid编号 :SmsSid (单位:千美元)SM…,或 MM… 与媒体), AccountSid, (中文(简体) ), From, (中文(简体) ), To (默认 : --caller-id, (中文(简体) ), Body, (中文(简体) ), NumMedia, (中文(简体) ), MediaUrl{i}, (中文(简体) ), MediaContentType{i}, (中文(简体) ), SmsStatus=received,, , , , , , , , |
POST /__admin/voice/twiml | /admin/messaging/voice/twiml | CallSid, (中文(简体) ), From=client:<uuid>, (中文(简体) ), To, (中文(简体) ), CallStatus=ringing 外加身体的田地(如:. conversationId(中文(简体) ) |
POST /__admin/voice/disclosure | /admin/messaging/voice/disclosure | CallSid, (中文(简体) ), CallStatus=in-progress |
POST /__admin/voice/status | /admin/messaging/voice/status | CallSid, (中文(简体) ), CallStatus=completed, (中文(简体) ), CallDuration |
POST /__admin/voice/recording | /admin/messaging/voice/recording | RecordingSid,犬类 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口. |
部分 嘲笑鸟。 。 。 .