@voxbuddy/sdk
v0.1.1
Published
VoxBuddy 呼叫中心话机 SDK —— SIP(jssip)+ CTI 信令(WebSocket)封装,提供呼叫/转接/三方/静音/状态机等能力
Downloads
8
Maintainers
Readme
@voxbuddy/sdk
VoxBuddy 呼叫中心话机 SDK —— 封装 SIP(基于 JsSIP)+ CTI 信令(WebSocket),提供注册、呼叫、接听、挂断、转接、三方、静音、保持、话务状态机、连接健康监控与通话统计等能力,适用于浏览器与 Electron 等 WebRTC 运行环境。
特性
- SIP + WebRTC:基于 jssip 完成 SIP 注册与媒体协商。
- CTI 信令:request/response 自动配对、连接级心跳、断线指数退避重连(与 SIP transport 节奏对齐)。
- 话务状态机:IDLE / RINGING / CALLING / WRAPPING / UNREGISTERED,非法迁移告警、未接通异常自动检测。
- 强类型事件订阅:
phone.on(eventName, listener)的 eventName 与 payload 由PhoneEventMap收窄,拼写错误与 payload 误用编译期即报错。 - 多格式产物:ESM / CJS / UMD / IIFE,适配打包器、Node 与
<script>直引。 - 可配置日志:默认静默,不污染宿主日志;dev 可注入 console logger 观察信令细节。
安装
npm install @voxbuddy/sdk
# peer dependencies(UMD/ESM/CJS 不内联,由宿主提供)
npm install jssip eventemitter3若使用 IIFE 产物(
dist/sdk.iife.js),无需另装 peer 依赖——jssip / eventemitter3 已全量打包进 IIFE。
快速开始
import { Phone, createConsoleLogger, PhoneErrorReason } from '@voxbuddy/sdk';
const phone = new Phone({
registerHost: 'sip.example.com',
registerPort: 7443,
sipAccount: '1001',
sipPassword: '***',
ctiWsUrl: 'wss://cti.example.com/ws', // ⚠️ 生产 HTTPS 页面必须 wss://
phone: '1001',
password: '***',
optId: 'agent-001',
workStatus: 1, // 1=在线
isAutoSign: true, // 连接建立后自动签入
logger: createConsoleLogger('info'),
});
phone.on('login', (resp) => console.log('已签入', resp));
phone.on('callRing', (evt) => {
console.log('来电:', evt.detail.remoteCallNo);
});
phone.on('error', (err) => {
if (err.reason === PhoneErrorReason.CommandFailed) {
console.error('业务失败:', err.action, err.code, err.message);
} else if (err.reason === PhoneErrorReason.CallNotConnected) {
console.warn('呼叫未接通');
}
});
phone.dial('13800000000');集成方式
| 格式 | 产物文件 | 适用场景 |
| --- | --- | --- |
| ESM | dist/sdk.mjs | Vite / Webpack / Rollup 等打包器(推荐) |
| CJS | dist/sdk.cjs | Node require / 旧打包器 |
| UMD | dist/sdk.umd.cjs | 通用,需页面预先提供全局 JsSIP / EventEmitter3 |
| IIFE | dist/sdk.iife.js | <script> 直接引入,依赖已内联,开箱即用 |
IIFE 用法:
<script src="./sdk.iife.js"></script>
<script>
// 全局名为 VoxBuddyPhone
const phone = new VoxBuddyPhone.Phone({ /* IParams */ });
</script>配置参数(IParams)
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| registerHost | string | ✅ | SIP 注册主机 |
| registerPort | number | ✅ | SIP 注册端口 |
| sipAccount | string | ✅ | SIP 账号(不带域名) |
| sipPassword | string | ✅ | SIP 密码 |
| ctiWsUrl | string | ✅ | CTI WebSocket 地址(HTTPS 页面须 wss://) |
| phone | string | ✅ | CTI 登录分机号 |
| password | string | ✅ | CTI 登录密码 |
| optId | string | ✅ | 坐席 ID |
| workStatus | number | ✅ | 初始工作状态(1 在线 / 2 忙碌 / 3 会议 / 4 离线) |
| isAutoSign | boolean | ✅ | 连接建立后是否自动签入 |
| incomingRingUrl | string | — | 呼入本地铃声 wav URL(默认 sounds/ringback.wav) |
| outgoingRingbackUrl | string | — | 呼出本地回铃 wav URL(默认同呼入铃声) |
| logger | Logger | — | 日志器,默认静默(noopLogger) |
事件
事件订阅为强类型,eventName 与 payload 一一对应(见 PhoneEventMap)。常用事件:
| 事件 | payload | 说明 |
| --- | --- | --- |
| login / logout | CtiResponseMsg / void | 签入 / 签出 |
| error | PhoneErrorPayload | 业务/连接/未接通错误,按 reason 分流 |
| close | { reason: 'systemClose'; detail } | 服务端强制下线(重试无效) |
| reconnecting / reconnected | void | 通信层断开重连中 / 已恢复 |
| callRing / callAnswer / callHangup | 对应事件对象 | 通话生命周期(服务端驱动) |
| phoneStatusChange | { status: string; countDown?: number } | 话务状态变更(1 空闲 / 2 振铃 / 3 通话 / 4 整理 / 5 未注册) |
| countdown | { countdown: number } | 整理倒计时(每秒) |
| workDuration / ringDuration / callDuration | { duration: number } | 本地计时(秒) |
| stats | PhoneStatsPayload | 通话 RTC 统计 |
| agentInfo | AgentInfoPayload | 坐席信息查询结果 |
完整事件名联合见导出类型
PhoneEventType。
错误处理
SDK 提供两条错误通道:
error事件(统一收敛):payload.reason为PhoneErrorReason枚举值之一CommandFailed:CTI 业务请求失败(response code ≠ 0),携带action/code/messageCallNotConnected:状态机检测到振铃直接进整理(电话未接通),携带from/toConnectionError:通信层连接级失败,携带message
CtiError抛出:await业务方法(hold/transfer/hangup等)失败时 reject,可用instanceof CtiError判断并读取.action/.code/.message。
import { CtiError } from '@voxbuddy/sdk';
try {
await phone.hold();
} catch (e) {
if (e instanceof CtiError) console.warn(e.action, e.code, e.message);
}浏览器与环境要求
- 支持 WebRTC(
RTCPeerConnection)、WebSocket、navigator.mediaDevices.getUserMedia。 - 可用
Phone.checkIsSupported()与Phone.checkHasHeadset()做运行时探测。 - HTTPS 要求:麦克风权限仅在 secure context(HTTPS / localhost /
file://配合)可用;HTTPS 页面下 CTI/SIP 地址必须使用wss://,否则浏览器拦截 mixed content。
日志
默认 noopLogger(生产零噪声)。调试时注入:
import { createConsoleLogger } from '@voxbuddy/sdk';
new Phone({ ..., logger: createConsoleLogger('debug') }); // debug|info|warn|error也可实现自定义 Logger 接口接入业务日志系统。
API 参考
Phone类:login/logout/dial/answer/hangup/hold/unHold/transfer/threeWay/mute/unmute/workStatusChange/agentInfo/sendDtmf/destroy/getPhoneStatus,以及静态checkIsSupported/checkHasHeadset。- 完整类型签名见
types/index.d.ts,可由 IDE 自动补全。 - 后端 CTI WebSocket 协议字段定义见仓库内
api-doc.md。
发布(维护者)
本 SDK 采用 changesets 管理版本号与 CHANGELOG(替代已归档的 standard-version)。常规发版流程:
# 1. 记录本次变更(交互式生成 .changeset/*.md,描述语义类型 major/minor/patch 与说明)
pnpm changeset
# 2. 消费 changeset:按其声明的语义升版本号、更新 CHANGELOG.md、清理已消费的 .changeset
pnpm release:version
# 3. 发布到 npm:先触发 prepublishOnly(tsc -b 产类型 + vite build 产四格式产物),再 changeset publish
pnpm release:sdk说明:
- 仅
@voxbuddy/sdk会发布;其余@ri/*内部包均为private,已在 .changeset/config.json 的ignore中排除,不会进入发包流程。 prepublishOnly钩子在发布前自动同步生成类型声明(types/)与运行时产物(dist/,含 ESM/CJS/UMD/IIFE 四格式),杜绝发出过时的.d.ts。- 发版前请确认已
npm login且对@voxbuddyscope 具备发布权限;首次发布需带--access public(changesets 已由publishConfig.access: public自动处理)。 - CI 自动化可对接
changeset publish(配合NPM_TOKEN);本地手动发版同上。
License
Apache-2.0 © VoxBuddy
