@squady/whatsapp-relay
v0.1.0
Published
Lightweight TypeScript SDK for WhatsApp Relay supplier integrations.
Readme
@squady/whatsapp-relay
轻量 TypeScript SDK,用于供应商后端或 Companion App 代理层接入 WhatsApp Relay。
安全提示:生产环境不要把长期
supplierApiKey放进真实手表端或公开浏览器环境。浏览器 WebSocket 应优先使用 Relay 签发的短期eventToken。
初始化
import { createRelayClient } from '@squady/whatsapp-relay'
const relay = createRelayClient({
baseUrl: 'https://relay.example.com',
supplierApiKey: process.env.RELAY_SUPPLIER_API_KEY!,
deviceId: 'watch_001',
ownerUserId: 'user_123',
})发送文本回复
await relay.messages.sendText({
chatId: '[email protected]',
body: '收到',
})SDK 会自动带上:
X-Supplier-API-Key: ...
X-Device-ID: watch_001
X-Owner-User-ID: user_123ownerUserId 或 appId 至少传一个,用来形成 supplier_id + device_id + owner_context 归属边界,避免手表转让后沿用上一位用户的数据。
绑定与短期事件 Token
const preflight = await relay.auth.preflight({
owner_context: { user_id: 'user_123' },
})
if (preflight.can_start_bind) {
const binding = await relay.auth.startBind({
owner_context: { user_id: 'user_123' },
})
// show binding.qr_code, then poll binding.binding_id
}
const { token: eventToken } = await relay.auth.mintEventToken({
ttl_seconds: 300,
})账号资料与二维码
const profile = await relay.account.profile({
qrBase64: true,
})display_name、push_name、status_text 和 avatar 是 WhatsApp runtime 的 best-effort 字段,可能因为隐私设置或 WhatsApp Web 限制返回 null。图片组件不能附带鉴权 header 时,可以传 qrBase64: true 使用 contact.qr_image_base64。
会话与聊天
const sessions = await relay.sessions.list({ status: 'connected' })
const chats = await relay.chats.list({ sessionId: sessions[0]?.id, limit: 50 })
const messages = await relay.messages.listInChat({
chatId: chats[0].id,
limit: 50,
})按收件人发送
await relay.messages.sendTextTo({
recipient: '15551234567',
body: '收到',
})sendTextTo 会先调用 contacts.resolve。如果结果 ambiguous,SDK 会抛 RelayConflictError,不会自动猜测收件人。
补拉 missed events
for await (const event of relay.events.catchUp({
after: lastCursor,
limit: 100,
})) {
if (event.cursor && event.event_type !== 'heartbeat') saveCursor(event.cursor)
// message.new / message.status_updated / session.state_changed
}解绑与 WhatsApp Logout
await relay.auth.unbind({ session_id: 'sess_1' })
await relay.auth.logout({ session_id: 'sess_1' })unbind 只清理 Relay 本地 watch/device 路由绑定,不会把 WhatsApp linked device 从用户手机里移除。用户明确选择移除 WhatsApp 账号或退出登录时,使用 logout。
WebSocket 订阅
import { isMessageNewEvent } from '@squady/whatsapp-relay'
const stream = relay.events.subscribe({ eventToken })
for await (const event of stream.filter(isMessageNewEvent)) {
if (event.cursor) saveCursor(event.cursor)
console.log(event.data.body)
}错误处理
import { RelayApiError } from '@squady/whatsapp-relay'
try {
await relay.messages.sendText({ chatId, body })
} catch (error) {
if (error instanceof RelayApiError) {
console.log(error.code, error.retryable, error.details)
}
}