产品手册
包名
we-livesdk· 版本1.2.0· UMD 全局window.LiveSDK
浏览器端直播 SDK:拉流播放、IM 聊天、互动、商品营销、运营弹框,挂到一个容器即起一个直播间。本手册覆盖全部对外能力——每个配置、方法、事件、模块、Store。
实现状态图例:✅ 已实现 · 🚧 占位未实现(Phase 2) · ⚠️ 待服务端验证(payload 推断)
| 能力 | 实现 | 状态 |
|---|---|---|
| 视频(直播 + VOD 回放) | 腾讯云 TCPlayer | ✅ |
| IM 聊天 | 腾讯 IM @tencentcloud/chat |
✅ |
| 实时信令 | LAPS WebSocket @zan/laps,断线降级 HTTP 轮询 |
✅ |
| 服务端时钟 | config/detail + LAPS + 营销 HTTP 统一锚定,单调推进 | ✅ |
| 观看时长 / 任务上报 | WatchClock 真实媒体计时 + ordinary/Range 独立可靠 channel | ✅(服务端 fence/finalAck ⚠️) |
| 互动(点赞/礼物/分享) | 内置 app 模块 | ✅ |
| 商品列表 / 营销弹框 | entry 模块 | ✅(推送 payload ⚠️) |
| 运营浮层(券/抽奖/任务/讲解) | entry 模块 | ⚠️ |
| 主题 / i18n / 弹框 | 运行时 API | ✅ |
| 弹幕 / 水印 / 清晰度插件 | plugin | 弹幕/水印 🚧 · 清晰度 ✅ |
兼容:iOS 12+ / Android 7+ / Safari 12+(ES2017)。UMD 经 Babel 转译,无原生 ESM 依赖。
pnpm add we-livesdkimport { LiveSDK } from 'we-livesdk'import 'we-livesdk/styles'
const sdk = new LiveSDK({ activityId: 'xxx', token: 'xxx', merchantId: 'xxx', api: { baseUrl: 'https://api.example.com' },})await sdk.mount('#live-container')sdk.on('ready', ({ detail }) => { document.title = detail.title ?? '' })拉流地址与 IM 凭证由 SDK 凭
activityId + token + merchantId在mount()内自动认证拉取,无需手动传。仅用外部 IM 时才传tim。
宿主安全 ESM(路由级嵌入)
Section titled “宿主安全 ESM(路由级嵌入)”import 'we-livesdk/embed.css'
const { LiveSDK, DefinitionPlugin } = await import('we-livesdk/legacy')const sdk = new LiveSDK({ activityId, token, merchantId, api: { baseUrl }, bootstrap: { roomDetailPolicy: 'required', roomDetail: hostCachedRoomDetail, },})sdk.use(new DefinitionPlugin())await sdk.mount(target)we-livesdk/legacy 是无 CSS 副作用的单文件安全 ESM,首字节注入 iOS 12 polyfill;we-livesdk/embed.css 关闭 preflight,包含 SDK Tailwind utilities、构建期提取的 Svelte scoped 样式与 TCPlayer 播放器样式,并统一限制在 .livesdk-container 下。该入口供宿主构建器动态导入,不提供 window.LiveSDK 全局。
UMD(裸 HTML)
Section titled “UMD(裸 HTML)”<link rel="stylesheet" href="we-livesdk/styles.css"><script src="we-livesdk/dist-umd/livesdk.umd.js"></script><div id="live-container"></div><script> new LiveSDK.LiveSDK({ activityId: 'xxx', token: 'xxx', merchantId: 'xxx' }).mount('#live-container')</script>构建:pnpm build:umd → dist-umd/{livesdk.umd.js, livesdk.iife.js, livesdk.esm.js, livesdk.legacy.js} + dist/embed.css;UMD/IIFE 全局名 LiveSDK。
配置 SDKConfig
Section titled “配置 SDKConfig”new LiveSDK(config)。仅 activityId / token / merchantId 必填;缺失抛错。
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
activityId |
string |
✅ | 直播间 id | |
token |
string |
✅ | JWT 访问令牌 | |
merchantId |
string |
✅ | 商户 id | |
storeId |
number |
门店 id;房间营销 cmd 6010 上报透传,缺省按 0 |
||
api |
SDKApiConfig |
HTTP API 地址;运行时 api.baseUrl 优先于构建期 VITE_API_ENDPOINT,两者都缺失则认证 fail-closed |
||
endpoints |
EndpointConfig |
统一 HTTP / LAPS WS / 观看上报端点;优先于兼容字段和构建环境变量,可经 setEndpoints 动态更新 |
||
watchSession |
WatchSessionConfig |
可信登录/bootstrap 服务签发的观看会话上下文;缺失时不启用可靠任务上报 | ||
bootstrap |
SDKBootstrapConfig |
sdk-fetch |
mount 认证的房间详情启动策略;宿主缓存模式可固定为 required |
|
locale |
string |
'zh-CN' |
UI 语言,未知值告警回退 | |
entryModules |
AppEntryModuleId[] |
全部 | 启用哪些运营入口模块 | |
tim |
TIMConfig |
外部 IM 凭证;不传则认证自动注入 | ||
ws |
WSConfig |
WebSocket 配置;不配则降级 HTTP 轮询 | ||
wsUrl |
string |
⚠️ 已废弃,用 ws.url |
||
modules |
ModuleConfig[] |
全部 | 核心模块开关 { id, options? } |
|
appModules |
AppModuleConfigs |
全部启用 | 互动 app 模块开关 | |
options |
SDKOptions |
SDK 运行选项(日志、主题、i18n、浮窗图标可见性等) | ||
layout |
LayoutConfig |
横竖屏 / Tab / 快捷评论 | ||
telemetry |
TelemetryConfig |
关 | 遥测上报,须显式 enabled:true(见 SPEC-TELEMETRY-LOGGING) |
|
sensitiveWords |
string[] |
客户端敏感词;空则不过滤(fail-open) | ||
user |
{ nickName?, avatar? } |
宿主 IM 用户资料;levelId 由 ve/token 自动注入,宿主不传 |
||
features |
FeatureConfig |
{} |
业务 UI 可见性(按钮/入口开关);运行时可经 updateFeatures/setFeature 增量更新。零配置 = 今日行为(见下「业务特性配置」) |
|
uiTextSize |
UiTextSizeConfig(Partial<Record<UiTextSizeScene, 'default' | 'large' | 'xlarge'>>) |
{} |
场景级 UI 字号默认值(static 层)。集成方设的默认会被用户运行时选择覆盖(runtime > static > default,见下「字号档位」)。仅支持已登记场景,未声明的档位回退 large→default |
|
handlers |
{ redPacket?: RedPacketHandlers } |
宿主能力注入;红包读流程由 SDK 负责,提现/待收款确认等微信写动作交给宿主 |
SDKApiConfig:baseUrl?:string(协议 + host,可带或不带尾 /;内部会 trim 并移除尾 /)。所有 SDK HTTP 模块统一按 api.baseUrl → 构建期 VITE_API_ENDPOINT → fail-closed 解析,不含测试域名硬编码兜底。
EndpointConfig:apiBaseUrl?:string · wsUrl?:string · watchReportBaseUrl?:string。优先级:运行时 setEndpoints → 构造期 endpoints → 兼容字段 → 构建变量。ordinary/Range Adapter 分别追加内置 path,保留 base pathname(支持 SaaS 前缀);拒绝完整 URL、跨域、query/hash、凭据和路径穿越。HTTP/上报仅接受 https://,WS 仅接受 wss://。
WatchSessionConfig:watchSessionId:string · predecessorSessionId?:string · handoffCapability:'fence_v1'|'none' · predecessorFinalization:'successor_authorized'|'current_session_only'。必须由可信后端签发;SDK 不自行生成 predecessor 或宣称 fence 能力。⚠️ 服务端回显、finalAck 和 fence 协议须按宿主测试文档确认。
SDKBootstrapConfig:roomDetailPolicy?:'sdk-fetch'|'required' · roomDetail?:RoomDetailBootstrap。缺省 sdk-fetch 时 SDK 自行请求详情;required 时必须提供合法宿主缓存 seed,缺失、字段非法或房间/商户不匹配均认证失败,不会回退请求详情。
RoomDetailBootstrap:{ source:'host-cache', activityId:string, merchantId:string, detail:RoomDetailBody }。detail.id / detail.siteId 必须分别匹配 activityId / merchantId,liveStatus 必须为 101~108。
RedPacketHandlers:withdraw?:({amount})=>Promise<RedPacketHandlerResult> · confirmReceipt?:(record)=>Promise<RedPacketHandlerResult>,其中 RedPacketHandlerResult.status 为 'success'|'cancelled'|'fail'|'pending',可带 message。
TIMConfig:sdkAppId:number · userId:string · userSig:string · groupId:string
WSConfig:url:string · reconnectBaseDelay(1000) · reconnectMaxDelay(30000) · reconnectMaxAttempts(10) · heartbeatInterval(25000) · authTimeout(5000) · loginRetryMax(3)
WS 地址优先级:
ws.url→wsUrl(废弃) → 构建期VITE_WS_URL。三者均未配置时不连接 WS,降级 HTTP 轮询;没有内置测试地址兜底。线上务必显式传ws.url。
SDKOptions:origin?:string(保留字段,当前不参与 HTTP API 地址解析;请使用 api.baseUrl) · saveUserInfo?:boolean · logLevel?:'silent'|'error'|'warn'|'info'|'debug'(默认 warn) · theme?:SDKTheme · i18n?:Partial<I18nMessages> · floatingInteractionIcons?:{key:string,visible?:boolean}[](image-text-float 图标可见性锁;支持 SYS: 前缀;受控 key:QUESTION/QUESTIONNAIRE/CHECKIN/LOTTERY/LUCKYMONEY/COUPON;未配置默认可见,⚠️ 配置形状待服务端/集成方校验) · goodsMarketing?:{autoOpenExchangeCoupon?:boolean}(默认 false;false 时兑换券胶囊只发 goods.promotion.click、由宿主自开;true 时 SDK 已自开,宿主不得从该事件重复调用 openGoodsMarketing)
LayoutConfig:orientation?:'portrait'|'landscape'|'auto'(默认 auto,跟随后台 screenType) · playerFit?:'cover'|'contain'(作用于 <video> object-fit,直播 TCPlayer / VOD 回放均生效;缺省按朝向:竖屏 cover 铺满裁剪消黑边,横屏 contain 等比留黑边——对齐 SPEC AC-L-01) · topOffset?:number|string(顶部安全偏移,默认 0px;App 沉浸式嵌入时避让系统状态栏——TopBar / 公告跑马灯 / 营销活动面板顶部对齐到此值。number 按 px,string 允许 CSS length / calc / env。运行时可 setTopOffset() 覆盖) · chatTabs?:{key,label}[] · modulesOrder?:{chatOffset?} · shortcutComments?:(string|{text,delaySec?})[] · shortcutCommentsEnabled?:boolean(默认 true)
AppModuleConfigs:viewerCount · like · gift · goods · security,每项 { enabled?: boolean },默认全开。
TelemetryConfig(遥测 v3)
Section titled “TelemetryConfig(遥测 v3)”遥测与 options.logLevel 完全独立,默认关闭;仅 enabled:true 才启用。第三方 Transport 收到经过字段白名单、采样和裁剪的 v3 batch,其中 ctx.userKey 为明文。
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
enabled |
boolean |
false |
总开关 |
profile |
'off'|'errors'|'sampled'|'debug' |
enabled 时 sampled | 上报档位 |
endpoint |
string |
按 build mode | 与 transport 互斥;开发态冲突抛错,生产态关闭遥测并本地告警,不中断 SDK |
transport |
TelemetryTransport |
内置 HTTP/Beacon | 自定义单一 Sink |
identityMode |
'hash'|'plain+hash' |
hash | 废弃兼容字段;不再改变身份输出,ctx.userKey 始终为明文 |
experiments |
{id,variant}[] |
[] |
最多 16 项短 ID |
diagnostic |
{userKey,expiresAt} |
明文 userKey 精确匹配当前 ctx.userKey 且未来不超过 30 分钟时,才允许生产 100% 诊断采样 |
|
sampleRate |
number |
0.1 |
sampled 稳定采样;生产无有效 diagnostic 时最高 0.1,允许调用方降低 |
batchSize/flushIntervalMs |
number |
20/10000 |
条数/时间阈值 |
maxQueue/maxBytes |
number |
100/64KiB |
有界队列,硬上限不可提高 |
appContext |
TelemetryAppContext |
商户/房间/应用/构建/设备上下文;uid 作为明文 ctx.userKey,plaintextIdentity 为废弃兼容字段 |
appContext 会完整保留宿主传入的页面、应用、构建、引擎字段,SDK 仅用构造参数覆盖 merchantId/activityId。身份字段中,ctx.userKey 上报去首尾空白后的明文用户标识,ctx.deviceKey 继续上报 SHA-256 截断哈希,空用户不生成 userKey。内置 HTTP 使用 text/plain;charset=UTF-8,单批硬上限 48KiB;不上传 token、Cookie、评论正文、完整 URL/拉流地址、headers、原始 response 或 UA。sendBeacon=true 仅表示浏览器接受排队,不代表服务端落库。
遥测 v3 的完整解析对照表为 TELEMETRY-V3-REFERENCE.md。14/14 个事件的 payload 顺序、类型、单位、枚举/位图以及顶层 batch、ctx/stats/sidecars 字段均由同一 manifest 生成;严格解析器遇到未知 code、错误 arity、未知枚举/位图或未登记字段会直接失败,避免导出日志被静默错解。当前 funnel.summary 类型映射为 goods=1、coupon=2、task=3、checkin=4、reward=5、goodsMarketing=6。该门禁只要求客户端生成或导出的请求体可完整解析,不要求证明服务端已接收或落库。
AppEntryModuleId:'roomMarketing' | 'lottery' | 'taskReward' | 'productList' | 'commentary' | 'goodsMarketing'(roomMarketing = 房间营销统一入口,签到/福袋/券合流,见下「运营入口模块」/「事件 ws.room_activity」)
UiTextSizeConfig:Partial<Record<UiTextSizeScene, UiTextSizeMode>>,UiTextSizeMode = 'default' | 'large' | 'xlarge'。已登记场景:
| UiTextSizeScene | 说明 | default | large | xlarge |
|---|---|---|---|---|
im.comment.content |
评论正文 | text-sm/5 |
text-base/6 |
text-lg/7 |
im.comment.nickname |
评论 / 送礼 / 普通消息昵称 | text-sm |
text-base |
text-lg |
im.comment.level |
评论等级徽标 | text-[10px] |
text-xs |
text-sm |
im.comment.avatar |
评论头像(有头像评论的圆形头像尺寸) | h-[18px] w-[18px] |
h-[20px] w-[20px] |
h-[22px] w-[22px] |
im.welcome.content |
温馨提示标签与正文 | text-sm |
text-base |
— |
im.enter.content |
进场消息浮条 | text-xs |
text-sm |
— |
im.shortcut.content |
快捷评论按钮文案 | text-xs |
text-sm |
— |
im.order.content |
用户下单悬浮消息(昵称/商品/「立即购买」按钮) | text-sm |
text-base |
text-lg |
「更多面板」字体大小会全场景同档联动(评论 content/nickname/level/avatar + 温馨提示 + 入场 + 快捷评论 + 下单消息,详见下「字号档位」)。welcome/enter/shortcut 三场景仅支持
default/large两档;未声明的档位回退到large→default。
const sdk = new LiveSDK({ activityId, token, merchantId, uiTextSize: { 'im.comment.content': 'large', 'im.comment.nickname': 'large', 'im.comment.level': 'large', 'im.welcome.content': 'large', 'im.enter.content': 'large', 'im.shortcut.content': 'large', },})业务特性配置(features)
Section titled “业务特性配置(features)”config.features 统一收口业务 UI 可见性(按钮/入口是否渲染),与 appModules(WS 数据模块开关 / 数据源)正交:appModules.goods.enabled=false → 数据空、面板渲染空;features.goods['cart.open'].enabled=false → 面板在、购物车按钮隐。
FeatureKey = 该功能激活时 emit 的精确事件键(单一真相源,1:1 映射,无平行词表)。enabled:false 隐藏入口后,该事件无法由 SDK UI 触发。
| FeatureKey | 默认 | 说明 | 对应事件 |
|---|---|---|---|
topbar.userCenter |
true |
右上角「个人中心」入口 | topbar.userCenter |
topbar.businessInfo |
跟随 server | 右上角「经营信息」入口(默认回退 liveStore.businessInfoToggle) |
topbar.businessInfo |
goods.cart.open |
true |
商品橱窗标题栏「购物车」入口 | goods.cart.open |
goods.cart.add |
true |
橱窗列表卡「加入购物车」按钮(仍受积分商品/售罄门控叠加) | goods.cart.add |
goods.order.open |
true |
商品橱窗标题栏「订单」入口 | goods.order.open |
more.quality |
true |
「更多」面板清晰度入口 + 底栏更多按钮清晰度下标(仍受多档流 + DefinitionPlugin 门控叠加) | more.quality |
more.fontSize |
true |
「更多」面板字体大小入口 | more.fontSize |
more.cleanScreen |
true |
「更多」面板清屏入口 | more.cleanScreen |
more.redPacket |
true |
「更多」面板「我的红包」入口(emit 后 openRedPacket()) |
more.redPacket |
more.score |
true |
「更多」面板「我的积分」入口(宿主导航) | more.score |
more.coupon |
true |
「更多」面板「我的券码」入口(宿主导航) | more.coupon |
more.order |
true |
「更多」面板「我的订单」入口(宿主导航) | more.order |
more.feedback |
true |
「更多」面板「意见/反馈」入口(emit 后转发 topbar.feedback) |
more.feedback |
可见性优先级:运行时(setFeature/updateFeatures)> 构造期 config.features > 服务端兜底/默认。三层都未设 enabled 时回退最后一层 → 零配置即今日行为。
// 构造期:隐藏个人中心 + 橱窗购物车入口const sdk = new LiveSDK({ activityId, token, merchantId, features: { topbar: { userCenter: { enabled: false } }, goods: { 'cart.open': { enabled: false } } },})
// 运行时:增量更新(链式,emit features.update)sdk.setFeature('topbar.businessInfo', { enabled: true }) // 强显经营信息(覆盖 server off) .updateFeatures({ goods: { 'cart.add': { enabled: false } } })
sdk.getFeatures() // → 当前 static+runtime 合并快照FeatureConfig / FeatureItemOptions:namespace 分组(topbar / goods),leaf key = 事件键去首段命名空间(保留后续点,如 goods 组下 'cart.open')。FeatureItemOptions = { enabled?: boolean, order?: number, badge?: number, [key:string]: unknown }(order 等为前向兼容预留;badge 见下)。
入口数字 badge(badge)
Section titled “入口数字 badge(badge)”FeatureItemOptions.badge 给入口图标(购物车 / 订单)显示数字角标。badge 数字 host-owned(购物车/订单页在宿主侧):
- 静态初值:构造期
config.features.<key>.badge播种。 - 动态更新:运行时
sdk.setBadge(key, n)(专用 API,链式,emitbadge.update)。n<=0视为清空(无角标)。 - 显示规则:
n>0显示;n>99显示99+;0/未设 隐藏。
⚠️ badge 动态只走
setBadge,勿用setFeature({badge})(setFeature 管「可见性」,setBadge 管「计数」,职责分离)。setFeature({badge})不会生效到角标。
| BadgeKey | 说明 |
|---|---|
goods.cart.open |
商品橱窗标题栏「购物车」入口图标右上角标 |
goods.order.open |
商品橱窗标题栏「订单」入口图标右上角标 |
// 静态初值const sdk = new LiveSDK({ activityId, token, merchantId, features: { goods: { 'cart.open': { badge: 5 } } } })
// 动态更新(链式,emit badge.update)sdk.setBadge('goods.cart.open', 3) // 购物车角标 → 3 .setBadge('goods.order.open', 0) // 订单角标清空sdk.getBadge('goods.cart.open') // → 3其余 topbar 入口(feedback/redeem/redPacket/task/invite)暂未纳入,仍走各自 server toggle;后续按「扩展契约 SOP」(PLAN-FEATURE-CONFIG.md)迁移。底栏购物车按钮(
interact.cart,开橱窗)不纳入,已有actionbar.update动态覆盖。
| 方法 | 签名 | 说明 |
|---|---|---|
| 构造 | new LiveSDK(config) |
创建实例,初始化模块(未拉流/未挂载) |
mount |
(target: string|HTMLElement) => Promise<void> |
认证 → 注入凭证 → 挂载 UI → 初始化模块 → emit ready |
destroy |
() => void |
emit destroy,卸载 UI、断 WS/IM、清定时器与本实例弹框 |
on / off / once |
(event, handler) => this |
事件订阅(类型安全) |
getEmitter |
() => IEventEmitter |
取底层 emitter |
getServerTime |
() => number | undefined |
当前校准后的服务端 epoch 毫秒;首个有效服务端锚点到达前返回 undefined,不回退设备时间。锚点来自 config/detail.serverTime、LAPS serverTime / ws.room_config.serverTime,营销 HTTP timestamp 在未锚定时补充 |
getWatchProgress |
() => Readonly<WatchProgressSnapshot> |
本机真实媒体观看快照;含 total/byKind/state/sequence/reason,服务端任务进度不会写回 |
setEndpoints |
(partial: EndpointConfig) => Promise<this> |
动态更新端点;相同规范化值 no-op。HTTP 后续请求、WS 换址重连、观看上报后续周期/最终 flush 使用新值 |
getEndpoints |
() => Readonly<EndpointConfig> |
当前规范化端点快照,不含凭证 |
use |
(plugin: IPlugin) => this |
注册插件 |
getModule |
<T>(id: ModuleId) => T|undefined |
取核心模块实例 |
getAppModule |
<T>(id: AppEntryModuleId) => T|undefined |
取运营入口模块实例 |
setTheme |
(theme: SDKTheme) => this |
增量改主题,已挂载即施色 |
setThemeColor |
(color: string) => this |
便捷 = setTheme({primaryColor}) |
setFontSize |
(size: string) => this |
便捷 = setTheme({fontSize}) |
setUiTextSize |
(config: UiTextSizeConfig) => this |
增量设置场景字号(runtime > 构造期 uiTextSize),仅保留已登记场景与 default/large/xlarge 合法值;链式、mount 前可用。更多面板「字体大小」内部即用此方法批量联动 content/nickname/level/avatar 四场景 |
setUiTextSizeScene |
(scene: UiTextSizeScene, mode: UiTextSizeMode) => this |
单场景字号设置便捷方法;非法 mode 会被忽略 |
getUiTextSize |
() => Readonly<UiTextSizeConfig> |
当前场景字号快照(static+runtime 合并) |
setTopOffset |
(value: number | string) => this |
顶部安全偏移运行时设置(number 按 px;string 允许 CSS length / calc / env):归一化后写 store(runtime > static > 0px),emit topOffset.update {value};mount 前可用。TopBar / 公告跑马灯 / 营销活动面板顶部对齐到该值 |
getTopOffset |
() => string |
当前生效的顶部偏移(归一化字符串,如 '100px' / '0px';runtime > static > 默认) |
setCleanScreen |
(active: boolean) => this |
清屏态运行时切换:写 store + emit ui.cleanscreen.changed {active};active=true 进入清屏(隐全部业务 UI),false 退出;mount 前可用(store 构造期即建)。进房默认 false,不持久(刷新/重进重置) |
getCleanScreen |
() => boolean |
当前清屏态(true=清屏中,false=正常) |
updateFeatures |
(partial: FeatureConfig) => this |
增量更新业务特性(runtime 层深合并),emit features.update {partial};mount 前可用 |
setFeature |
(key: FeatureKey, options: FeatureItemOptions) => this |
单键便捷设置,emit features.update {partial, key};key = 对应事件键 |
getFeatures |
() => Readonly<FeatureConfig> |
当前特性配置快照(static+runtime 合并,不含服务端兜底) |
setBadge |
(key: BadgeKey, n: number) => this |
入口图标数字 badge 运行时设置(n<=0 清空),emit badge.update {key, value};mount 前可用 |
getBadge |
(key: BadgeKey) => number | undefined |
入口 badge 当前值(runtime > static;未设返 undefined) |
showLoading |
(text?: string) => this |
显示全局 loading(可选文案)。全局唯一 overlay,颜色跟随主题色 |
hideLoading |
() => this |
隐藏全局 loading |
modal |
(opts: ModalOptions) => Promise<boolean> |
打开本实例弹框,resolve 确认/取消 |
dialog |
(opts: ModalOptions) => Promise<boolean> |
modal 别名(命令式 Dialog 入口,复用 Modal 内核)。表单/snippet 注入为后续能力 |
toast |
(message: string, opts?: { duration?, type? }) => ToastHandle |
通用 toast(直采 svelte-sonner),返回 { id, dismiss() }。含 toast.success/error/warning(message)。直播结束自动清场本实例 toast |
showToast |
(opts: { content, duration?, mask? }) => this |
轻量 toast(小程序 wx.showToast 风格):全局单例——再次调用仅替换 content 并重置计时(不堆叠)。默认 duration=5000ms 自动关(<=0 不自动关);mask=true 渲染透明蒙层拦截底层点击(默认 false 不拦截);最多两行(line-clamp-2)、最大宽 90%、容器内顶层(z=100000,仅覆盖 SDK 容器,非整屏)。与 sdk.toast()(svelte-sonner 堆叠、整屏)独立并存。链式返回 this |
hideToast |
() => this |
隐藏轻量 toast(清计时)。链式返回 this |
t |
(key: I18nKey) => string |
取本地化文案 |
openGoodsMarketing |
(numIid, opts?:{scoreGoods?}) => void |
打开营销弹框,按 numIid 惰性拉取 |
closeGoodsMarketing |
() => void |
关闭营销弹框 |
claimMarketingCoupon |
(couponId: number) => void |
领取营销弹框内优惠券 |
loadMoreMarketingCoupons |
() => void |
加载更多兑换券(分页,对齐 goods-coupon-popup loadMore) |
registerMarketingSection |
(kind, component) => void |
注册营销 section 渲染器(未知 kind 不抛错) |
claimCoupon |
(packetId: string) => Promise<{status:'pickup'|'sendCompleted'}> |
实时券领取(券=福袋 type=1,上行 6010 + 等 6020 或 8s 乐观回退);委托 roomMarketing entry |
joinCheckIn |
(checkInId?: string) => void |
签到参与(省略 id → 取当前 active 签到)。乐观返成功,真实态由 6000/6020 幂等校正 |
joinLuckyPacket |
(packetId: string) => Promise<{phase:'attended'|'won'|'lost', awardAmount?}|undefined> |
福袋参与(等开奖结果或 8s 回退) |
setUiTextSizeScene |
(scene: UiTextSizeScene, mode: 'default' | 'large' | 'xlarge') => this |
单场景字号设置(runtime),同步持久化到 localStorage(key livesdk:uiTextSize),刷新/重进自动恢复;mount 前可用(见下「字号档位」)。注意:仅设单个场景(如 im.comment.content)时,昵称/等级/头像不会跟随——需整条消息统一放大请用「更多面板」或 setUiTextSize 四场景同设 |
getUiTextSize |
() => Readonly<UiTextSizeConfig> |
当前合并后的字号配置快照({...static, ...runtime}) |
只读属性:config(归一化配置)· i18n · stores(见下)。
mount()仅支持腾讯云直播(liveType=6),其它类型 emitauth.error中止;数据类降级 emitauth.warning不阻断。失败抛AuthError。
字号档位(uiTextSize)
Section titled “字号档位(uiTextSize)”| 显示文案 | mode | Tailwind class | 实际字号 |
|---|---|---|---|
| 默认 | default |
text-sm/5 |
14px |
| 中 | large |
text-base/6 |
16px |
| 大 | xlarge |
text-lg/7 |
18px |
- 作用范围:「更多面板」字体大小是整条 IM 消息的统一缩放——同时联动
im.comment.content(正文)、im.comment.nickname(昵称)、im.comment.level(等级徽标)、im.comment.avatar(头像)、im.welcome.content(温馨提示)、im.enter.content(进场浮条)、im.shortcut.content(快捷评论)、im.order.content(用户下单悬浮消息)八个场景,大字体下昵称/头像/温馨提示/进场/下单消息同比放大,避免只有正文放大的割裂观感。 - 持久化:用户选择写入
localStorage(keylivesdk:uiTextSize),刷新/重进自动恢复。 - 优先级:runtime(持久化) >
SDKConfig.uiTextSize(static) >default。 - mode
large显示为「中」:mode 值为公开契约不可改名,文案经 i18n 解耦。 - 单场景写入:集成方也可仅设
im.comment.content等单个场景(setUiTextSizeScene),未设场景回退default——此路径下昵称/头像/温馨提示/进场/下单消息不会跟随正文缩放,如需整条 IM 消息统一放大请全场景同设或用「更多面板」。
sdk.on(name, handler)。下表含 payload 类型。
核心 / 认证
Section titled “核心 / 认证”| 事件 | Payload | 触发 |
|---|---|---|
ready |
{detail: RoomDetailBody} |
mount 完成;detail 为直播详情对象(title 直播间名称 / liveStatus / extendSet.coverImg 封面 / planBeginDate 计划开播 等) |
destroy |
undefined |
destroy() |
error |
{code,message} |
全局错误 |
auth.success |
{streamUrl,qualityList} |
认证成功;qualityList 为服务端归一化清晰度列表 |
auth.error |
{code?,message} |
身份类失败,中止 mount |
auth.warning |
{reason,branch?:'configDetail'|'replayAddress'} |
数据类降级 |
| 事件 | Payload | 触发 |
|---|---|---|
live.status |
LiveStatus |
状态变更 |
live.orientation |
Orientation |
横竖屏确定 |
live.config |
Record<string,unknown> |
后台配置推送 |
live.thumb |
{thumb} |
点赞总数(LAPS 心跳/登录) |
live.startTime |
number |
预告计划开播时间(ms) |
live.coverImg |
string |
预告封面图 |
| 事件 | Payload | 触发 |
|---|---|---|
player.ready |
undefined |
可播 |
player.playing / player.pause |
undefined |
播放 / 暂停 |
player.waiting / player.stalled / player.recovered |
undefined |
缓冲 / 中断 / 恢复 |
player.firstframe |
undefined |
真首帧(一次性) |
player.ended |
undefined |
播放结束 |
player.error |
{code,message} |
播放错误 |
player.duration |
{duration} |
时长(VOD) |
player.timeupdate |
{currentTime} |
进度(节流 250ms,内部) |
player.replay.segment |
{index,total} |
回放切段 |
player.quality.changed |
{code,name} |
兼容事件:请求目标/回滚档位已改变,不代表目标流已经真实出帧 |
player.quality.switching |
{switchId,fromCode,toCode,name,reason} |
运行时切流事务开始;当前源继续播放,目标源开始隐藏预加载;reason 为 manual|downgrade|upgrade|decode-error |
player.quality.switched |
{switchId,code,name,reason} |
目标 generation 已取得真实进度并完成画面交换;新接入方应以此作为完成事件 |
player.quality.switch-failed |
{switchId,fromCode,toCode,name,reason,recovery,error} |
切流失败;recovery 为 rolled-back|next-lower|none,error 为可序列化 {code,message} |
player.quality.switch-cancelled |
{switchId,fromCode,toCode,name,reason,cause,supersededBySwitchId?} |
切流取消;cause 为 superseded|destroy|terminal |
player.quality.changed仅表示 SDK 的目标档位状态已经改变,是兼容旧事件;player.quality.switched才表示目标流真实出帧。推荐通过同一switchId的switching → switched/switch-failed/switch-cancelled判断完整生命周期。
同一事务对目标 URL 最多内部重试一次,并复用播放器的协议候选;重试不重复发 switching/changed。运行时切档保留当前播放器继续出画面,在隐藏、静音的 standby 播放器预加载目标源;目标取得 loadstart → playing → progress 证据后才交换显示层并释放旧播放器。音量/静音交接使用 Player 通过公开控制方法维护的缓存真值。预加载失败、超时或被新请求替代时只释放 standby,当前源不换源、不回切;非 superseded 取消还会把档位、URL 与 store 恢复为 confirmed 真值。切流期间调用 pause() 会同步暂停两个播放器并挂起提交/超时,调用 play() 后恢复事务。首次起播、VOD 与故障自愈仍是单播放器路径。
双槽位存在时,平台和声音状态均不改变预加载路径:iOS/WebKit 已开声、预加载中开声及微信桥接开声都继续保留 active 画面并预加载原 standby,不得对 active 直接换源。开声只同步声音真值;交换时不修改旧 active 的 muted 状态,旧 active 停止后再把缓存音量/静音应用到新 active。媒体画面层固定为
z-index: 0,控制条和水印覆盖层为z-index: 10;聊天输入仅由布局层ChatInput承载,Player 内不重复渲染Danmu输入框。
聊天 / IM
Section titled “聊天 / IM”| 事件 | Payload | 触发 |
|---|---|---|
chat.message |
ChatMessage |
新消息 |
chat.pinned |
ChatMessage|null |
置顶变更 |
chat.mute |
boolean|{muted} |
全员禁言开关 |
im.ready / im.reconnected |
undefined |
IM 就绪 / 重连 |
im.user_banned / im.user_kicked |
{userId,reason?} |
用户被禁言 / 踢出 |
im.error / im.net_error |
{code,message} |
IM 致命错误 / 网络断开 |
im.warning |
{code,message} |
缺凭证休眠告警 |
互动 / 用户 / 房间
Section titled “互动 / 用户 / 房间”| 事件 | Payload | 触发 |
|---|---|---|
interact.like |
{delta,count?,reaction?:ReactionKey} |
点赞帧 |
interact.like.total |
{total} |
点赞累计总数(角标权威源) |
interact.gift |
GiftPayload |
礼物 |
interact.cart / interact.share |
undefined |
底栏购物车 / 分享点击 |
interact.more |
{action?} |
底栏更多点击 |
user.join |
UserProfile |
用户进房 |
room.viewerCount |
{count} |
观看数(每 10s 轮询) |
| 事件 | Payload | 触发 |
|---|---|---|
goods.show |
GoodsItem |
展示商品卡 |
goods.hide |
{goodsId} |
隐藏商品卡 |
goods.list |
GoodsCardItem[](讲解品置顶 + 其余 seq 升序 + numIid 确定性 tiebreak;项含可选 marketingActivities 营销摘要) |
HTTP 首屏全量列表就绪 |
goods.list.error |
{message?} |
HTTP 商品列表拉取失败(fail-soft,橱窗内显重试入口) |
goods.list.retry |
undefined |
商品橱窗「重新加载」按钮点击 → SDK 触发 GoodsListFetcher 重新拉取首屏列表(host 可监听做埋点/二次处理) |
goods.buy |
{numIid,scoreGoods?} |
点购买/兑换按钮(列表卡 + 浮窗卡统一;host 接管下单) |
goods.card.click |
{numIid,name?,scoreGoods?} |
商品卡片整体点击(列表卡 + 浮窗卡空白区,购买/加车/促销按钮已 stopPropagation)。host 通常开商详页 |
goods.promotion.click |
{numIid,scoreGoods?} |
兑换券胶囊点击通知:autoOpenExchangeCoupon=false 时 host 可自开;true 时 SDK 已自开,本事件仅作通知/埋点,host 不得重复打开 |
goods.cart.add |
{numIid,scoreGoods?} |
列表卡「加入购物车」按钮点击(仅非积分商品、未售罄) |
goods.cart.open |
undefined |
商品橱窗标题栏「购物车」入口点击(host 开完整购物车页;区别于 interact.cart,后者由底栏购物车按钮发出、用于开橱窗) |
goods.order.open |
undefined |
商品橱窗标题栏「订单」入口点击(host 开订单列表) |
goods.config ⚠️ |
Record<string,unknown> |
商品配置推送 |
goods.open / goods.close |
undefined |
商品面板开 / 关 |
goods.marketing.open |
{numIid} |
营销弹框打开 |
goods.marketing.show |
MarketingDetail |
营销详情就绪(sections 可含 fullReduction 满减/满赠摘要,本地归一不发请求) |
goods.marketing.error |
{numIid,message?} |
营销拉取失败(可重试) |
goods.marketing.close |
undefined |
营销弹框关闭 |
⚠️ 行为变更(破坏性):浮窗卡(HotSellCard)购买按钮原外抛
interact.cart,现统一为goods.buy(与列表卡一致)。依赖浮窗卡interact.cart的宿主需迁移:改监听goods.buy做下单;如需开橱窗,监听底栏interact.cart。 事件冒泡约定:点购买 / 加车 / 促销按钮不触发卡片整体goods.card.click(已stopPropagation);点卡片空白区才触发。
兑换券入口与弹框(按 scoreGoodsInfo.useCouponType 分流)
积分商品(scoreGoods=true)的兑换券胶囊与 goods.marketing.* 弹框按 useCouponType 三态分流,对齐 live-app:
useCouponType=1(商品券):入口胶囊数量取scoreGoodsInfo.couponNum;弹框标题「可用兑换券」,并行请求分页券列表(loadMoreMarketingCoupons加载更多)与用户已有数量,提示行展示「需要 X 张 / 已有 Y 张」(mine缺失或请求失败按0,不整行隐藏),券卡片显示「已获得」;不展示万能券提示。useCouponType=2(普通券+万能券):入口胶囊数量累加内联scoreGoodsInfo.couponList计数;弹框标题「商品所需兑换券」,直接归一/合并/过滤零计数内联列表(不发分页与已有数量请求),不展示「需要/已有」「已获得」;supportUniversalCoupon=true时展示「数量不足可使用万能券」提示。内联列表为空时不渲染胶囊。useCouponType=0/空(不使用):不渲染兑换券胶囊、不打开兑换券弹框(即便couponNum/couponList有值)。
向后兼容:商品不在列表(上下文
found=false)且scoreGoods=true时程序式openGoodsMarketing回退为类型 1 分页分支(旧 SDK 行为),不因上下文缺失抛错;found=false且scoreGoods=false走普通优惠券couponsection。autoOpenExchangeCoupon默认值与goods.promotion.click语义不变。
房间营销(roomMarketing:签到 / 福袋 / 券)
Section titled “房间营销(roomMarketing:签到 / 福袋 / 券)”LAPS 6000/6010/6020 + HTTP 79952 首屏 → lapsBridge 收敛为单一事件族 ws.room_activity(判别联合 RoomActivityOp),由 RoomMarketingEntry → roomMarketingStore.dispatch 驱动 cards / 弹窗队列 / 服务端时钟。参与经 sdk.claimCoupon / joinCheckIn / joinLuckyPacket(见上「实例方法」)。
| 事件 | Payload | 触发 |
|---|---|---|
ws.room_activity |
RoomActivityOp(判别联合:coupon_create / lucky_create / checkin_start / checkin_end / display / finish / result) |
6000 签到/福袋建卡显隐结束、6020 本人开奖结果(仅本人 agentId 命中)。券=福袋 type=1,create 由 luckyPacket.type 路由,display/finish/result 按 cards[id].kind 回查路由 |
ws.server_time |
number(服务端毫秒) |
每帧服务端时钟锚定 → roomMarketingStore.setServerTime(同钟铁律:倒计时基准与锚点同源同 floor) |
ws.reconnect |
{attempts} |
重连 → resync(15s cooldown + in-flight 合并 + pruneGhost + 重拉首屏建卡) |
互动工具聚合抽屉(FloatMoreDrawer):FloatBar「更多」点击后立即打开 60% 高度 contained 抽屉(overlayVariant=light),同时触发 SDK 内部 _refreshInteractiveTools() 静默拉取 79952 并 reconcilePrime(不自动弹详情)。列表数据来自 roomMarketingStore.interactiveItems(签到/福袋/券时间轴);点击卡片仅 show(id),抽屉保持打开,详情层(CouponLayer/CheckInLayer/LuckyLayer)外壳 z-[1200] 覆盖抽屉。刷新失败保留旧列表;refreshing 仅显示非阻塞指示器。无公开刷新 API。
⚠️ 已废止事件(ActivityPanel/liveStore.coupons 体系,勿监听):
activity.change/activity.result/activity.participate(旧签到福袋面板,已删 ActivityPanel);coupon.show/coupon.open/coupon.close(旧 CouponStack 徽标链路,已归roomMarketingStore.floatItems);ws.coupon_dispatch(旧 6000/6020 回落通道,已归ws.room_activity)。
左上角营销互动浮窗(image-text-float)⚠️
Section titled “左上角营销互动浮窗(image-text-float)⚠️”| 事件 | Payload | 触发 |
|---|---|---|
imagetext.change |
ImageTextChange |
LAPS check.in.* / lucky.packet.* 映射为浮窗数据变更;内部 ImageTextEntry 消费 |
imagetext.entry.click |
{type,current,stableKey} |
用户点击浮窗图标;ImageTextEntry 路由到对应面板,集成方也可监听自定义面板 |
imagetext.icon.close |
{stableKey,type} |
用户关闭单个浮窗图标 |
imagetext.more.click |
undefined |
用户打开「更多」抽屉 |
checkin.show / checkin.close |
{currentId} / undefined |
签到图标点击 / 签到面板关闭 |
checkin.detail |
CheckInDetail |
签到详情拉取成功 |
checkin.submit_result |
{success,message} |
签到提交结果 |
checkin.kickout |
{banTips} |
截止未签到且活动要求禁止观看 |
观看时长 / 应用模块
Section titled “观看时长 / 应用模块”| 事件 | Payload | 触发 |
|---|---|---|
watch.progress |
WatchProgressSnapshot |
真实媒体证明、状态或累计变化;服务端秒数不写回 |
watch.state.changed |
{previous,current,snapshot} |
idle/watching/suspended/ended 状态变化 |
watch.report.calibration.* |
WatchReportEventMeta |
校准开始、ACK、stale、失败或 best-effort 降级 |
watch.report.queued/attempt/retry/ack/rejected/parked |
WatchReportEventMeta |
ordinary/Range 上报漏斗(脱敏元数据) |
watch.report.exit.queued/kickout.queued/finalize.error/final.abandoned |
WatchReportEventMeta |
退出、踢出与最终对账诊断 |
duration.change |
{totalMs,seconds} |
废弃兼容别名;WatchClock 每跨 5s 映射一次 |
duration.report |
{seconds,success} |
废弃兼容别名;仅 ordinary 逻辑 ACK/终态失败 |
app.module.init / app.module.destroy |
{moduleId} |
app 模块生命周期 |
| 事件 | Payload | 触发 |
|---|---|---|
features.update |
{partial: FeatureConfig, key?: FeatureKey} |
updateFeatures(无 key)/ setFeature(带 key)后 emit |
badge.update |
{key: BadgeKey, value: number | undefined} |
setBadge 后 emit;value=undefined 表示清空(n<=0) |
topOffset.update |
{value: string} |
setTopOffset 后 emit;value 为可直接用于 CSS 的归一化长度串(如 '100px') |
ui.cleanscreen.changed |
{active: boolean} |
setCleanScreen 后 emit;active=true 进入清屏(隐全部业务 UI),false 退出 |
WebSocket
Section titled “WebSocket”| 事件 | Payload | 触发 |
|---|---|---|
ws.connected / ws.disconnected |
undefined / {reason?} |
连接 / 断开 |
ws.reconnect |
{attempts} |
重连尝试 |
ws.error / ws.auth_failed |
{code,message} |
WS 错误 / 认证失败 |
ws.room_status |
{status,reason?} |
5000 房间状态 |
ws.room_config |
Record<string,unknown> |
5010 房间配置 |
ws.kicked |
{roomId,reason?} |
1001 强制移出 |
ws.enter_message |
{roomId,data:{type,content}} |
5020 进场消息 |
ws.audience_change |
{agentId,roomId,eventType,eventData?} |
2020 观众变更(1禁言/2取消/3封禁/4踢出) |
ws.message / ws.server_time |
WSMessage / number |
原始帧 / 服务端时间(内部) |
ws.commentary ⚠️ / ws.goods_config ⚠️ |
Record<string,unknown> |
讲解 / 商品推送 |
运营入口(⚠️ payload 推断)
Section titled “运营入口(⚠️ payload 推断)”| 事件 | Payload |
|---|---|
lottery.start / task.new / commentary.push |
Record<string,unknown> |
lottery.open|close · task.open|close · commentary.open|close |
undefined |
⚠️
coupon.show/coupon.open/coupon.close/ws.coupon_dispatch已废止(券归ws.room_activity+roomMarketingStore)。 完整事件名常量见导出的SDK_EVENTS。
type LiveStatus = 'not_started'|'ongoing'|'ended'|'banned'|'paused'|'error'|'expired'|'playback'// 对应服务端 102/101/103/104/105/106/107/108// not_started(102 预告态) 仍展示 IM 聊天模块,支持用户聊天;结束/禁播/异常等阻断态仍展示状态遮罩。type ReactionKey = 'heart'|'ghost'|'qbox'|'rockhand'|'joystick'
interface ChatMessage { id; userId; userName; userAvatar?; content; timestamp type: 'text'|'system'|'pinned'|'enter'|'welcome'|'comment' template?; level?; levelName?; levelColor?; levelIcon?; welcomeTitle? // 等级/欢迎语扩展}interface GiftPayload { giftId; giftName; giftIcon?; userId; userName; count }interface GiftAnimation { userId; giftId; giftName; count; timestamp }interface UserProfile { userId; userName; avatar?; level? }interface GoodsItem { id; name; price; image?; url?; sellOut?; priceHidden? }interface GoodsCardItem { numIid; name; price; image; url?; explainStatus; floatingStatus; sellOut; priceHidden; hasPublish; hotNum; reminderType; reminderText?; quantity?; seq?; tags?; isPresell?; goodsType?; scoreGoods?; scoreGoodsInfo?; marketingActivities?; supportUniversalCoupon? }// GoodsCardItem.scoreGoodsInfo(积分商品详情,scoreGoods=true 时存在):// score?; price?; couponNum?; couponName?; couponId?; couponList?; exchangeNum?; limitNum?// useCouponType?: 0|1|2 —— 0/空=不使用(无兑换券胶囊/弹窗)、1=商品券(couponNum + 分页接口,列表态 couponList=null)、// 2=普通券+万能券(列表态内联 couponList,实测项 {couponNum,couponId,couponName};code/consumeNum/count/name 可选未下发)// couponList[] 项:{ couponNum?; couponName?; couponId?; code?; consumeNum?; count?; name? }// GoodsCardItem.supportUniversalCoupon?: boolean —— 是否支持万能券(商品项顶层;仅 useCouponType=2 消费;缺失→false)interface MarketingActivity { actId; actType; actName } // 商品关联营销摘要(goodsCard/get marketingActivities 内联,仅三字段,无明细)interface FullReductionSectionData { activities: MarketingActivity[] } // fullReduction section 数据(v2 摘要级)// 兑换券(积分商品)section 数据;ExchangeCouponSectionData.couponType 决定渲染分支interface ExchangeCouponSectionData { coupons: Array<{ couponNum?; couponName?; name?; couponId?; code?; consumeNum?; count? }> couponType?: 1 | 2 // 1=商品券(分页)/2=普通券+万能券(内联);marketingApi 必填,驱动渲染分支 count: number // 商品所需兑换券总数(type1=scoreGoodsInfo.couponNum / type2=sum(couponList)),非券种数 mine?: number // 用户已持有数(mySelfCouponNum;仅 type1) isSupportUniversalCoupon?: boolean // 是否展示万能券提示(仅 type2) hasMore?; pageNo?; loadingMore?; loadMoreError? // 分页(仅 type1)}interface LikeBurst { id: number; reaction: ReactionKey; count: number }interface SDKError { code: number; message: string }核心模块(getModule)
Section titled “核心模块(getModule)”sdk.getModule<T>(id),id ∈ liveRoom|player|im|interact|user|marketing|security。
player ✅
Section titled “player ✅”| 方法 | 说明 |
|---|---|
play() / pause() |
播放 / 暂停 |
setVolume(v) |
音量 [0,1] |
seek(time) |
跳转(仅 VOD) |
attachElement(el) |
绑定 video 元素 |
initStream(url) |
手动设流地址并起播 |
setReplayList(list) / getReplayList() |
注入 / 取回放分段 |
currentReplayIndex / isVodPlaying / isReplay |
只读 getter |
能力:直播 HLS/FLV(TCPlayer)+ VOD 多段回放(分段容错、整轮重试 3 次、15s 超时探测);直播错误指数退避重连。
| 方法 | 说明 |
|---|---|
sendTextMessage(text) |
发文本 |
sendCustomMessage({type,data?,description?}) |
发自定义消息 |
sendLikeMessage(count?) / sendGiftMessage(gift) |
发点赞 / 礼物 |
getHistoryMessages(count=20) |
拉历史 |
getOnlineCount() / getLikeCount() |
在线数 / 点赞数 |
getAdapter() |
取适配器(userSig 重登用) |
setCredentials(creds) |
注入 IM 凭证(init 前) |
凭证优先级:config.tim > 认证注入。缺凭证 → emit im.warning 并休眠。
interact ✅
Section titled “interact ✅”sendLike(count?) · sendGift(gift)(IM 不可用时降级本地 emit)。
user ✅
Section titled “user ✅”| 方法 / 属性 | 说明 |
|---|---|
setProfile({ nickName?, avatar? }) |
运行时更新昵称 / 头像并 sync 到 TIM updateMyProfile |
refreshUserSig(newSig) |
userSig 过期重登 |
setUserId(id) |
设置 userId |
userName · avatar · levelId |
只读;levelId 来自 auth ve/token.agentLevelId,不可宿主注入 |
构造期可通过 config.user 注入昵称 / 头像;mount 时与 JWT 昵称合并(宿主 > JWT > userId)。发评时 TIM cloudCustomData 只附 { levelId },收端用 live.memberLevels 匹配等级徽章。
const sdk = new LiveSDK({ activityId, token, merchantId, user: { nickName: '小明', avatar: 'https://...' } })await sdk.getModule('user')?.setProfile({ avatar: 'https://new-avatar.png' })liveRoom ✅
Section titled “liveRoom ✅”无 host 方法;init() 内拉房间元数据并 emit live.* / room.viewerCount。状态码 101–108 → LiveStatus。
marketing 🚧
Section titled “marketing 🚧”showGoodsCard(goodsId) · hideGoodsCard() —— 占位空实现(Phase 2)。当前商品能力走 entry 模块 productList/goodsMarketing。
security 🚧
Section titled “security 🚧”setWatermark(text) · clearWatermark() —— 占位空实现(Phase 2)。
互动应用模块(appModules)
Section titled “互动应用模块(appModules)”构造期实例化,config.appModules.<key> = { enabled:false } 可关。默认全开。
| 模块 | key | 方法 / getter | emit |
|---|---|---|---|
| ViewerCount ✅ | viewerCount |
count · setCount(n) |
room.viewerCount |
| Like ✅ | like |
total · like(userId,delta=1) |
interact.like.total |
| Gift ✅ | gift |
queue · sendGift(p) · dequeue() |
interact.gift |
| Goods ✅ | goods |
visibleGoods · show(g) · hide(id) |
goods.show / goods.hide |
| Security ✅ | security |
isContentAllowed(c) · checkRateLimit(uid) |
— |
- Like:
live.thumb(服务端权威)+interact.like(增量)合并算总数。 - Security(app 层,区别于 core security 🚧):聊天限流 10 条/秒 + 非空校验。
- WatchClock ✅(Player 内部,非 appModules):播放意图 + 真实媒体进度双门控,live/replay 分项、source epoch、watchdog 与 48h 稳定用户 scope 持久化;不持有任务/HTTP 状态。旧 DurationTracker 网络链路已不可达且不再从主包导出。
运营入口模块(entryModules)⚠️
Section titled “运营入口模块(entryModules)⚠️”WS 驱动的运营浮层,config.entryModules 选择启用(默认全开)。多数 open()/close() 仅发信号事件,UI 由集成方或内置组件渲染。
| 模块 | id | 命令式方法 | 主要 emit | 状态 |
|---|---|---|---|---|
| 房间营销(签到/福袋/券统一) | roomMarketing |
prime(roomId)(首屏 HTTP 79952)resync(roomId)(重连)经 SDK:claimCoupon / joinCheckIn / joinLuckyPacket |
ws.room_activity(订阅);6010 上行 reportCheckIn / reportLuckyPacketJoin |
✅ |
| 抽奖 | lottery |
open() close() |
lottery.start/open/close |
⚠️ |
| 任务奖励 | taskReward |
open() close() refresh() getState() subscribe() receiveOrdinaryTask() acknowledgeReward() |
task.new/open/close/state.changed/reward.present/reward.closed/receive.result |
✅(ordinary/Range;fence/finalAck 联调 ⚠️) |
| 讲解 | commentary |
open() close() |
commentary.push/open/close |
⚠️ |
| 商品列表 | productList |
open()(惰性拉列表)close() |
goods.config/open/close/list/show/hide |
✅(推送 ⚠️) |
| 商品营销 | goodsMarketing |
经 SDK:openGoodsMarketing / closeGoodsMarketing / claimMarketingCoupon |
goods.marketing.* |
✅ |
⚠️ = payload schema 由 5010/6000/7000 LAPS 帧推断,测试环境无真实下行,上线前须以真实信令校验。
goodsMarketing为命令式(无 WS 订阅);taskReward的 HTTP 配置/上报/领奖链路已实现,只有task.newWS 子字段与服务端 fence/finalAck 能力仍需联调。⚠️ 已废止 entry:旧
coupon(优惠券open()/close()+coupon.*事件)、imageTextFloat(营销互动浮窗 +checkin.show)、checkIn(签到面板submit)已被统一roomMarketing取代(详见SPEC-ROOM-MARKETING.md)。勿据此集成。
Stores(sdk.stores)
Section titled “Stores(sdk.stores)”响应式状态,供自定义 UI 读取。_ 前缀为内部方法。
| Store | 暴露名 | 关键状态 | 公开方法 | 存在条件 |
|---|---|---|---|---|
| live | live |
status viewerCount title orientation startTime coverImg previewText endText countdownEnabled replayList trailerUrl kicked serverTime(同 getServerTime(),毫秒)buyingFrenzy shortcutComments memberLevels · 派生 videoState isPortrait/isLandscape |
setRoomConfig(cfg)(serverTime 会重校时实例统一时钟) |
总是 |
| player | player |
isPlaying isPaused volume quality qualityList manualMode ready currentTime duration buffering error · 派生 isMuted progress hasError |
setVolume setQuality setQualityList setManualMode switchQuality(code) getQualityList() setControlsVisible toggleControls |
总是 |
| chat | chat |
messages(≤1000) pinned unreadCount muted userMuted userBanned banTips historyLoaded |
sendMessage loadHistory setSelfId setSelfName setSelfAvatar setMuteStatus setWelcomeConfig |
总是 |
| enterMessage | enterMessage |
current({item:{id,userName,timestamp},playKey} 或 null) |
_destroy(内部清理) |
mount 后;受 liveWatch.enterMsgSwitch===1 门控 |
| interact | interact |
likeCount likeBursts(≤30) giftQueue |
sendLike consumeBurst(id) removeGift(id) |
总是 |
| user | user |
profile authenticated levelId · 派生 userId userName avatar |
—(只读) | 总是 |
| goodsList | goodsList |
goods:Map · getter list floatCard loaded(首帧推送前 false,UI 据此渲染骨架而非空态) |
applyChange(payload) getByNumIid(numIid)(按 numIid 同步取商品快照,供满减摘要本地归一) |
productList 启用时 |
| marketing | marketing |
open numIid scoreGoods loading sections error |
setOpening(numIid,scoreGoods) setReady setError reset |
goodsMarketing 启用时 |
| roomMarketing | roomMarketing |
cards(Record<id,RoomActivityCard>) · 派生 currentModalId currentCard floatItems(visible 卡按 createTime 降序) interactiveItems(互动工具时间轴) refreshing(静默刷新中) serverNowSec clockAnchored(未锚定倒计时显示 00:00) |
dispatch(op) show(id) dismiss() reconcilePrime({ops,liveIds,retiredIds}) primeDispatch(ops) primeShow(id) participateCheckIn(id) participateLucky(id) registerPickup(id) setRefreshing(v) setServerTime(ms) pruneGhost(ids) getServerNowMs() reset() |
roomMarketing 启用时(默认) |
| loading | loading |
visible text settled |
show(text?) hide() settle() |
总是(构造期即建) |
| topOffset | topOffset |
resolve()(runtime > static > '0px') |
setStatic(value?) set(value) |
总是(构造期即建) |
| cleanScreen | cleanScreen |
get()(true=清屏中) |
set(v: boolean) |
总是(构造期即建) |
| uiTextSize | uiTextSize |
resolve(scene) · snapshot() |
setStatic(config) update(partial) setScene(scene, mode) |
总是(构造期即建) |
全局 loading:mount() 一调用即在容器上独立挂载一个唯一 overlay(先于 LiveRoom,覆盖 auth 网络阶段),默认 visible=true。「首帧可见」——player.firstframe 真首帧(首个真 playing、解码出帧,区别于 player.playing 的 ‘play’ 意图)、可播态 player.error、或进入终态 live.status(not_started/ended/paused/banned/error/expired,由 StatusOverlay 接管)任一先到 → 自动收起(绝不卡死)。中途卡顿(player.waiting/stalled)复用同一 overlay 显隐,恢复即收起。颜色跟随主题色 --primary。对外/对内可用 showLoading(text?) / hideLoading() 手动控制(全局唯一,不会出现两个 loading)。
聊天敏感词:发送端命中 → 本地影子回显(仅本人可见);接收端命中 → 丢弃;无 matcher/异常 → fail-open 放行。
进场消息浮条:liveWatch.enterMsgSwitch===1 时启用,消息源为 IM user.join(含本人进房自进场事件);enterMessage store 以 FIFO 队列单条展示,UI 由 NotificationMessage 在 IM 消息列表上方渲染 3s 右进左出动画。同用户 60s 窗口内重复进场去重;enterMsgSwitch!==1 或缺省时不展示。
直播预告态(live.status='not_started' / 服务端 liveStatus=102):状态层继续展示封面、预告文案、倒计时,但 IM 聊天面板与输入栏保持展示和可操作;结束、禁播、暂停、异常、过期等阻断态仍由状态层接管。
SDKTheme 字段(全可选,局部应用)映射到挂载容器上的 CSS 变量——颜色字段走 shadcn token(HSL 通道,传 hex 自动转通道),其余走无前缀自定义属性;默认值在 app.css。
| 字段 | CSS 变量 | 默认 | 说明 |
|---|---|---|---|
primaryColor |
--primary |
hsl(10 100% 63%)(珊瑚) |
主色;hex→HSL 通道,供 bg-primary/text-primary/bg-primary/10 |
backgroundColor |
--background |
0 0% 100% |
hex→HSL 通道 |
overlayColor |
--overlay-color |
rgba(0,0,0,.6) |
原值 |
chatBgColor |
--chat-bg-color |
rgba(0,0,0,.4) |
原值 |
textColor |
--foreground |
222.2 84% 4.9% |
hex→HSL 通道 |
fontFamily |
--font-family |
系统字体栈 | 原值 |
fontSize |
--font-size |
14px |
原值 |
radius |
--radius |
0.5rem |
原值 |
次色
--secondary: 330 81% 60%(粉)+--secondary-foreground: 0 0% 100%在 app.css 固定(非 SDKTheme 字段),供bg-secondary/text-secondary。 旧--live-*/--livesdk-*前缀变量与applyTheme/DEFAULT_THEME/ThemeConfig已移除(统一 shadcn token)。
初始:options.theme;运行时:setTheme / setThemeColor / setFontSize(增量合并,已挂载即施色,未挂载缓存到 mount)。
场景字号不走全局 fontSize,而是通过 config.uiTextSize 或运行时 setUiTextSize / setUiTextSizeScene 控制。它只影响已登记的 IM 文案场景,不会整体缩放 SDK UI。
config.locale(默认'zh-CN',未知值告警回退)。当前内置 locale:仅zh-CN。config.options.i18n: Partial<I18nMessages>覆盖部分文案。- 取值:
sdk.t(key)(仅接受已知I18nKey)。 - 文案分类(共 67 key):
status.*(状态浮层)·chat.*(输入/消息)·player.*(播放控件)·interact.*(底栏)·goods.*(商品橱窗/卡片:标题/加载/空态/拉取失败/失败描述/重试/购物车·订单入口/加车/讲解中/已抢光/促销/抢购/兑换/待开价/关闭)·coupon.label·room.viewerCount·task.entry·gift.sent·milestone.default·hotSell.cta·more.*(更多面板:字体大小、清屏)·common.cancel(通用取消)。 - 底部聊天输入框默认 placeholder:
chat.input.placeholder=快来和大家聊聊吧~;集成方仍可通过config.options.i18n覆盖。
新增 key(字号设置 / 清屏 / 通用取消):
| key | 文案 |
|---|---|
more.font_size |
字体大小 |
more.cleanScreen |
清屏 |
more.red_packet |
我的红包 |
more.score |
我的积分 |
more.coupon |
我的券码 |
more.order |
我的订单 |
more.feedback |
意见/反馈 |
more.font_size.default |
默认 |
more.font_size.large |
中 |
more.font_size.xlarge |
大 |
player.cleanScreen.exit |
退出清屏 |
common.cancel |
取消 |
sdk.modal(opts): Promise<boolean>(resolve true=确认 / false=取消/关闭)。归属本实例,destroy() 仅关本实例弹框。
ModalOptions:type?:'info'|'danger'(默认 info) · title? · content?(纯文本)/ html?({@html},自行防 XSS) · confirmText?(默认“确认”) · cancelText?(传了才显示取消按钮) · confirm?/cancel?:()=>void|Promise(异步,报错则阻塞关闭) · singleton?(true 先关其它弹框)。
弹框挂载目标自带独立 .livesdk-container 样式边界;单点登录踢出等终态 Modal 即使在 sdk.destroy() 后按契约留屏,Tailwind/embed 样式仍持续生效,直至弹框关闭。
浮层组件(Dialog / Drawer / Toaster / Empty)✅
Section titled “浮层组件(Dialog / Drawer / Toaster / Empty)✅”命令式:sdk.dialog(opts) = sdk.modal 别名;sdk.toast(msg) / .success / .error / .warning(直采 svelte-sonner,多实例共享唯一全局 Toaster + 实例级 id 追踪,destroy()/直播结束仅清本实例)。
轻量 toast(小程序 wx.showToast 风格,独立于 sdk.toast):sdk.showToast({ content, duration?, mask? }) / sdk.hideToast()。全局单例——再次 showToast 仅替换 content 并重置计时(不堆叠、不闪烁两次);默认 5s 自动关(duration<=0 不自动关,仅 hideToast 手动关);mask=true 渲染透明蒙层拦截底层点击(默认 false → 点击穿透不挡操作);最多两行、最大宽 90%、容器内顶层(z=100000,仅覆盖 SDK 容器,非整屏——渲染层挂载于 SDK 容器内,absolute inset-0)。SDK 内部核心层亦可经 this.showToast() 调用;destroy()/直播结束自动清场。多 LiveSDK 实例共享同一单例(符合「一次只一个」语义)。
声明式组件(we-livesdk 顶层导出,类型 DialogProps/DrawerProps/EmptyProps):
| 组件 | 形态 | 关键 props |
|---|---|---|
Dialog |
bits-ui 直采,居中卡 | open($bindable) · title/content/html · type · confirmText/cancelText · confirm/cancel(异步) · onConfirm/onCancel/onOpenChange · contained(默认 false=body fixed) · dismissible(默认 false 防误触) · showClose/hideButtons |
Drawer |
原生底弹(弃 vaul,无手势关) | open($bindable) · title/description/descriptionHtml · showClose/showSubmit/submitText · overlayVariant · safeAreaBottom(默认 true,底部 env 安全距离) · children/footer(Snippet) · contained · onClose/onClosed(150ms)/onSubmit/onOpenChange · defer 字段(snapPoints/非 bottom direction 等)保留类型、dev warn、prod 降级 MVP |
Toaster |
svelte-sonner <Toaster>(去 mode-watcher) |
由 SDK 构造期自动挂载(全局唯一),一般无需手动渲染 |
Empty |
通用空态占位(居中 + 通用图标) | text(默认「暂无数据」) · description · icon(默认通用 lucide Inbox,传任意 lucide 图标覆盖) · iconSize(默认 48) · class · testid(默认 empty) · children(Snippet,放重试按钮等)。商品橱窗(暂无商品)/营销面板(暂无优惠券)空态已复用 |
Dialog
preventScroll={false}(不锁宿主 body);Drawer 用--vh约束高度(min 30% / max 80%,禁裸 100vh),嵌套 z 由drawerStore(base 1090 + depth×10)自动管理。商品橱窗/营销面板已收敛为<Drawer contained>。
sdk.use(new Plugin(opts))。IPlugin:{ id:string; install(sdk); uninstall?(sdk) }。子路径 we-livesdk/plugins。
| 插件 | 选项(默认) | 状态 |
|---|---|---|
DanmuPlugin |
speed(8) fontSize(14) opacity(.85) maxLines(3) |
🚧 占位 |
WatermarkPlugin |
text position(‘top-right’) opacity(.4) |
🚧 占位 |
DefinitionPlugin |
defaultQuality(‘preset’) auto(true) allowUpgrade(false) stallWindowMs(10s episode 上限) stallThreshold(可靠帧连续冻结窗,默认3;不可靠时至少4窗) cooldownMs(15s) dropFrameSampleMs(5s) dropFrameRatio(0.1,连续2个且每窗≥30帧才命中) decodeErrorCooldownMs(5s) decodeErrorThreshold(2) · 只读 manualMode + 方法 setManualMode(bool) · manualOverrideMs(@deprecated) |
✅ |
DefinitionPlugin 已公开导出(ESM 主路径 + UMD 全局 LiveSDK.DefinitionPlugin),为 opt-in 插件——宿主须显式注册才生效:
// ESMimport { LiveSDK, DefinitionPlugin } from 'we-livesdk'const sdk = new LiveSDK({ activityId, token, merchantId })sdk.use(new DefinitionPlugin())
// UMD(裸 HTML)const sdk = new LiveSDK.LiveSDK({ activityId, token, merchantId })sdk.use(new LiveSDK.DefinitionPlugin())注册后:起播按 defaultQuality 选档、健康 episode/连续丢帧/解码错误驱动自动降档;手动请求被 Player 接纳后立即进入永久 manualMode 锁定,解码错误硬路径仍可降档。默认 defaultQuality:'preset'、allowUpgrade:false;选择「自动」或调用 setManualMode(false) 才解除锁定。每个真实 player.quality.switched 都显示一次切换成功提示,不受普通提示的 30 秒冷却抑制;弱网、失败和恢复类普通提示仍限频。「更多」面板清晰度入口需插件存在才显示(门控 hasMultiQuality && getPlugin('definition'))。未注册时手动切档本身仍可用(走 player.switchQuality),但无入口、无自动降级。DanmuPlugin/WatermarkPlugin 仍为 Phase 2 占位实现,注册不报错但暂无实际效果。自定义插件按 IPlugin 实现即可立即生效。
首次 101 起播会在 auth.success 前原子确定最终档位/URL,事件后只启动最终源;108→101 先退出 VOD,再恢复真实手动档(档位消失时用服务端预设并保持锁定)。运行时事务不立即替换当前源,而是在隐藏、静音的 standby 中预加载目标流;仅由目标 generation 的 loadstart + playing + 相对进度增长 提交并交换画面。ready、公共 player.playing 和绝对非零进度均不足以完成切流;预加载失败只清理 standby,旧画面继续播放。iOS/WebKit 和所有声音状态都沿用同一 standby 预加载路径,禁止因开声退回 active 单播放器换源。公开 pause() 会暂停 active/standby、挂起事务门与超时,play() 后恢复;detach 等非替代取消会恢复 confirmed 档位/URL。候选/回滚中间错误只走内部 observer,不污染公开错误态。健康 episode 的冻结窗口最短 1 秒,真实推进立即结束 episode;后台、暂停、VOD、初始化、事务和退避期间禁用丢帧降档,手动锁定/最低档冻结由 Player 同源恢复。
class AuthError extends Error { name = 'AuthError' statusCode?: number // HTTP / 业务码}mount() 认证失败抛 AuthError 并 emit auth.error,在 mount().catch() 捕获。SDK 仅导出此一个错误类。
包导出与构建
Section titled “包导出与构建”| 子路径 | 内容 |
|---|---|
we-livesdk |
LiveSDK、app 模块、SDK_EVENTS、AuthError、PollingFallback、BrowserTransport、bridgeLapsEvents、DefinitionPlugin(+ 类型 DefinitionPluginOptions)、浮层组件 Dialog/Drawer/Toaster/Empty/ActionSheet + 类型 DialogProps/DrawerProps/EmptyProps/ActionSheetProps、@zan/laps 转出(LapsAdapter LAPS_CMD ROOM_STATUS WATCH_EVENT 等) |
we-livesdk/legacy |
宿主嵌入安全 ESM:单文件、无 CSS 副作用、首字节 iOS 12 polyfill;需另引 we-livesdk/embed.css |
we-livesdk/embed.css |
完整宿主嵌入样式:无 preflight;包含 Tailwind utilities、Svelte scoped/TCPlayer 组件样式,构建期统一命名空间到 .livesdk-container |
we-livesdk/components |
Svelte 组件(含 Dialog/Drawer/Toaster/Empty/ActionSheet) |
we-livesdk/stores |
Store 工厂 |
we-livesdk/plugins |
插件类 |
we-livesdk/types |
仅类型(SDKConfig SDKEventPayloads DialogProps DrawerProps EmptyProps 等) |
we-livesdk/styles |
样式(Tailwind + --live-* 默认) |
we-livesdk/tailwind |
Tailwind 配置 |
UMD:入口 src/lib/umd-entry.ts(含样式)→ dist-umd/livesdk.{umd,iife,esm}.js,全局 LiveSDK,目标 ES2015 / Safari 12 / iOS 12。bundle 首部注入 iOS12 polyfill banner(globalThis + Array.prototype.at + Object.fromEntries),保证 bits-ui Dialog 在 iOS12.0/12.1 模块求值期不崩。
标准 pnpm build / pnpm package 会生成 Svelte package、dist-umd/livesdk.legacy.js、完整 dist/embed.css 并运行 publint;clean checkout 不需要预先存在的 dist-umd。pnpm build:umd 额外生成 UMD/IIFE/ESM 演示产物,并同步重建 legacy 入口。发布或宿主构建必须使用标准 build,禁止依赖工作区残留产物。
live-app 启动开发服务(pnpm dev)与测试环境构建(pnpm build:test)均先通过 workspace filter 执行 LiveSDK build:test,确保宿主加载的 legacy/embed 产物固化测试环境端点。
实现状态总览
Section titled “实现状态总览”| 区块 | 状态 |
|---|---|
| 核心:mount/destroy、认证、事件、服务端时钟、主题、i18n、弹框 | ✅ |
宿主嵌入:runtime api.baseUrl、严格 host-cache bootstrap、legacy + 完整 embed.css |
✅(iOS 12 / Android 7 真机 ⚠️) |
| 播放器(直播 + VOD 回放) | ✅(清晰度双槽位预加载切换;iOS 12 / Android 7 真机 ⚠️ 待验证) |
| IM 聊天、敏感词、禁言/封禁、欢迎语、历史 | ✅ |
| 互动 app 模块(viewerCount/like/gift/goods/security)+ 观看时长 | ✅ |
| 业务特性配置 features(UI 可见性)+ 入口数字 badge | ✅ |
| 商品列表 / 营销弹框(命令式流程) | ✅ |
房间营销 roomMarketing(签到/福袋/券 + HTTP 79952 首屏 prime + 重连 resync) |
✅(79952 响应 shape ⚠️ 待服务端验证) |
| 左上角营销互动浮窗 image-text-float + 签到面板 | ⚠️ 已被 roomMarketing 取代(旧 imageTextFloat/checkIn entry 废止) |
WS 运营推送 payload(lottery/task/commentary/goods 推送;coupon 推送已归 ws.room_activity) |
⚠️ 待服务端验证 |
core marketing / core security 模块方法 |
🚧 占位 |
| Danmu / Watermark 插件 | 🚧 占位 · Definition ✅ |
本手册是 SDK 对外契约的产品级真源,改动对外使用面必须同步:SDKConfig(及嵌套)字段、LiveSDK 公开方法、SDK_EVENTS/SDKEventPayloads 事件、构造/mount/destroy 行为、主题/i18n/modal/插件契约、src/lib/index.ts 导出、UMD 全局与构建产物。占位能力落地后须移除对应 🚧 标记。
| 日期 | 版本 | 变更 |
|---|---|---|
| 2026-07-15 | 1.2.0 | 修复观看上报端点后置配置:认证会话就绪即建立 ordinary/Range channel;宿主在 mount 后调用 setEndpoints({ watchReportBaseUrl }) 会刷新任务配置并重新校准,上报无需重新挂载 SDK。 |
| 2026-07-15 | 1.2.0 | 观看时长与任务奖励链路完成并修复应用层装配:新增 WatchClock、getWatchProgress()、watch.*、可信 watchSession、ordinary/Range 独立校准/outbox/retry/final ACK;TaskRewardEntry 从主包导出,真实映射 watchCondition/interactiveCondition/awardSet/awardReceiveType,支持动态端点、任务时间窗、普通手动领奖与 Range 累计;修复 entry 创建早于 WatchClock、在途 ACK 吞 final、destroy 中断终态、跨用户 scope 串时长。服务端 fence/finalAck 仍标 ⚠️;集成示例见 GUIDE-APP-LAYER-MARKETING.md |
| 2026-07-14 | 1.2.0 | 商品兑换券按 scoreGoodsInfo.useCouponType 对齐 live-app(无 SDKConfig/方法/事件签名变化,纯数据模型与 section 语义补充):① useCouponType 枚举驱动分流——0/空=不使用(不显兑换券胶囊/弹窗)、1=商品券(分页「可用兑换券」+需要/已有)、2=普通券+万能券(内联「商品所需兑换券」+万能券提示);② GoodsCardItem 新增可选 supportUniversalCoupon?: boolean(商品项顶层,仅 type2 消费,缺失→false);③ scoreGoodsInfo.couponList[] 项形状补齐 {couponNum,couponName,couponId,code?,consumeNum?,count?,name?}(numIid 1954756 实测 type2 内联);④ ExchangeCouponSectionData 语义明确:新增 couponType:1|2 驱动渲染分支,count = 商品所需兑换券总数(type1=couponNum / type2=sum(couponList),非券种数),mine(仅 type1,mySelfCouponNum),isSupportUniversalCoupon(仅 type2),hasMore/pageNo/loadingMore/loadMoreError(仅 type1);⑤ 缓存/single-flight 键 + Entry 竞态守卫扩展到 numIid + scoreGoods + couponType;⑥ 向后兼容:商品不在列表(found=false)且 scoreGoods=true 时程序式打开回退 type1 分页分支。goods.list payload 项字段扩展、goods.marketing.show 的 MarketingDetail.sections 中 exchangeCoupon section 语义如上;满减/满赠 chip 维持纯展示不开弹框 |
| 2026-07-13 | 1.2.0 | 兑换券胶囊新增兼容型 SDK 自开:SDKOptions.goodsMarketing.autoOpenExchangeCoupon 默认 false,显式 true 时 SDK 打开 GoodsMarketingPanel 并继续发送 goods.promotion.click;修复真实请求失败被伪装为空态、重试丢失 scoreGoods、营销缓存未区分普通/积分分支及陈旧请求覆盖。marketing Store 新增 scoreGoods,setOpening 签名同步更新 |
| 2026-07-13 | 1.2.0 | 清晰度预加载评审与回归修复(无新增配置/API/事件):所有平台及声音状态统一使用 standby 预加载,回滚已开声触发的 active 直接换源;开声不销毁 standby,旧 active 停止后才向新 active 继承缓存音量/静音;同时完成 pause/detach、媒体/UI 层级、重复 Danmu 输入框与逐次成功提示修复。 |
| 2026-07-13 | 1.2.0 | 清晰度切换体验优化(内部播放机制,无新增配置/API/事件):运行时切档由“当前 video 立即换源”改为 active/standby 双槽位;目标源隐藏静音预加载,取得 loadstart → playing → progress 后原子交换画面并迁移音量/静音。失败、超时、取消或快速改选只释放 standby,旧源持续播放,避免目标源缓冲期间 1~5 秒空白。首次起播、VOD、自愈与公开切流事件契约不变。 |
| 2026-07-13 | 1.2.0 | 新增实例级服务端时间校准与公开方法 getServerTime():首屏 config/detail.serverTime、LAPS serverTime / ws.room_config.serverTime、营销 HTTP timestamp 汇入同一 ServerClock;以 performance.now() 单调增量推进,设备日期/时区修改不影响结果,重复/乱序锚点不回拨;live.setRoomConfig({serverTime}) 同步更新统一时钟,签到活动先到时显示 00:00 并在校时后立即重算 |
| 2026-07-13 | 1.2.0 | 互动工具聚合抽屉:FloatMoreDrawer 改读 interactiveItems 时间轴(60% contained 抽屉、打开即静默刷新、详情 z=1200 覆盖可返回);Store 新增 interactiveItems/refreshing/reconcilePrime;Entry 三路径共用 generation 门控。_refreshInteractiveTools 为 SDK 内部委托,非公开 API |
| 2026-07-13 | 1.2.0 | 底部聊天输入框中文默认 placeholder(chat.input.placeholder)由“说点什么…”调整为“快来和大家聊聊吧~”;i18n key 与覆盖方式不变,无 SDKConfig/API/事件/数据模型变化 |
| 2026-07-13 | 1.2.0 | 补全遥测 v3 解析契约:14/14 事件逐 payload 字段定义,覆盖 batch/ctx/stats/sidecars,新增严格导出日志解析器与语义基线门禁;统一漏斗枚举为 goods=1、coupon=2,修复采集数据 type=1 被旧表误解为 coupon。 |
| 2026-07-13 | 1.2.0 | 遥测 v3 的 ctx.userKey 改为明文用户标识(去首尾空白),deviceKey 保持哈希;diagnostic.userKey 改为匹配明文,identityMode/plaintextIdentity 仅兼容保留。 |
| 2026-07-12 | 1.2.0 | 修复单播放器切流评审缺口:接通首次 101 原子起播与 108→101 VOD teardown/真实手动档恢复;完成门改为 source-applied + playing + 相对进度,隔离中间错误并收紧健康采样/同源恢复。 |
| 2026-07-12 | 1.2.0 | 收口遥测 v3 评审:真实事件接线、60 秒/5 窗口预算、生产诊断闸门、可靠退避熔断、sidecar 重试、APM/白屏与 contract 门禁。 |
| 2026-07-12 | 1.2.0 | 遥测升级 v3:新增 profile、Transport、SHA-256 身份、批次上下文、聚合/漏斗/APM 与有界队列;同步事件参考、zan-mini 同构规范及宿主环境验证清单。 |
| 2026-07-12 | 1.2.0 | 清晰度自适应升级为健康 episode + 单播放器 generation 切流事务:新增 switching/switched/switch-failed/switch-cancelled 事件,首次选流与预告/回放转直播原子提交,提示绑定真实出帧终态。 |
| 2026-07-11 | 1.2.0 | 修复终态 Modal 在 sdk.destroy() 后 Tailwind/embed 样式失效:Modal target 自带样式边界,留屏期间保持 py-7 等完整视觉;修复 TCPlayer 已 playing/canplay、画面正常时前台恢复复判误发 foreground recovery failed: still stalled |
| 2026-07-11 | 1.2.0 | 新增统一 EndpointConfig、setEndpoints/getEndpoints,支持 HTTP、LAPS WS、观看上报端点按环境构建、宿主初始化覆盖与运行时换址;观看上报改为独立 base URL;live-app 开发启动与测试构建统一前置 LiveSDK build:test。 |
| 2026-07-10 | 1.2.0 | LiveSDK 接入契约补齐:新增运行时 api.baseUrl、严格 host-cache 房间详情 bootstrap、storeId 与红包 handlers;公开 we-livesdk/legacy / we-livesdk/embed.css,标准 build 产出嵌入资源;移除 API/WS 测试地址兜底并同步状态切换请求地址。 |
| 2026-07-13 | 1.3.2 | 「更多」面板补齐小程序 more-popup 五项业务入口(增量,不改既有清晰度/字体/清屏):新增 features.more 5 个 FeatureKey(more.redPacket/more.score/more.coupon/more.order/more.feedback,默认 true)+ 5 个 more.* 事件;MorePanel 追加「我的红包/积分/券码/订单/意见反馈」入口(52×52 白底圆 + 渐变背景,既有 3 项样式不变);红包点击 emit 后 openRedPacket(),反馈 emit 后转发 topbar.feedback,积分/券码/订单纯外抛由宿主导航。新增组件 MoreEntryButton + 5 个 i18n key。详见 docs/superpowers/plans/2026-07-13-livesdk-more-panel-business-items.md |
| 2026-07-11 | 1.2.0 | 商品营销面板(GoodsMarketingPanel)视觉+功能对齐主应用 coupon-detail 弹窗(新增 1 个实例方法):①兑换券合并——相同 couponId/code 的兑换券累加计数、过滤 0 计数条目,标识键使用 id:/code: 独立命名空间(对齐 detail-popup mergedList);②计数回退链 couponNum→consumeNum→count→0(对齐 DetailItem getConsumeNum);③「已获得」标签(对齐 goods-coupon-popup showSubText=true);④万能券提示横幅 isSupportUniversalCoupon(对齐 detail-popup);⑤分页加载更多——新增实例方法 loadMoreMarketingCoupons(),marketingApi.fetchExchangeCouponPage 分页拉取 + marketingStore.appendExchangeCoupons 合并追加,section 保存服务端 pageNo 并按分页元数据判定 hasMore,避免合并后重复请求;section 内「加载更多/加载中/加载失败」三态 UI(对齐 goods-coupon-popup loadMore);⑥pageSize 20→10 对齐 goods-coupon-popup。ExchangeCouponSectionData 新增 consumeNum/count/isSupportUniversalCoupon/hasMore/pageNo/loadingMore/loadMoreError 字段。SectionComponent props 新增 onLoadMore/loadingMore/loadMoreError(可选) |
| 2026-07-10 | 1.2.0 | 营销浮标展示细节对齐(内部 UI/store 行为,无 SDKConfig/公开 API/事件/数据模型变化):横竖屏统一位于顶部横向左侧,超出容器可横向滚动;每项增加 × 关闭,关闭仅写入 store 本地隐藏标记、不删除原始活动,同 ID 数据刷新/upsert 不会令其复活,仍可从「更多」重新打开;页面刷新、store 重建或 reset() 会清空关闭集合并重新显示活动。文案规则:coupon 恒为「领券」、checkin 恒为「签到」;lucky active 且 openType=2 显示倒计时,active 手动开启显示「等待开启」,attended 显示「开启中」,其余显示「福袋」。定时福袋以 Math.floor(openTime / 1000) 得到 deadlineSec,再减 serverNowSec;服务端时钟未锚定时稳定显示 00:00。相关 store 方法仅供内部组件使用 |
| 2026-07-10 | 1.3.1 | 营销浮标样式对齐火山小程序 image-text-float(纯视觉 + 新增溢出交互,无 SDKConfig/API/事件变更):① FloatBar 图标由 lucide 线性图标改为本地 PNG(assets/image-text-float/float-coupon|checkin|luckymoney.png,Vite 内联 base64),容器 44×44px 圆角方块 + 底部文字条(券「领券」/签到「签到」/福袋「福袋」,对齐小程序 statusRules);lucky(积分/红包福袋)用 float-luckymoney.png。② 新增 floatIcons.ts(kind→图标/文案映射)+ FloatIconButton(单图标单元,portrait 深色 / landscape 浅色主题)+ FloatMoreDrawer(基于 Drawer 的聚合抽屉)。③ 溢出折叠:浮标最多 3 个,超出折叠为「更多」方块,点击打开聚合抽屉列出全部(对齐小程序 floatIconNum=3)。④ 横屏(liveStore.isLandscape)浮标横向靠右 + 浅色主题。数据源 roomMarketing.floatItems、点击 store.show(id)、清屏门控不变;CouponStack 仍保留导出(DEPRECATED) |
| 2026-07-10 | 1.3.1 | 修复房间营销浮标被遮挡不显示的 bug(纯内部视觉,无 SDKConfig/API/事件/导出变更)+ 我的红包全功能(有 SDKConfig/API/事件/导出变更):FloatBar(签到/福袋/券入口)改为迁入 TopBar 第二行作为流式子元素;简化版:…① SDKConfig.handlers.redPacket(withdraw/confirmReceipt,微信 JSAPI 写操作整体抛宿主,返回归一化结果 {status:'success'|'cancelled'|'fail'|'pending', message?});② 实例方法 openRedPacket()(等价点击 topbar 按钮);③ AppEntryModuleId 加 'redPacket',新增入口模块 RedPacketEntry + 新事件 redPacket.open;④ 新增 store sdk.stores.redPacket;⑤ SDK 自调账户域 HTTP;⑥ 三个组件 RedPacketPopup/RedPacketRecordPopup/RedPacketRecordList;⑦ 命令式挂载基建 mountOverlay + RedPacketHost 接线;⑧ 金额规则:<0.03 拦截、>200 裁剪;⑨ 24 个 i18n key |
| 2026-07-10 | 1.3.2 | 商品橱窗卡新增预售/海淘/跨境标签:GoodsCardItem 新增 isPresell?:number(0=非预售 1=全款 2=定金 3=混合)+ goodsType?:number(1=普通 2=视频号 3=海淘 4=跨境),goodsMapper.mapGoodsData 防御性数值透传(缺省→undefined 不入对象、null→undefined、非数字→toNum 兜底 0);GoodsListPanel 商品名前内嵌语义色 chip(预售=emerald-500 / 海淘=amber-500 / 跨境=red-500;预售粗粒度 isPresell!==0 即显,海淘/跨境互斥仅 goodsType===3/4,可叠加),与一方 goods.svelte 对齐。新增 3 个 i18n key(goods.tag_presale/goods.tag_oversea/goods.tag_crossborder,zh-CN:预售/海淘/跨境)。无新 SDKConfig/API/事件/方法;3 个 i18n 键扩展 I18nMessages 公共面(宿主可经 SDKOptions.i18n 覆盖),非破坏性增量。字段下发 NEEDS-SERVER-VERIFY:@zan/laps cmd 7000 / goodsCard 路径是否携带 isPresell/goodsType 待抓包复核(防御式 mapper 不崩,未下发则标签不显示) |
| 2026-07-09 | 1.2.0 | 房间营销统一为 roomMarketing 域(SPEC-ROOM-MARKETING Phase F 收尾):① AppEntryModuleId 旧 coupon/checkIn/imageTextFloat → 统一 'roomMarketing'(签到/福袋/券合流);② 新增实例方法 claimCoupon(packetId) / joinCheckIn(id?) / joinLuckyPacket(id);③ 新增事件族 ws.room_activity(判别联合 RoomActivityOp)+ ws.server_time / ws.reconnect,废止 activity.change/result/participate / coupon.show/open/close / ws.coupon_dispatch;④ 新增 Store sdk.stores.roomMarketing(cards/currentCard/currentModalId/floatItems/serverNowSec + dispatch/show/dismiss/primeDispatch/primeShow/setServerTime/reset),下线 liveStore.coupons 与 checkIn store;⑤ CouponPopupLayer 改名搬入 room-marketing/CouponLayer.svelte,删 ActivityPanel。废弃旧文档 SPEC-MARKETING/PLAN-MARKETING/SPEC-MARKETING-REVIEW(加 deprecated 抬头)。详见 SPEC-ROOM-MARKETING.md |
| 2026-07-09 | 1.3.1 | 修复大字体模式下 IM 消息部分元素不缩放的问题:更多面板「字体大小」改为全场景同档联动——评论(im.comment.content 正文 / im.comment.nickname 昵称 / im.comment.level 等级 / im.comment.avatar 头像)+ 温馨提示(im.welcome.content)+ 进场消息(im.enter.content)+ 快捷评论(im.shortcut.content)+ 新增下单消息(im.order.content)八场景统一 setUiTextSize 批量写入(非单场景 setUiTextSizeScene)。新增场景 im.comment.avatar(头像尺寸 18/20/22px)与 im.order.content(下单消息文案,default text-sm / large text-base / xlarge text-lg);im.comment.nickname、im.comment.level 补全 xlarge 档。ChatMessage 头像由硬编码 h-[18px] w-[18px] 改为响应式 avatarSizeClass;BuyingFeed 下单消息容器/按钮由固定 text-sm 改为消费 orderTextClass。对外契约:UiTextSizeScene 新增 im.comment.avatar、im.order.content,更多面板行为变更(昵称/头像/温馨提示/进场/下单消息随正文同比放大);单场景 setUiTextSizeScene('im.comment.content') 路径不受影响、其余场景回退 default。手册「配置 SDKConfig」/「字号档位」/本表同步 |
| 2026-07-09 | 1.2.0 | 「更多」面板业务特性可见性:features.more 命名空间 + 3 个 FeatureKey(more.quality/more.fontSize/more.cleanScreen,默认 true;清晰度仍 AND hasMultiQuality && DefinitionPlugin)。入口点击先 emit 对应 more.* 再执行既有业务逻辑。复用 setFeature/updateFeatures/getFeatures,不改 featureStore。零配置 = 今日行为。不含底栏 interact.more。详见 PLAN-MORE-PANEL-FEATURES.md |
| 2026-07-09 | 1.3.0 | 商品营销满减/满赠摘要级渲染(v2):GoodsCardItem 新增 marketingActivities(goodsCard/get 商品项内联,仅摘要 actId/actType/actName,无档位/赠品明细,YApi 67205 实测;推翻旧 activityList+activityDetail 富结构假设——商城详情页端点形状不适用直播商品卡);marketingApi 新增 buildFullReduction 本地归一(零 HTTP)+ getMarketingActivities 窄回调注入(依赖倒置;goodsListStore 新增 getByNumIid 方法);新增 FullReductionSection.svelte + registry 注册 fullReduction kind(满赠合一不拆 kind);goodsMapper 扩 MarketingEntryHint 多源派生(兑换券 + actName,普通商品满减现也能出 chip 入口)。actType 码表未知期全量摘要 + 单点过滤钩子 FULL_REDUCTION_ACT_TYPES(抓包确认 2026-07-09:0=满减/1=满赠;保持 null 全量渲染),section 标题「促销活动」。无新事件/方法/SDKConfig;goods.list payload 项新增可选 marketingActivities,goods.marketing.show 的 MarketingDetail.sections 可含 fullReduction kind |
| 2026-07-08 | 1.3.0 | DefinitionPlugin 公开导出(补清晰度重构遗漏):① ESM 主路径 + UMD 全局 LiveSDK.DefinitionPlugin 导出(src/lib/index.ts re-export,DefinitionPluginOptions 类型一并导出;Danmu/Watermark 仍 🚧 占位不固化);② html-demo 装配补 sdk.use(new LiveSDK.DefinitionPlugin())(构造后、mount 前注册)+ 代码集成展示框同步插件注册示例;③ 手册「插件」章节注明 opt-in 装配(ESM/UMD 两式)与「更多」面板清晰度入口门控依赖插件存在(hasMultiQuality && getPlugin('definition'))。契约:LiveSDK.DefinitionPlugin / DefinitionPluginOptions 命名固化为对外公开 API 面。修复:预览站(UMD)「更多」面板缺失清晰度入口(根因 = 插件未导出 + demo 未注册,见 REVIEW-DEFINITION-PREVIEW-MISSING.md)。非破坏性(纯增量导出) |
| 2026-07-09 | 1.3.1 | 商品营销满减/满赠摘要级渲染(v2):GoodsCardItem 新增 marketingActivities(goodsCard/get 商品项内联,仅摘要 actId/actType/actName,无档位/赠品明细,YApi 67205 实测;推翻旧 activityList+activityDetail 富结构假设——商城详情页端点形状不适用直播商品卡);marketingApi 新增 buildFullReduction 本地归一(零 HTTP)+ getMarketingActivities 窄回调注入(依赖倒置;goodsListStore 新增 getByNumIid 方法);新增 FullReductionSection.svelte + registry 注册 fullReduction kind(满赠合一不拆 kind);goodsMapper 扩 MarketingEntryHint 多源派生(兑换券 + actName,普通商品满减现也能出 chip 入口)。actType 码表未知期全量摘要 + 单点过滤钩子 FULL_REDUCTION_ACT_TYPES(抓包确认 2026-07-09:0=满减/1=满赠;保持 null 全量渲染),section 标题「促销活动」。无新事件/方法/SDKConfig;goods.list payload 项新增可选 marketingActivities,goods.marketing.show 的 MarketingDetail.sections 可含 fullReduction kind |
| 2026-07-08 | 1.3.0 | 更多面板字体大小设置:SDKConfig.uiTextSize(场景级 UI 字号默认值,static 层,类型 Partial<Record<'im.comment.content', 'default' | 'large' | 'xlarge'>>)+ 实例方法 setUiTextSizeScene(scene, mode) / getUiTextSize()(链式、mount 前可用、运行时同步持久化到 localStorage key livesdk:uiTextSize,刷新/重进自动恢复)。新增 xlarge 档(text-lg/7 = 18px),三档显示「默认/中/大」对应 mode default/large/xlarge(mode 值为公开契约不可改名,文案经 i18n 解耦)。作用范围:聊天评论内容文字(im.comment.content)。优先级 runtime(持久化) > SDKConfig.uiTextSize(static) > default。MorePanel 更多面板新增字体大小入口(ActionSheet 三档选择 + 高亮 + xlarge badge)。新增 5 个 i18n key(more.font_size/.default/.large/.xlarge + common.cancel,ActionSheet cancelText 走 common.cancel)。SDKConfig/方法/事件 契约同步见本表上方「配置 SDKConfig」「实例方法」「字号档位」「国际化」 |
| 2026-07-08 | 1.3.0 | 清晰度切换重构(FR-DEF-RW,PLAN-DEFINITION-REWORK):① defaultQuality 默认 auto→preset(破坏性:低端机起播失去设备分级降档保护,宿主需显式 defaultQuality:'auto' 保留);② manualOverrideMs 废弃(60s 静默→手动永久锁定,依赖自动恢复的宿主须自行 setTimeout+setManualMode(false) 重建);③ 解码错误硬路径(player.error 同档≥2→降档,豁免手动锁定,最低档 emit player.quality.failed);④ 手动 UI 迁移:移除 PlayerControls 清晰度入口+删 QualityMenu/QualityToast,新增「更多」Drawer(MorePanel)+ActionSheet(Drawer contained 薄封装);⑤ 新增 LiveSDK.getPlugin<T> 公共方法、playerStore.manualMode 响应式、player.quality.failed 事件、ActionSheet 三落点导出(we-livesdk/+components/+types)、6 个 i18n key;⑥ quality toast 收归 plugin 直接调 sdk.toast(手动 success/软降级 warning/解码 warning/不流畅 warning/终态 error)。DefinitionPlugin 🚧→✅。存量宿主迁移:低端机占比高→显式 defaultQuality:'auto';依赖 60s 自动恢复→自行重建。详见 PLAN-DEFINITION-REWORK.md/-TASKS.md |
| 2026-07-08 | 1.2.0 | 新增左上角营销互动浮窗 imageTextFloat 与签到面板 checkIn:支持 CHECKIN/LUCKYMONEY/COUPON 三类 LAPS 映射、10 张本地图标、图标关闭/更多抽屉、签到详情/提交/6010 上报/踢出;新增 SDKOptions.floatingInteractionIcons 与 imagetext.* / checkin.* 事件 |
| 2026-07-08 | 1.2.0 | 新增清屏态 API:实例方法 setCleanScreen(active) / getCleanScreen()(链式、mount 前可用,emit ui.cleanscreen.changed {active})+ 新事件 ui.cleanscreen.changed + 新 store sdk.stores.cleanScreen(get() / set(v),构造期即建、进房默认 false、不持久)。active=true 进入清屏(隐全部业务 UI),false 退出。UI 入口:「更多」面板(MorePanel)新增恒显清屏入口(EyeOff 图标,点击 setCleanScreen(true) 并关闭面板);清屏态 ExitCleanScreen 根级浮动退出按钮(z-[80]、右侧垂直居中、Eye 图标,点击 setCleanScreen(false))。门控:竖屏 PortraitLayout 卸载 z-[60] 业务层 + Interact + ActivityPanel + 根级弹窗,保留 Player/MilestoneToast/MorePanel;横屏 LandscapeLayout 卸载评论区模块 + Interact/TopBar + 根级弹窗,观看区高度 h-[45%]↔h-full 切换 + 视频容器 absolute inset-0 使清屏态仅留视频铺满整屏,保留 Player/MilestoneToast/StatusOverlay/MorePanel。{#if !clean} 卸载(非 CSS 隐藏)→ 隐藏元素无 DOM/监听/焦点,彻底不可触发。新增 2 个 i18n key(more.cleanScreen / player.cleanScreen.exit)。setCleanScreen/getCleanScreen/ui.cleanscreen.changed/stores.cleanScreen 契约同步见本表上方「实例方法」「事件」「Store」 |
| 2026-07-07 | 1.2.0 | IM 场景字号扩展:UiTextSizeScene 从 im.comment.content 扩展为 6 个场景,新增昵称、等级徽标、温馨提示、进场消息浮条、快捷评论按钮文案;config.uiTextSize 与运行时 setUiTextSize / setUiTextSizeScene / getUiTextSize 文档化,playground 字号切换同步覆盖全部 IM 场景。无新增 SDK API,沿用既有场景字号契约 |
| 2026-07-06 | 1.2.0 | 商品橱窗底部安全区位置优化(纯内部视觉,无 SDKConfig/API/事件变更):GoodsListPanel 给 <Drawer> 传 safeAreaBottom={false} 关闭其固定底部安全区条,改在滚动列表(drawer-content)末尾自加 data-testid="goods-list-safe-area"(height:env(safe-area-inset-bottom)、bg-white)占位——安全区随列表一起滚动、列表滚到底时才出现,避免固定白条截断滚动列表底部(列表无法从最底部滚出)。Drawer 组件与 safeAreaBottom 契约不变;营销面板仍用默认固定安全区。需宿主 viewport-fit=cover |
| 2026-07-06 | 1.2.0 | 横屏布局重构:LandscapeLayout 改上下 50/50 均分(观看区 / 评论模块各 flex-1);观看区内占位容器把 16:9 视频向下推(与顶部保持距离),16:9 改用 aspect-ratio 实现(移除原 padding-bottom:56.25% iOS12 兼容占位);横屏 playerFit 缺省由 cover 改 contain(对齐 SPEC AC-L-01,等比留黑边不裁切);根 data-testid="landscape-layout" 加 bg-black/70 backdrop-blur-xl,移除子元素背景色、视频容器自带 bg-black;TopBar / 跑马灯改为观看区直接子元素(锚定布局顶部、不随视频下沉,--livesdk-top-offset 偏移逻辑不变);底部新增专属安全区固定条 data-testid="landscape-safe-area-bar"(height:env(safe-area-inset-bottom)、shrink-0,参考 Drawer/商品橱窗),底部栏内边距改基础值避免重复安全区。需宿主 viewport-fit=cover 才生效 |
| 2026-07-06 | 1.2.0 | 对齐 LAPS CMD 梳理补齐营销判断:6000 按 commandType 分流 check.in.start/end 到 activity.change(type=1),分流 lucky.packet.create/display/finish 到 activity.change(type=2);6020 lucky.packet.user.result 统一按当前 agentId 过滤,命中本人时派发 activity.result / ws.coupon_dispatch / coupon.result,他人结果不再透出;未知 commandType 仍保留 ws.coupon_dispatch 回落且不抛错 |
| 2026-07-05 | 1.2.0 | 新增顶部安全偏移:LayoutConfig 加 topOffset?: number | string(默认 0px,App 沉浸式嵌入避让系统状态栏;number 按 px,string 允许 CSS length/calc/env);实例方法 setTopOffset(value) / getTopOffset()(链式、mount 前可用,emit topOffset.update {value});LiveRoom 根写 --livesdk-top-offset CSS 变量,TopBar / 公告跑马灯 / 营销活动面板顶部由 top-0 改为 var(--livesdk-top-offset) 定位。新增 topOffset store(sdk.stores.topOffset,runtime > static > 0px,构造期即建)、新事件 topOffset.update。同步新增 activity.change / activity.result / activity.participate 事件(ActivityPanel 签到 / 福袋面板,原 as never 内联 emit 收敛为类型安全) |
| 2026-07-03 | 1.2.0 | 播放器填充选项:LayoutConfig 加 `playerFit?:‘cover’ |
| 2026-07-03 | 1.1.0 | 新增进场消息浮条:liveWatch.enterMsgSwitch===1 门控,IM user.join 单源驱动,enterMessage store FIFO 单条展示,NotificationMessage 在 IM 消息列表上方 3s 滑入滑出;chat.enterNotice 旧聊天流内进场态移除 |
| 2026-07-01 | 1.2.0 | 新增商品橱窗入口数字 badge:FeatureItemOptions 加 badge?: number(静态初值,构造期 config.features.<key>.badge 播种)+ 专用运行时 API setBadge(key,n)/getBadge(key)(链式、mount 前可用、emit badge.update {key,value},n<=0 清空)+ 新事件 badge.update;覆盖 2 个 BadgeKey(goods.cart.open/goods.order.open,购物车·订单入口图标右上角标,n>99 显示 99+)。新增类型 BadgeKey(顶层导出)+ badgeStore(sdk.stores.badge,双层 runtime > static,镜像 featureStore)。badge 动态只走 setBadge,不走 setFeature({badge})(职责分离)。GoodsListPanel 购物车/订单入口渲染角标 |
| 2026-07-02 | 1.1.0 | 调整直播预告态交互:liveStatus=102/not_started 保留预告封面、文案与倒计时,同时 IM 聊天面板和输入栏继续展示并可聊天;结束/禁播/异常等阻断态行为不变 |
| 2026-06-30 | 1.1.0 | 新增业务功能配置系统:SDKConfig.features: FeatureConfig(业务 UI 可见性,与 appModules 正交)+ 运行时方法 updateFeatures(partial)/setFeature(key,opts)/getFeatures()(链式、mount 前可用)+ 事件 features.update {partial,key?};覆盖 5 个 FeatureKey(topbar.userCenter/topbar.businessInfo/goods.cart.open/goods.cart.add/goods.order.open,键 = 对应事件键);三源优先级 runtime > 构造 > 服务端兜底,零配置 = 今日行为。新增类型 FeatureConfig/FeatureItemOptions/FeatureKey(顶层导出)+ featureStore(sdk.stores.features)。RightButtons/GoodsListPanel 可见性改由 featureStore.resolve 驱动 |
| 2026-06-26 | 1.0.0 | 初版:全量配置/方法/事件/模块/Store 覆盖;标注未实现(marketing/security core、3 插件 🚧)与待验证推送 payload(⚠️);以代码为真源,修正 README 旧示例 |
| 2026-06-27 | 1.0.1 | ready 事件 payload 由 undefined 改为 {detail: RoomDetailBody}(直播详情对象:title/liveStatus/coverImg/planBeginDate 等),host 可于 ready 读直播间名称等;弹框(modal/AuthError)改容器内呈现 + 黑色 blur overlay + 失败时容器封面底图(roomDetail 复用不二次请求详情接口) |
| 2026-06-28 | 1.0.1 | 新增全局 loading:showLoading(text?)/hideLoading() 方法 + sdk.stores.loading;进房默认展示、首帧可见自动收起、颜色跟随主题色;全局唯一 overlay,移除播放器内旧初始 spinner(统一由全局 loading 接管) |
| 2026-06-29 | 1.0.1 | 新增浮层三件套:声明式组件 Dialog(bits-ui)/Drawer(原生)/Toaster(svelte-sonner) 顶层导出 + 类型 DialogProps/DrawerProps;命令式 sdk.dialog(=modal 别名) 与 sdk.toast/.success/.error/.warning;商品橱窗+营销面板收敛为 <Drawer contained>(z 1090/1100 不变)。依赖对齐 live-app(bits-ui/svelte-sonner/clsx/tailwind-merge/tailwind-variants)。UMD 首部 iOS12 polyfill banner(globalThis/Array.at/Object.fromEntries)。SDKConfig 无变化 |
| 2026-06-29 | 1.0.1 | 浮层公共组件 bug 修复:① Drawer overlay 与 panel 同 z(嵌套时后开 overlay 不再被先开 panel 盖住);Dialog overlay/content 钉 z-[1200](高于 drawer 带、低于命令式 modal)。② Drawer 下拖关闭改由顶部 grip(把手+标题区,touch-action:none)承载,与可滚动 body 隔离,修复「下滑无法关闭」。③ 新增 goodsList.loaded getter,商品橱窗加载态渲染骨架;Drawer 内容高度 min 30% / max 80%(--vh,content-driven),消除「空内容闪现→撑到最大高度」卡顿 |
| 2026-06-29 | 1.0.1 | 新增公共组件 Empty(通用空态:居中 + 通用 lucide Inbox 图标,text/description/icon/iconSize/class/testid/children 可配)+ 类型 EmptyProps,顶层//components//types 导出;商品橱窗(暂无商品)、营销面板(暂无优惠券)空态统一复用(全量空态场景排查后仅此两处面向用户) |
| 2026-06-29 | 1.0.1 | 商品橱窗/商品卡片交互事件补齐:新增 goods.card.click(卡片整体点击,列表卡+浮窗卡)、goods.promotion.click(促销标签,纯外抛、移除 SDK 自开营销面板、host 可回调 openGoodsMarketing)、goods.cart.add(加入购物车按钮,非积分商品)、goods.cart.open/goods.order.open(橱窗标题栏购物车/订单入口,纯外抛);Drawer 新增 headerRight snippet 槽承载标题栏入口。i18n:新增 15 个 goods.* key(title/loading/empty/cart_entry/order_entry/add_to_cart/explaining/sold_out/promotion/buy_now_full/exchange/price_pending/price_hidden/go_check/close),GoodsListPanel/HotSellCard 全量用户可见文案走 sdk.t()(共 50 key)。⚠️ 破坏性:浮窗卡(HotSellCard)购买按钮由 interact.cart 统一为 goods.buy,旧宿主需迁移 |
| 2026-06-30 | 1.0.1 | 主题变量统一 shadcn token:移除 --live-*/--livesdk-* 前缀,全量改用 bg-primary/text-primary/bg-secondary 等工具类(/10 透明生效);--primary 改珊瑚 10 100% 63%、新增 --secondary 粉 330 81% 60%(:root+.dark);SDKTheme 颜色字段映射到 shadcn HSL 通道(primaryColor→--primary 等,hex 自动转通道,applySDKTheme 增 toHslChannels);移除 dead legacy token + tailwind colors.live.* + 已退役导出 applyTheme/DEFAULT_THEME/ThemeConfig/CSS_VAR_MAP。⚠️ 破坏性:旧 --live-primary-color/--livesdk-* 变量与 applyTheme API 删除,自定义主题样式需迁 shadcn token |
| 2026-06-29 | 1.0.1 | Drawer 公共组件优化:① 移除手势下拖关闭——删 draggable/showHandle 字段、grip 把手及全部触摸拖拽逻辑(仅保留遮罩点击 / × 按钮关闭);② 新增 safeAreaBottom(默认 true),panel 容器加 env(safe-area-inset-bottom),footer(确认按钮)/body 均避开 home indicator,原 body 内 env 内边距移除避免重复间距。破坏性:DrawerProps 删 draggable/showHandle(无内部消费方,仅类型层) |
| 2026-06-30 | 1.0.1 | 新增轻量 toast(小程序 wx.showToast 风格,独立于 svelte-sonner 的 sdk.toast):实例方法 sdk.showToast({ content, duration?, mask? }) / sdk.hideToast()(链式 this)。全局单例——再次 showToast 仅替换内容并重置计时(不堆叠);默认 5s 自动关(duration<=0 不自动关);mask=true 透明蒙层拦截底层点击(默认 false 穿透);≤2 行 / ≤90% 宽 / 顶层 z=100000。SDK 内部核心层可经 this.showToast() 调用,destroy()/直播结束自动清场。SDKConfig 无变化 |
| 2026-06-30 | 1.0.1 | 播放错误提示「直播信号加载失败,请稍后重试」由 Player 内自建遮罩层(player-error-overlay/player-error-prompt,z-100 黑底胶囊)改为走 SDK 统一 sdk.showToast(顶层轻量 toast):Player.svelte 由 showErrorPrompt effect 在 hasError && (isPlayable|isReplay) 跳变 true 时弹一次(保留封面/已结束态不提示的守卫)。原 player-error-overlay/player-error-prompt testid 移除。视觉上提示由播放区内胶囊变为顶层 toast |
| 2026-06-30 | 1.0.1 | 轻量 toast 改为容器内渲染:<LightToast> 由挂 document.body(fixed 整屏)改为挂 SDK 容器内(absolute inset-0,仅覆盖 SDK 容器,非整屏),随 mount()/destroy() 挂卸(替换原 acquire/release 引用计数 + body root 方案)。容器内顶层 z=100000 不变。SDK 挂载容器新增 livesdk-container class 标识(与 LiveRoom 内 .livesdk-root 房间盒子区分,供宿主/CSS 定位 SDK 挂载根),destroy() 移除 |
| 2026-07-05 | 1.2.0 | 起播视觉与「取消静音播放」CTA 优化(纯内部行为,无 SDKConfig/API/事件变更):① 全局 loading 收起时机由 player.playing(‘play’ 意图)改为 player.firstframe(真首帧),并令 <video> 起播前透明、首帧后 0.3s 淡入(Player 容器 video-pending 类),消除「loading 提前收起→黑底闪一下→出帧」的画面闪烁;② CTA 显示时机收敛为「真首帧后且仍静音」(playerStore.hasFirstFrame 门控),不再在缓冲/loading 期提前显示——浏览器与微信同逻辑;③ 微信桥接:bridgeUnlockPending 默认 true 杜绝「先显后隐」闪烁,回调兜底窗口 5s→10s,新增 bridgeUnlockTimedOut 让桥接失败(无首帧)时仍兜底显 CTA |
| 2026-07-08 | 1.2.0 | HotSellCard 价格三态对齐 GoodsListPanel(隐价 待开价 gray-400、积分商品 {price}元 + CTA 立即兑换、正常 ¥{price} + CTA 抢购;卖光由 goods-sellout-mask 遮罩表达,删除价格区 去看看 死代码分支;判定顺序 priceHidden > scoreGoods > 正常)。i18n:删除 goods.price_hidden / goods.go_check 两个 key(改用既有 goods.price_pending)。⚠️ 破坏性:类型化 i18n 覆盖方(config.options.i18n: Partial<I18nMessages>)传入已删 key 编译期报错。无 SDKConfig/API/事件/主题/导出/UMD 全局变更 |
| 2026-07-08 | 1.2.0 | 商品列表排序与讲解置顶:goodsListStore.list getter 由「Map 插入序」改为集中排序——讲解品(explainStatus===1)置顶、其余按 seq 升序、numIid 字典序确定性 tiebreak(规避旧 WebView Array.sort 不稳定)。goods.list 事件 payload 顺序随之变更(影响面 = 首屏 HTTP 拉取那次 emit,GoodsListFetcher.doFetch 全局唯一 emit 点;WS 增量更新不重发该事件)。GoodsListPanel 讲解中卡片整体高亮(bg-primary/5 浅底 + rounded-xl + 去分隔线 + transition-all,与置顶同源;保留底部「讲解中」角标双重强调)。讲解结束自动回 seq 原位、抢光仍置顶。无 SDKConfig/API/事件名变更 |
| 2026-07-08 | 1.2.0 | 商品橱窗空态/加载态/错误兜底三态分离:① 首开骨架 loading(既有,loaded=false 渲染 6 条 animate-pulse 占位,避免空内容闪现 + 高度跳变);② 拉取失败重试入口(新增)——GoodsListFetcher HTTP 失败不再静默返空导致骨架永久转圈,改为 store.markError() 标记错误 + emit goods.list.error {message?};橱窗在「无任何成功数据」(error && !loaded) 时渲染错误态(CloudAlert 图标 + goods.load_failed/goods.load_failed_desc 文案 + 「重新加载」按钮),点按钮 emit goods.list.retry → ProductListEntry 触发 fetcher 重新拉取(发起即 clearError 回骨架态 → 出结果);③ 空态区分——loaded=true && list=[] 显「暂无商品」(真的空),与「拉取失败」错误态严格区分;已有数据后 refetch 失败(loaded=true && error) 不夺走列表(错误为瞬时)。新增事件 goods.list.error / goods.list.retry;新增 i18n key goods.load_failed / goods.load_failed_desc / goods.retry;goodsListStore 新增 error getter + markError() / clearError()。无 SDKConfig/API/主题/导出/UMD 全局变更 |