UNPKG

@realsee/vr-signals

Version:

vr 信号器

943 lines (731 loc) 25.1 kB
# @realsee/vr-signals VR 信号通信库,用于在 VR 应用和父窗口之间建立双向通信。 ## 特性 - 🔄 自动握手和连接管理 - 📡 双向消息通信 - 🚀 智能重试策略(指数退避 + 抖动) - 🔌 自动重连机制 - 📝 详细的日志记录 - 🎯 类型安全的 API - 🛡️ **企业级安全特性** - ✨ **开箱即用的核心类型** - 无需传入泛型参数 ## 🆕 核心类型支持 SDK 现在提供了核心类型支持,包含了必要的 Action 和 Event。这意味着你可以直接使用 SDK,无需定义自己的类型映射: ## 🚀 动态 Action 注册系统 SDK 现在支持动态注册和移除 Actions,无需在初始化时传入完整的 `actionMap`: ### Remote 端动态管理 ```typescript import { RealseeVRSignalsRemote } from '@realsee/vr-signals' const remote = new RealseeVRSignalsRemote({ logLevel: 'INFO' }) // 动态注册单个 Action remote.registerAction('setState', async (data) => { console.log('setState 被调用:', data) // data 包含 mode, longitude, latitude, fov 等 Five SDK 状态 return { success: true, message: '状态已设置' } }) // 批量注册 Actions remote.registerActions({ 'updateCamera': async (data) => { console.log('updateCamera 被调用:', data) // data.state 包含 longitude, latitude, fov, offset 等 Five SDK 相机状态 return { success: true, message: '相机已更新' } }, 'tag.changeData': async (data) => { console.log('tag.changeData 被调用:', data) return { success: true, message: '标签已更新' } } }) // 移除 Action remote.unregisterAction('tag.changeData') // 监听 Action 变化 remote.onActionChange((event) => { console.log('Action 变化:', event) }) // 获取统计信息 const stats = remote.getActionStats() console.log('已注册 Actions:', stats.registered) ``` ### Client 端智能检查 ```typescript import { RealseeVRSignalsClient } from '@realsee/vr-signals' const client = new RealseeVRSignalsClient({ vrLink: 'http://localhost:3000/vr-app', element: iframeElement }) // 检查 Action 是否可用 if (client.isActionAvailable('setState')) { // 安全调用 const result = await client.send('setState', { mode: 'panorama', longitude: 0, latitude: 0, fov: 90 }) console.log('结果:', result) } else { console.log('setState 不可用') } // 监听 Action 可用性变化 client.onActionAvailabilityChange('setState', (available) => { if (available) { console.log('setState 现在可用了!') } else { console.log('setState 不可用了') } }) // 等待特定 Action 可用 try { await client.waitForAction('setState', 5000) console.log('setState 可用,开始调用...') await client.send('setState', { mode: 'panorama', longitude: 0, latitude: 0, fov: 90 }) } catch (error) { console.log('等待超时:', error.message) } // 获取可用 Actions 列表 const availableActions = client.getAvailableActions() console.log('可用的 Actions:', availableActions) ``` ### 无需泛型的简单用法 ```typescript import { RealseeVRSignalsClient, RealseeVRSignalsRemote } from '@realsee/vr-signals' // 客户端 - 无需泛型 const client = new RealseeVRSignalsClient({ vrLink: 'http://localhost:3000/vr-app', element: document.getElementById('vr-container') as HTMLDivElement, logLevel: 'INFO' }) // 服务端 - 无需泛型 const remote = new RealseeVRSignalsRemote({ logLevel: 'INFO', actionMap: { setState(data) { console.log('State update:', data) // data 包含 mode, longitude, latitude, fov 等 Five SDK 状态 return { success: true } }, updateCamera({ state }) { console.log('Camera update:', state) // state 包含 longitude, latitude, fov, offset 等 Five SDK 相机状态 return { success: true } } } }) // 直接使用预定义的事件和动作 client.on('stateSynced', (data) => { console.log('State synced:', data) // data 包含 mode, longitude, latitude, fov 等 Five SDK 状态 }) client.on('cameraUpdate', (data) => { console.log('Camera updated:', data.state) // data.state 包含 longitude, latitude, fov, offset 等 Five SDK 相机状态 }) client.on('tag.click', (data) => { console.log('Tag clicked:', data.data.title) }) client.on('monitor.open', (data) => { console.log('Monitor opened:', data.data.name) }) client.on('monitor.close', (data) => { console.log('Monitor closed:', data.data.name) }) client.on('overlay.visible', (data) => { console.log('Overlay visibility:', data.visible) }) // 发送动作 client.send('setState', { mode: 'panorama', longitude: 0, latitude: 0, fov: 90 }) client.send('updateCamera', { state: { longitude: 0, latitude: 0, fov: 90, offset: { x: 0, y: 0, z: 0 } } }) // 发送事件 remote.sendEvent('stateSynced', { mode: 'editing', view: 'panorama' }) remote.sendEvent('cameraUpdate', { state: { longitude: 0, latitude: 0, fov: 90, offset: { x: 0, y: 0, z: 0 } }, userAction: false }) ``` ### 已实现的核心功能 SDK 包含了以下核心功能: #### 🎮 Actions(动作) - **状态管理**: `setState` - 设置应用状态 - **相机控制**: `updateCamera` - 更新相机状态 #### 📡 Events(事件) - **状态同步**: `stateSynced` - 状态同步事件 - **相机事件**: `cameraUpdate` - 相机更新事件 - **标签事件**: `tag.click` - 标签点击事件 - **监控事件**: `monitor.open`, `monitor.close` - 监控开启/关闭事件 - **覆盖层事件**: `overlay.visible` - 覆盖层显示/隐藏事件 ### 高级用法 - 扩展核心类型 如果你需要添加自定义功能,仍然可以使用泛型: ```typescript import { RealseeVRSignalsClient, DefaultActionMap, DefaultEventMap } from '@realsee/vr-signals' // 扩展核心类型 interface CustomActionMap extends DefaultActionMap { 'custom.action': (data: { message: string }) => Promise<{ result: string }> } interface CustomEventMap extends DefaultEventMap { 'custom.event': (data: { message: string }) => void } // 使用扩展的类型 const customClient = new RealseeVRSignalsClient<CustomActionMap, CustomEventMap>({ vrLink: 'http://localhost:3000/vr-app', element: document.getElementById('vr-container') as HTMLDivElement }) // 使用核心功能 customClient.on('cameraUpdate', (data) => { console.log('Camera updated:', data.state) }) // 使用自定义功能 customClient.on('custom.event', (data) => { console.log('Custom event:', data.message) }) customClient.send('custom.action', { message: 'Hello' }) ``` ## 安全特性 ### 🚨 安全风险提醒 **重要**:为了兼容 1.x 版本,2.x 版本默认禁用了严格的安全模式: - 默认允许所有域名的跨域通信 - 这提供了与 1.x 版本的最大兼容性 - 在生产环境中建议启用安全模式以提高安全性 ### 🛡️ 内置安全机制 1. **Origin 验证**:验证消息来源域名 2. **消息结构验证**:验证消息格式和必需字段 3. **时间戳验证**:防止重放攻击 4. **消息签名**:可选的数字签名验证 5. **严格模式**:限制只允许可信域名 6. **🆕 自适应策略**:智能识别 iframe 和父级窗口的域名关系 ### 🔄 自适应安全策略 **自适应策略**是 `vr-signals` 的核心安全特性,能够智能识别和适应不同的域名关系: #### 自动识别的场景 - **同源环境**:`http://localhost:3000` ↔ `http://localhost:3000` ✅ - **同域名不同端口**:`http://localhost:3000` ↔ `http://localhost:1234` ✅ - **同域名不同协议**:`http://example.com` ↔ `https://example.com` ✅ - **子域名关系**:`https://app.example.com` ↔ `https://vr.example.com` ✅ - **恶意域名**:`https://app.example.com` ↔ `https://malicious-site.com` ❌ #### 自适应策略优势 1. **🎯 零配置**:开发环境无需手动配置域名白名单 2. **🔧 自动适应**:自动处理 localhost 不同端口的情况 3. **🌐 智能识别**:自动识别同域名下的子域名关系 4. **🛡️ 安全可靠**:完全避免使用危险的通配符 5. **⚡ 开箱即用**:减少配置错误和安全漏洞 ### 🔒 安全配置示例 #### 完全自适应模式(推荐用于所有环境) ```typescript const adaptiveClient = new RealseeVRSignalsClient({ vrLink: 'http://localhost:1234/vr-app', element: iframeElement, // 安全配置:完全自适应 security: { strictMode: true, // 启用严格模式 validateOrigin: true, // 验证消息来源 validateSignature: false, // 开发环境不启用签名验证 signatureKey: undefined } }) ``` #### 生产环境配置(自适应 + 签名验证) ```typescript const productionClient = new RealseeVRSignalsClient({ vrLink: 'https://vr-app.example.com', element: iframeElement, // 安全配置:自适应 + 签名验证 security: { strictMode: true, validateOrigin: true, validateSignature: true, // 启用消息签名验证 signatureKey: 'your-secret-key' // 签名密钥 } }) ``` ## 安装 ```bash npm install @realsee/vr-signals ``` ## 基本用法 ### 🆕 客户端(父窗口)- 使用核心类型 ```typescript import { RealseeVRSignalsClient } from '@realsee/vr-signals' // 无需泛型参数,直接使用核心类型 const client = new RealseeVRSignalsClient({ vrLink: 'http://localhost:3000/vr-app', element: iframeElement, logLevel: 'INFO', // 自定义握手重试策略 handshakeRetryStrategy: { baseDelay: 500, // 基础延迟 500ms maxDelay: 5000, // 最大延迟 5s jitterRange: [0.85, 1.15] // 抖动因子范围 }, // 自定义重连策略 reconnectStrategy: { baseDelay: 2000, // 基础重连延迟 2s maxDelay: 30000, // 最大重连延迟 30s jitterRange: [0.8, 1.2] // 抖动因子范围 }, shakehandRetryTimes: 10, // 握手重试次数 enableAutoReconnect: true, // 启用自动重连 maxReconnectAttempts: 5 // 最大重连次数 }) // 监听连接状态 client.onConnectionStatusChange((status) => { console.log('Connection status:', status) }) // 等待连接就绪 client.onReady(() => { console.log('Client is ready!') }) // 发送核心动作(无需类型声明) client.send('setState', { mode: 'panorama', longitude: 0, latitude: 0, fov: 90 }) client.send('updateCamera', { state: { longitude: 0, latitude: 0, fov: 90, offset: { x: 0, y: 0, z: 0 } } }) // 监听核心事件(无需类型声明) client.on('stateSynced', (data) => { console.log('State synced:', data) // data 包含 mode, longitude, latitude, fov 等 Five SDK 状态 }) client.on('cameraUpdate', (data) => { console.log('Camera updated:', data.state) // data.state 包含 longitude, latitude, fov, offset 等 Five SDK 相机状态 }) client.on('tag.click', (data) => { console.log('Tag clicked:', data.data.title) }) client.on('monitor.open', (data) => { console.log('Monitor opened:', data.data.name) }) client.on('monitor.close', (data) => { console.log('Monitor closed:', data.data.name) }) client.on('overlay.visible', (data) => { console.log('Overlay visibility:', data.visible) }) ``` ### 🆕 服务端(VR 应用)- 使用核心类型 ```typescript import { RealseeVRSignalsRemote } from '@realsee/vr-signals' // 无需泛型参数,直接使用核心类型 const remote = new RealseeVRSignalsRemote({ logLevel: 'INFO', actionMap: { // 处理来自父窗口的核心请求 setState(data) { console.log('Received state update request:', data) // data 包含 mode, longitude, latitude, fov 等 Five SDK 状态 // 执行状态更新逻辑 return { success: true } }, updateCamera({ state }) { console.log('Received camera update request:', state) // state 包含 longitude, latitude, fov, offset 等 Five SDK 相机状态 // 执行相机更新逻辑 return { success: true } } } }) // 等待连接就绪 remote.onReady(() => { console.log('Remote is ready!') }) // 发送核心事件到父窗口(无需类型声明) remote.sendEvent('stateSynced', { mode: 'panorama', longitude: 0, latitude: 0, fov: 90 }) remote.sendEvent('cameraUpdate', { state: { longitude: 0, latitude: 0, fov: 90, offset: { x: 0, y: 0, z: 0 } }, userAction: false }) remote.sendEvent('tag.click', { id: 'tag1', data: { id: 'tag1', title: '标签标题', description: '标签描述', type: 'info', extraData: '额外数据' } }) remote.sendEvent('monitor.open', { id: 'monitor1', data: { id: 'monitor1', name: '监控1号', videoSrc: 'http://example.com/video1.mp4', type: 'camera', extraData: '监控数据' } }) remote.sendEvent('monitor.close', { id: 'monitor1', data: { id: 'monitor1', name: '监控1号', videoSrc: 'http://example.com/video1.mp4', type: 'camera', extraData: '监控数据' } }) remote.sendEvent('overlay.visible', { visible: true }) ``` ### 🔧 传统用法 - 自定义类型(仍然支持) 如果你需要自定义类型,仍然可以使用泛型: ```typescript // 定义自定义类型 type CustomActionMap = { 'custom.method': (data: { message: string }) => Promise<{ result: string }> } type CustomEventMap = { 'custom.event': (data: { message: string }) => void } // 使用自定义类型 const customClient = new RealseeVRSignalsClient<CustomActionMap, CustomEventMap>({ vrLink: 'http://localhost:3000/vr-app', element: iframeElement }) const customRemote = new RealseeVRSignalsRemote<CustomActionMap, CustomEventMap>({ logLevel: 'INFO', actionMap: { 'custom.method': async (data) => { return { result: `Processed: ${data.message}` } } } }) ``` ## 重试策略配置 ### 握手重试策略 握手重试使用指数退避策略,避免频繁重试: ```typescript handshakeRetryStrategy: { baseDelay: 500, // 基础延迟时间(毫秒) maxDelay: 5000, // 最大延迟时间(毫秒) jitterRange: [0.85, 1.15] // 抖动因子范围 } ``` **延迟计算示例:** - 第1次重试:500ms × 2⁰ = 500ms - 第2次重试:500ms × 2¹ = 1000ms - 第3次重试:500ms × 2² = 2000ms - 第4次重试:500ms × 2³ = 4000ms - 第5次重试:500ms × 2⁴ = 5000ms(达到最大值) ### 重连策略 重连也使用指数退避策略: ```typescript reconnectStrategy: { baseDelay: 2000, // 基础重连延迟时间(毫秒) maxDelay: 30000, // 最大重连延迟时间(毫秒) jitterRange: [0.8, 1.2] // 抖动因子范围 } ``` **延迟计算示例:** - 第1次重连:2000ms × 2⁰ = 2000ms - 第2次重连:2000ms × 2¹ = 4000ms - 第3次重连:2000ms × 2² = 8000ms - 第4次重连:2000ms × 2³ = 16000ms - 第5次重连:2000ms × 2⁴ = 30000ms(达到最大值) ### 抖动策略 抖动策略用于避免多个客户端同时重试,减少网络拥塞: - **握手抖动**:0.85-1.15 倍随机因子 - **重连抖动**:0.8-1.2 倍随机因子 ## 安全最佳实践 ### 🚨 生产环境安全要求 1. **必须启用严格模式**:`strictMode: true` 2. **必须验证消息来源**:`validateOrigin: true` 3. **建议启用消息签名**:`validateSignature: true` 4. **无需配置域名白名单**:系统自动适应 ### 🔧 开发环境配置 ```typescript security: { strictMode: true, validateOrigin: true, validateSignature: false // 开发环境可选 } ``` ### 🧪 测试环境配置 ```typescript security: { strictMode: true, // 测试环境建议启用 validateOrigin: true, // 建议验证来源 validateSignature: false // 测试环境可选 } ``` ### 🌟 自适应策略优势 - **🎯 零配置**:无需手动配置域名白名单 - **🔧 自动适应**:自动处理 localhost 不同端口 - **🌐 智能识别**:自动识别同域名下的子域名关系 - **🛡️ 安全可靠**:完全避免使用危险的通配符 - **⚡ 开箱即用**:减少配置错误和安全漏洞 ## API 参考 ### RealseeVRSignalsClient #### 构造函数选项 | 选项 | 类型 | 默认值 | 描述 | |------|------|--------|------| | `vrLink` | `string` | - | VR 应用链接(可选) | | `element` | `HTMLElement` | - | iframe 或容器元素(可选) | | `logLevel` | `LogLevel` | `'NONE'` | 日志级别 | | `handshakeRetryStrategy` | `object` | 见下方 | 握手重试策略 | | `reconnectStrategy` | `object` | 见下方 | 重连策略 | | `shakehandRetryTimes` | `number` | `10` | 握手重试次数 | | `enableAutoReconnect` | `boolean` | `true` | 是否启用自动重连 | | `maxReconnectAttempts` | `number` | `5` | 最大重连次数 | | `security` | `object` | 见下方 | **安全配置** | #### 握手重试策略选项 | 选项 | 类型 | 默认值 | 描述 | |------|------|--------|------| | `baseDelay` | `number` | `500` | 基础延迟时间(毫秒) | | `maxDelay` | `number` | `5000` | 最大延迟时间(毫秒) | | `jitterRange` | `[number, number]` | `[0.85, 1.15]` | 抖动因子范围 | #### 重连策略选项 | 选项 | 类型 | 默认值 | 描述 | |------|------|--------|------| | `baseDelay` | `number` | `2000` | 基础重连延迟时间(毫秒) | | `maxDelay` | `number` | `30000` | 最大重连延迟时间(毫秒) | | `jitterRange` | `[number, number]` | `[0.8, 1.2]` | 抖动因子范围 | #### **安全配置选项** | 选项 | 类型 | 默认值 | 描述 | |------|------|--------|------| | `strictMode` | `boolean` | `false` | 是否启用严格模式(兼容 1.x 版本) | | `validateOrigin` | `boolean` | `false` | 是否验证消息来源(兼容 1.x 版本) | | `validateSignature` | `boolean` | `false` | 是否验证消息签名 | | `signatureKey` | `string` | - | 消息签名密钥 | ### 🆕 核心类型支持 SDK 现在提供了核心类型支持,包含以下功能: #### 预定义的 Actions - **状态管理**: `setState` - 设置应用状态 - **相机控制**: `updateCamera` - 更新相机状态 #### 预定义的 Events - **状态同步**: `stateSynced` - 状态同步事件 - **相机事件**: `cameraUpdate` - 相机更新事件 - **标签事件**: `tag.click` - 标签点击事件 - **监控事件**: `monitor.open`, `monitor.close` - 监控开启/关闭事件 - **覆盖层事件**: `overlay.visible` - 覆盖层显示/隐藏事件 ## 🔄 兼容性说明 **重要**:本版本 (2.0.0-beta.3) 完全向后兼容旧版本,但建议迁移到新的 API。 ### 🚨 1.x 版本兼容性问题 如果你正在使用 1.x 版本的 SDK,可能会遇到通信失败的问题。这是因为 2.x 版本默认启用了严格的安全模式。 #### 问题原因 - 1.x 版本使用通配符 `*` 进行跨域通信 - 2.x 版本默认启用严格的安全验证 - 安全机制会拒绝来自不可信域名的消息 #### 解决方案 **方案 1:使用兼容性配置(推荐)** ```typescript import { RealseeVRSignalsClient, getV1CompatibilityConfig } from '@realsee/vr-signals' const client = new RealseeVRSignalsClient({ vrLink: 'http://localhost:3000/vr-app', element: iframeElement, security: getV1CompatibilityConfig() // 自动配置 1.x 兼容性 }) ``` **方案 2:手动禁用安全验证** ```typescript const client = new RealseeVRSignalsClient({ vrLink: 'http://localhost:3000/vr-app', element: iframeElement, security: { strictMode: false, // 禁用严格模式 validateOrigin: false, // 禁用来源验证 validateSignature: false // 禁用签名验证 } }) ``` **方案 3:自动检测环境** ```typescript import { RealseeVRSignalsClient, getAutoCompatibilityConfig } from '@realsee/vr-signals' const client = new RealseeVRSignalsClient({ vrLink: 'http://localhost:3000/vr-app', element: iframeElement, security: getAutoCompatibilityConfig() // 自动检测并配置 }) ``` #### 兼容性工具函数 ```typescript import { getV1CompatibilityConfig, // 获取 1.x 兼容配置 getAutoCompatibilityConfig, // 自动检测环境配置 isV1Environment // 检测是否为 1.x 环境 } from '@realsee/vr-signals' // 检测环境 if (isV1Environment()) { console.log('检测到 1.x 版本环境,使用兼容配置') } ``` ### 主要变化 - **方法名变化**:`callAction()` → `send()`(旧方法仍可用,但会显示警告) - **属性变化**:`subscribe` → 直接使用 Client 实例(旧属性仍可用,但会显示警告) - **构造函数参数**:`vrLink` 和 `element` 在类型定义中变为可选(运行时验证仍然存在) - **核心类型支持**:无需泛型参数即可使用核心功能 ### 快速迁移 ```typescript // 旧用法(仍然支持) const result = await client.callAction('setState', { mode: 'editing' }) client.subscribe.on('cameraUpdate', handler) // 新用法(推荐) const result = await client.send('setState', { mode: 'editing' }) client.on('cameraUpdate', handler) ``` ## 迁移指南 ### 从旧版本迁移 如果你正在使用旧版本的 VR Signals SDK,迁移到新版本非常简单: #### 1. 更新依赖 ```bash npm install @realsee/vr-signals@latest ``` #### 2. 简化客户端代码 **旧版本(需要泛型)** ```typescript interface MyActionMap { setState: (data: any) => void updateCamera: (data: { state: any }) => void } const client = new RealseeVRSignalsClient<MyActionMap>({ vrLink: 'http://localhost:3000/vr-app', element: iframeElement }) ``` **新版本(无需泛型)** ```typescript const client = new RealseeVRSignalsClient({ vrLink: 'http://localhost:3000/vr-app', element: iframeElement }) ``` #### 3. 简化服务端代码 **旧版本(需要泛型)** ```typescript interface MyActionMap { setState: (data: any) => void updateCamera: (data: { state: any }) => void } const remote = new RealseeVRSignalsRemote<MyActionMap>({ logLevel: 'INFO', actionMap: { setState(data) { return { success: true } }, updateCamera({ state }) { return { success: true } } } }) ``` **新版本(无需泛型)** ```typescript const remote = new RealseeVRSignalsRemote({ logLevel: 'INFO', actionMap: { setState(data) { return { success: true } }, updateCamera({ state }) { return { success: true } } } }) ``` ### 迁移检查清单 - [ ] 更新依赖到最新版本 - [ ] 移除不必要的类型定义 - [ ] 简化客户端初始化代码 - [ ] 简化服务端初始化代码 - [ ] 测试核心的事件和动作 - [ ] 验证类型安全 ### 注意事项 1. **向后兼容**: 旧版本的泛型用法仍然完全支持 2. **类型安全**: 新版本提供完整的类型安全,无需额外配置 3. **性能**: 核心类型不会影响运行时性能 4. **扩展性**: 仍然可以使用泛型来扩展核心类型 ## 🔄 版本兼容性 ### 1.x ↔ 2.x 兼容性 **好消息!** 2.0 版本默认兼容 1.x 版本,无需特殊配置。 #### 兼容性矩阵 | Client 版本 | Remote 版本 | 兼容性 | 配置要求 | |------------|------------|--------|---------| | 1.x | 1.x | ✅ 完全兼容 | 默认配置 | | 1.x | 2.x | ✅ 兼容 | 默认配置即可(无需特殊配置) | | 2.x | 1.x | ✅ 兼容 | 默认配置即可 | | 2.x | 2.x | ✅ 完全兼容 | 可使用严格安全配置 | #### 使用 2.0 Remote 兼容 1.0 Client ```typescript import { RealseeVRSignalsRemote } from '@realsee/vr-signals' // 默认配置已兼容 1.x Client,无需特殊配置 const remote = new RealseeVRSignalsRemote({ logLevel: 'INFO', actionMap: { setState(data) { return { success: true } } } }) ``` #### 显式使用兼容配置(可选) ```typescript import { RealseeVRSignalsRemote, getV1CompatibilityConfig } from '@realsee/vr-signals' const remote = new RealseeVRSignalsRemote({ security: getV1CompatibilityConfig(), // 显式声明兼容 1.x actionMap: { /* ... */ } }) ``` #### 2.x 高安全模式(仅用于 2.x Client + 2.x Remote) ```typescript import { RealseeVRSignalsRemote, getV2DefaultConfig } from '@realsee/vr-signals' const remote = new RealseeVRSignalsRemote({ security: getV2DefaultConfig('my-secret-key'), // 启用签名验证等高级安全特性 actionMap: { /* ... */ } }) ``` 详见 [兼容性指南](./COMPATIBILITY.md) 和 [版本差异分析](./VERSION_DIFF.md)。 ## 📚 API 文档 本项目使用 TypeDoc 自动生成 API 文档,并通过 npm 包发布。 ### 本地预览 ```bash # 生成文档 npm run docs # 启动本地服务器预览 npm run docs:serve # 监听文件变化并自动重新生成 npm run docs:watch ``` ### 在线文档 - **API 文档**: https://unpkg.com/@realsee/vr-signals@latest/docs/ - **文档说明**: 查看 [DOCS.md](./DOCS.md) 了解详细的文档生成和发布流程 ## 许可证 MIT