@sentinel-lab/video-protocol
v4.0.0
Published
Sentinel Video Player 契约层:Zod schema 定义命令 / 事件 / 错误码 / 配置,所有包的唯一事实源
Readme
@sentinel-lab/video-protocol
Sentinel Video Player 的契约层(L4)。定义 host ↔ iframe 的通信契约,所有其他包依赖它,它不依赖任何内部包。
唯一外部依赖:zod。
它定义什么
| 模块 | 内容 |
|:---|:---|
| version | CONTRACT_VERSION + 版本兼容判定 |
| envelope | 通信包裹:command / event / response / error |
| methods | 16 条命令(play / pause / seek / load / setSubtitle / pushDanmaku / …) |
| events | 20 个事件(ready / timeupdate / error / reconnectstart / subtitlechange / stalled / …) |
| errors | 29 个错误码 + 2 个警告码 + PlayerError |
| configs | MediaSource、PlayerConfig、poster / locale / danmaku / controls |
| presets | 1 个场景预设(homepage-preview,ADR-032)+ resolvePreset |
类型一律从 Zod schema 用 z.infer 推导,不手写 interface——避免 schema 和类型变成两套真相。
用法
import {
CommandSchema,
EnvelopeSchema,
eventEnvelope,
makePlayerError,
resolvePreset,
} from '@sentinel-lab/video-protocol'
// 收到消息:先 parse,再按 type 分支(TS 会自动收窄 payload)
const envelope = EnvelopeSchema.parse(rawMessage)
if (envelope.type === 'event' && envelope.payload.event === 'timeupdate') {
console.log(envelope.payload.payload.time)
}
// 构造错误:category / retryable 从 ERROR_META 推出,不接受调用方伪造
const err = makePlayerError('E_NETWORK', '拉流失败', originalError)
// 应用预设:显式传的字段永远覆盖预设默认值
const config = resolvePreset('homepage-preview', { source: 'a.m3u8', autoplay: false })
// → autoplay: false(显式值赢),muted: true(来自预设)几个容易踩的点
事件名是全小写连写(timeupdate / autoplayblocked),对齐 HTML5 媒体事件。这是 wire 上的名字;消费面各自映射——Vue emit time-update,React prop onTimeUpdate。(团队约定里的 snake.case 指埋点事件名如 playback.start,是另一套命名空间。)
retryable 是给自动重连看的信号,不是"用户能不能点重试按钮"。判断标准是:同样的请求原样再发一次,有没有可能得到不同结果。所以 E_AUTH_EXPIRED 是 false——SDK 不做签名刷新(ADR-022),原样重试必然再次失败。
source.onBeforeRequest 不在 wire 契约里。函数不可序列化,过不了 iframe 边界;它是宿主侧的 hook,由 inline 模式的 player-core 直接消费。且它在 MP4 和 iOS Safari 播 HLS 时不生效。
带 query 的 URL 推断不出类型。video.m3u8?token=xxx 必须显式传 type: 'hls',否则会走 MP4 路径。签名 URL 场景尤其注意。
type DrmConfig = never(ADR-014)。v1.0 不做 DRM,消费方传 drm 字段会直接编译报错,而不是运行时才发现没生效。
版本与冻结
当前 CONTRACT_VERSION = '1.0.0' —— 契约已冻结(2026-07-15,见 ADR-025)。现有 schema 不再破坏兼容。
兼容规则(host 和 iframe 用同一个 isContractCompatible):
0.x阶段(已过):minor 变更即破坏性 → minor 必须相同>= 1.0.0(当前):minor 是向后兼容的新增 → major 相同即兼容- patch 差异永远兼容
冻结后:新增 method / event / 可选字段走 minor bump(1.x 向后兼容);破坏兼容必须走 ADR + major bump。
测试
pnpm --filter @sentinel-lab/video-protocol test契约测试在 tests/(和 src/ 分开,方便冻结后独立管理)。其中 consumer-parity.contract.test.ts 拿 examples/team-video-vue/ 实际用到的事件 / 命令 / 错误码逐个校验——契约一旦漂移到验收基准用不了,它会先红。
