@antglobal/rlog-sdk 0.0.1755855517-dev.9 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/README.md +192 -432
  2. package/dist/esm/index.d.ts +14 -41
  3. package/dist/esm/index.d.ts.map +1 -1
  4. package/dist/esm/index.js +92 -76
  5. package/dist/esm/lib/api.d.ts +10 -0
  6. package/dist/esm/lib/api.d.ts.map +1 -1
  7. package/dist/esm/lib/api.js +58 -35
  8. package/dist/esm/lib/config.d.ts +13 -6
  9. package/dist/esm/lib/config.d.ts.map +1 -1
  10. package/dist/esm/lib/config.js +61 -33
  11. package/dist/esm/lib/constants.d.ts +89 -0
  12. package/dist/esm/lib/constants.d.ts.map +1 -0
  13. package/dist/esm/lib/constants.js +145 -0
  14. package/dist/esm/lib/drive/indexeddb-adapt.d.ts +12 -0
  15. package/dist/esm/lib/drive/indexeddb-adapt.d.ts.map +1 -1
  16. package/dist/esm/lib/drive/indexeddb-adapt.js +190 -20
  17. package/dist/esm/lib/drive/localstorage-adapt.d.ts +12 -0
  18. package/dist/esm/lib/drive/localstorage-adapt.d.ts.map +1 -1
  19. package/dist/esm/lib/drive/localstorage-adapt.js +179 -36
  20. package/dist/esm/lib/drive/memory-adapt.d.ts +10 -2
  21. package/dist/esm/lib/drive/memory-adapt.d.ts.map +1 -1
  22. package/dist/esm/lib/drive/memory-adapt.js +118 -26
  23. package/dist/esm/lib/drive/safe-storage.d.ts +24 -0
  24. package/dist/esm/lib/drive/safe-storage.d.ts.map +1 -0
  25. package/dist/esm/lib/drive/safe-storage.js +96 -0
  26. package/dist/esm/lib/drive/storage-interface.d.ts +20 -0
  27. package/dist/esm/lib/drive/storage-interface.d.ts.map +1 -1
  28. package/dist/esm/lib/error-trigger.d.ts +73 -0
  29. package/dist/esm/lib/error-trigger.d.ts.map +1 -0
  30. package/dist/esm/lib/error-trigger.js +162 -0
  31. package/dist/esm/lib/error.d.ts +9 -0
  32. package/dist/esm/lib/error.d.ts.map +1 -1
  33. package/dist/esm/lib/error.js +70 -118
  34. package/dist/esm/lib/init.d.ts +0 -4
  35. package/dist/esm/lib/init.d.ts.map +1 -1
  36. package/dist/esm/lib/init.js +148 -47
  37. package/dist/esm/lib/logger.d.ts +27 -0
  38. package/dist/esm/lib/logger.d.ts.map +1 -0
  39. package/dist/esm/lib/logger.js +79 -0
  40. package/dist/esm/lib/net.d.ts +11 -0
  41. package/dist/esm/lib/net.d.ts.map +1 -1
  42. package/dist/esm/lib/net.js +264 -119
  43. package/dist/esm/lib/request.d.ts.map +1 -1
  44. package/dist/esm/lib/request.js +2 -2
  45. package/dist/esm/lib/router-monitor.d.ts.map +1 -1
  46. package/dist/esm/lib/router-monitor.js +135 -49
  47. package/dist/esm/lib/rrweb.d.ts.map +1 -1
  48. package/dist/esm/lib/rrweb.js +31 -24
  49. package/dist/esm/lib/storage-manager.d.ts +12 -0
  50. package/dist/esm/lib/storage-manager.d.ts.map +1 -1
  51. package/dist/esm/lib/storage-manager.js +129 -46
  52. package/dist/esm/lib/upload-worker-manager.d.ts +47 -0
  53. package/dist/esm/lib/upload-worker-manager.d.ts.map +1 -0
  54. package/dist/esm/lib/upload-worker-manager.js +559 -0
  55. package/dist/esm/lib/upload-worker.d.ts +58 -0
  56. package/dist/esm/lib/upload-worker.d.ts.map +1 -0
  57. package/dist/esm/lib/upload-worker.js +28 -0
  58. package/dist/esm/lib/uploader.d.ts +43 -0
  59. package/dist/esm/lib/uploader.d.ts.map +1 -1
  60. package/dist/esm/lib/uploader.js +464 -102
  61. package/dist/esm/lib/utils.d.ts +75 -0
  62. package/dist/esm/lib/utils.d.ts.map +1 -1
  63. package/dist/esm/lib/utils.js +268 -5
  64. package/dist/lib/index.d.ts +14 -41
  65. package/dist/lib/index.d.ts.map +1 -1
  66. package/dist/lib/index.js +81 -63
  67. package/dist/lib/lib/api.d.ts +10 -0
  68. package/dist/lib/lib/api.d.ts.map +1 -1
  69. package/dist/lib/lib/api.js +59 -35
  70. package/dist/lib/lib/config.d.ts +13 -6
  71. package/dist/lib/lib/config.d.ts.map +1 -1
  72. package/dist/lib/lib/config.js +63 -33
  73. package/dist/lib/lib/constants.d.ts +89 -0
  74. package/dist/lib/lib/constants.d.ts.map +1 -0
  75. package/dist/lib/lib/constants.js +151 -0
  76. package/dist/lib/lib/drive/indexeddb-adapt.d.ts +12 -0
  77. package/dist/lib/lib/drive/indexeddb-adapt.d.ts.map +1 -1
  78. package/dist/lib/lib/drive/indexeddb-adapt.js +191 -19
  79. package/dist/lib/lib/drive/localstorage-adapt.d.ts +12 -0
  80. package/dist/lib/lib/drive/localstorage-adapt.d.ts.map +1 -1
  81. package/dist/lib/lib/drive/localstorage-adapt.js +179 -36
  82. package/dist/lib/lib/drive/memory-adapt.d.ts +10 -2
  83. package/dist/lib/lib/drive/memory-adapt.d.ts.map +1 -1
  84. package/dist/lib/lib/drive/memory-adapt.js +117 -26
  85. package/dist/lib/lib/drive/safe-storage.d.ts +24 -0
  86. package/dist/lib/lib/drive/safe-storage.d.ts.map +1 -0
  87. package/dist/lib/lib/drive/safe-storage.js +102 -0
  88. package/dist/lib/lib/drive/storage-interface.d.ts +20 -0
  89. package/dist/lib/lib/drive/storage-interface.d.ts.map +1 -1
  90. package/dist/lib/lib/error-trigger.d.ts +73 -0
  91. package/dist/lib/lib/error-trigger.d.ts.map +1 -0
  92. package/dist/lib/lib/error-trigger.js +167 -0
  93. package/dist/lib/lib/error.d.ts +9 -0
  94. package/dist/lib/lib/error.d.ts.map +1 -1
  95. package/dist/lib/lib/error.js +73 -118
  96. package/dist/lib/lib/init.d.ts +0 -4
  97. package/dist/lib/lib/init.d.ts.map +1 -1
  98. package/dist/lib/lib/init.js +144 -43
  99. package/dist/lib/lib/logger.d.ts +27 -0
  100. package/dist/lib/lib/logger.d.ts.map +1 -0
  101. package/dist/lib/lib/logger.js +84 -0
  102. package/dist/lib/lib/net.d.ts +11 -0
  103. package/dist/lib/lib/net.d.ts.map +1 -1
  104. package/dist/lib/lib/net.js +268 -120
  105. package/dist/lib/lib/request.d.ts.map +1 -1
  106. package/dist/lib/lib/request.js +3 -3
  107. package/dist/lib/lib/router-monitor.d.ts.map +1 -1
  108. package/dist/lib/lib/router-monitor.js +136 -49
  109. package/dist/lib/lib/rrweb.d.ts.map +1 -1
  110. package/dist/lib/lib/rrweb.js +31 -23
  111. package/dist/lib/lib/storage-manager.d.ts +12 -0
  112. package/dist/lib/lib/storage-manager.d.ts.map +1 -1
  113. package/dist/lib/lib/storage-manager.js +130 -46
  114. package/dist/lib/lib/upload-worker-manager.d.ts +47 -0
  115. package/dist/lib/lib/upload-worker-manager.d.ts.map +1 -0
  116. package/dist/lib/lib/upload-worker-manager.js +570 -0
  117. package/dist/lib/lib/upload-worker.d.ts +58 -0
  118. package/dist/lib/lib/upload-worker.d.ts.map +1 -0
  119. package/dist/lib/lib/upload-worker.js +33 -0
  120. package/dist/lib/lib/uploader.d.ts +43 -0
  121. package/dist/lib/lib/uploader.d.ts.map +1 -1
  122. package/dist/lib/lib/uploader.js +468 -101
  123. package/dist/lib/lib/utils.d.ts +75 -0
  124. package/dist/lib/lib/utils.d.ts.map +1 -1
  125. package/dist/lib/lib/utils.js +276 -6
  126. package/dist/rlog-sdk.min.js +1 -1
  127. package/package.json +3 -2
package/README.md CHANGED
@@ -1,485 +1,245 @@
1
- # rlog-sdk 性能与安全设计文档
1
+ # @antglobal/rlog-sdk
2
2
 
3
- ## 动态配置功能
3
+ 基于 [rrweb](https://github.com/rrweb-io/rrweb) 的用户行为录制与上报 SDK,用于 Web 应用的会话回放、错误追踪和行为分析。
4
4
 
5
- ### 1. CDN 配置支持
6
- SDK 现在支持从 CDN 获取动态配置,可以实时调整以下参数:
7
- - 采集总开关
8
- - Canvas 录制采样率
9
- - 数据上传时间间隔
5
+ ## 特性
10
6
 
11
- ### 2. 配置参数说明
12
- CDN 配置文件应为 JSON 格式,包含以下字段:
7
+ - **全量录制** — 持续录制用户操作,定时上传
8
+ - **错误模式录制** 仅在发生错误时上传前后时间窗口内的录制数据
9
+ - **多 Tab 隔离** — 每个标签页独立 Session,分布式锁保证数据安全
10
+ - **存储自动降级** — IndexedDB > LocalStorage > Memory
11
+ - **网络监控** — 拦截 XHR/Fetch,记录请求响应,支持黑白名单过滤
12
+ - **路由监控** — 监听 History API 和 Hash 变化,记录页面停留时间
13
+ - **Console 录制** — 可选的 console 输出捕获(rrweb 插件)
14
+ - **上传重试** — 失败自动重试,超过阈值停止录制并派发事件
15
+ - **Web Worker 上传** — 后台线程上传,不阻塞主线程
16
+ - **只采集不上报** — 可动态切换的 consume-only 模式
17
+ - **自定义事件** — 支持注入业务自定义事件到录制流
18
+ - **错误上报** — 全局 JS 错误和资源加载错误自动捕获
13
19
 
14
- #### 基础配置
15
- ```json
16
- {
17
- "enable": true, // 采集总开关
18
- "samplingRate": 15, // Canvas 采样率 (帧/秒)
19
- "uploadInterval": 2000, // 数据上传时间间隔 (毫秒)
20
- "configUpdateInterval": 300000 // 配置更新时间间隔 (毫秒),默认 5 分钟
21
- }
22
- ```
20
+ ## 安装
23
21
 
24
- #### Console录制插件详细配置
25
- ```json
26
- {
27
- "console": {
28
- "enable": true, // 是否启用console录制
29
- "level": ["log", "warn", "error", "info"], // 需要录制的console方法
30
- "lengthThreshold": 1000, // 最大录制条数,默认1000
31
- "stringifyOptions": {
32
- "stringLengthLimit": 500, // 字符串长度限制
33
- "numOfKeysLimit": 50, // 对象key数量限制,默认50
34
- "depthOfLimit": 4 // 对象深度限制,默认4
35
- }
36
- }
37
- }
22
+ ```bash
23
+ npm install @antglobal/rlog-sdk
38
24
  ```
39
25
 
40
- **支持的console方法级别**:
41
- - `assert`, `clear`, `count`, `countReset`
42
- - `debug`, `dir`, `dirxml`, `error`
43
- - `group`, `groupCollapsed`, `groupEnd`, `info`
44
- - `log`, `table`, `time`, `timeEnd`, `timeLog`, `trace`, `warn`
26
+ ## 快速开始
45
27
 
46
- ### 3. 使用方式
47
- ```javascript
48
- // 初始化时传入 CDN 配置 URL
49
- Rlog.init({
28
+ ```typescript
29
+ import { init } from '@antglobal/rlog-sdk';
30
+
31
+ const rlog = init({
32
+ serv: 'https://your-server.com/api/rlog/record',
50
33
  appId: 'your-app-id',
51
- serv: 'your-upload-server',
52
- cdnConfigUrl: 'https://your-cdn.com/rlog-config.json'
34
+ cdnConfigUrl: 'https://your-cdn.com/rlog-config.json', // 可选,远程动态配置
53
35
  });
54
- ```
55
36
 
56
- ## 请求头注入功能
37
+ // 停止录制
38
+ rlog.cancel();
57
39
 
58
- ### 1. 功能说明
59
- SDK 支持在所有 XMLHttpRequest 和 fetch 请求中自动注入全局自定义请求头,方便添加认证信息、跟踪标识等。
40
+ // 停止录制并清除本地数据
41
+ rlog.cancel({ clearData: true });
42
+ ```
60
43
 
61
- ### 2. 使用方式
62
- ```javascript
63
- // 设置全局自定义请求头
64
- Rlog.setCustomHeaders({
65
- 'Authorization': 'Bearer your-token',
66
- 'X-Request-Id': 'unique-request-id',
67
- 'X-Client-Version': '1.0.0'
68
- });
44
+ ## API
69
45
 
70
- // 设置白名单URL(只有这些URL的请求会被监控和注入请求头)
71
- Rlog.setWhiteListUrls([
72
- 'https://api.your-app.com',
73
- 'https://analytics.your-app.com'
74
- ]);
75
- ```
46
+ ### 核心
76
47
 
77
- ### 3. 实现原理
78
- - 拦截 XMLHttpRequest 和 fetch API
79
- - 在发送请求前自动添加自定义请求头
80
- - 只对白名单中的 URL 注入请求头
81
- - 监控请求结果并记录成功/失败事件
82
-
83
- ## 代码结构优化
84
-
85
- ### 1. 入口文件精简
86
- 入口文件 [`src/index.ts`](src/index.ts) 已经优化得更加精简,只包含必要的导入和导出:
87
- - 导入核心初始化函数
88
- - 导出初始化接口
89
- - 导出自定义事件接口
90
-
91
- ### 2. 模块化设计
92
- 项目现在采用更好的模块化设计,按功能域清晰划分:
93
-
94
- #### 核心模块
95
- - [`src/lib/init.ts`](src/lib/init.ts): 初始化逻辑,负责SDK的启动和配置
96
- - [`src/lib/config.ts`](src/lib/config.ts): 配置管理,支持CDN动态配置
97
- - [`src/lib/rrweb.ts`](src/lib/rrweb.ts): 录制功能,集成rrweb录制器
98
-
99
- #### 数据管理模块
100
- - [`src/lib/storage-manager.ts`](src/lib/storage-manager.ts): 存储管理,统一处理数据存储
101
- - [`src/lib/drive/`](src/lib/drive/): 存储驱动层
102
- - [`indexeddb-adapt.ts`](src/lib/drive/indexeddb-adapt.ts): IndexedDB存储适配器
103
- - [`localstorage-adapt.ts`](src/lib/drive/localstorage-adapt.ts): LocalStorage存储适配器
104
- - [`memory-adapt.ts`](src/lib/drive/memory-adapt.ts): 内存存储适配器
105
- - [`storage-interface.ts`](src/lib/drive/storage-interface.ts): 存储接口定义
106
-
107
- #### 网络通信模块
108
- - [`src/lib/uploader.ts`](src/lib/uploader.ts): 数据上传逻辑,包含重试机制
109
- - [`src/lib/request.ts`](src/lib/request.ts): 网络请求工具,封装HTTP请求
110
- - [`src/lib/net.ts`](src/lib/net.ts): 网络监控,拦截和记录网络请求
111
-
112
- #### 功能扩展模块
113
- - [`src/lib/router-monitor.ts`](src/lib/router-monitor.ts): 路由监控,跟踪页面路由变化
114
- - [`src/lib/api.ts`](src/lib/api.ts): API接口,提供外部调用接口
115
- - [`src/lib/utils.ts`](src/lib/utils.ts): 工具函数,通用工具方法
116
- - [`src/lib/error.ts`](src/lib/error.ts): 错误处理,统一的错误捕获和处理
117
-
118
- #### 架构特点
119
- - **分层架构**: 驱动层、服务层、接口层清晰分离
120
- - **插件化设计**: 各模块可独立启用/禁用
121
- - **高内聚低耦合**: 模块间通过明确定义的接口交互
122
- - **可扩展性**: 易于添加新的存储驱动或功能模块
123
-
124
- ## 请求工具
125
-
126
- ### 1. 工具说明
127
- 项目中封装了兼容性更好的请求工具 [`src/lib/request.ts`](src/lib/request.ts),提供以下功能:
128
- - 兼容性更好的 HTTP 请求(基于 XMLHttpRequest)
129
- - 支持 GET/POST 方法
130
- - 支持超时设置
131
- - 统一的错误处理
132
-
133
- ### 2. 使用方式
134
- ```typescript
135
- import { get, post, request } from './lib/request';
48
+ | 方法 | 说明 |
49
+ |------|------|
50
+ | `init({ serv, appId, cdnConfigUrl? })` | 初始化 SDK,返回 `{ cancel }` |
51
+ | `cancelRecord(options?)` | 停止录制(推荐使用 `rlog.cancel()`) |
52
+ | `addCustomEvent(tag, payload)` | 添加自定义事件到录制流 |
53
+ | `reportError(error)` | 手动上报错误(Error 对象或字符串) |
136
54
 
137
- // GET 请求
138
- const response = await get('https://api.example.com/data');
55
+ ### 网络配置
139
56
 
140
- // POST 请求
141
- const response = await post('https://api.example.com/data', { key: 'value' });
57
+ | 方法 | 说明 |
58
+ |------|------|
59
+ | `setCustomHeaders(headers)` | 设置全局自定义请求头(注入到 XHR/Fetch) |
60
+ | `getCustomHeaders()` | 获取当前自定义请求头 |
61
+ | `setWhiteListUrls(urls)` | 设置白名单 URL(仅监控这些请求) |
62
+ | `getWhiteListUrls()` | 获取白名单 |
63
+ | `setBlackListUrls(urls)` | 设置黑名单 URL(排除这些请求) |
64
+ | `getBlackListUrls()` | 获取黑名单 |
142
65
 
143
- // 自定义请求
144
- const response = await request('https://api.example.com/data', {
145
- method: 'POST',
146
- headers: { 'Content-Type': 'application/json' },
147
- body: JSON.stringify({ key: 'value' }),
148
- timeout: 5000
149
- });
150
- ```
66
+ > 黑名单优先于白名单。白名单为空时监控所有非黑名单请求。
151
67
 
152
- ## 性能优化方案
153
-
154
- ### 1. Canvas录制动态采样
155
- **自适应采样算法**:
156
- ```ts
157
- class SamplingController {
158
- // 设备性能评估
159
- static getSamplingRate(): number {
160
- const isMobile = /Mobi/.test(navigator.userAgent);
161
- const deviceMemory = (navigator as any).deviceMemory || 4;
162
-
163
- // 动态计算采样率:
164
- // 1. 根据设备类型选择基准值
165
- // 2. 根据内存大小动态调整(4GB基准,每增加1GB降低1帧)
166
- // 3. 最低不低于5帧保证录制可用性
167
- const baseRate = isMobile ? 8 : 15;
168
- const memoryFactor = Math.max(0, 4 - (deviceMemory - 4));
169
-
170
- return Math.max(5, baseRate - memoryFactor);
171
- }
172
-
173
- // 实时性能监控(每5秒检测一次)
174
- static startPerformanceMonitor() {
175
- setInterval(() => {
176
- const fps = this.calculateFPS();
177
- if (fps < 15) { // 低性能预警
178
- this.throttleRecording();
179
- } else if (fps > 25) { // 高性能提升
180
- this.boostSampling();
181
- }
182
- }, 5000);
183
- }
184
- }
68
+ ### 路由监控
185
69
 
186
- // 在rrweb初始化时应用
187
- rrweb.record({
188
- sampling: {
189
- canvas: SamplingController.getSamplingRate()
190
- }
191
- });
192
- ```
70
+ | 方法 | 说明 |
71
+ |------|------|
72
+ | `updateRouterConfig(config)` | 更新路由监控配置 |
73
+ | `getCurrentRouteInfo()` | 获取当前路由信息 |
74
+ | `manualRouteChange(newRoute, prevRoute?)` | 手动触发路由变化事件 |
75
+ | `stopRouterMonitor()` | 停止路由监控 |
193
76
 
194
- **性能指标**:
195
- | 指标 | 目标值 | 监控方式 |
196
- |------|-------|---------|
197
- | FPS | ≥15 | requestAnimationFrame |
198
- | 内存占用 | ≤15MB | performance.memory |
199
- | CPU使用率 | ≤30% | navigator.hardwareConcurrency |
200
-
201
- ### 2. 存储性能优化
202
- **批量写入策略**:
203
- ```ts
204
- // IndexedDBAdapter增强
205
- async push(deviceId: string, data: any): Promise<void> {
206
- // 实现批量缓冲
207
- if (!this.writeBuffer) {
208
- this.writeBuffer = [];
209
- // 500ms批量提交
210
- setTimeout(() => this.flushBuffer(), 500);
211
- }
212
- this.writeBuffer.push({ deviceId, data });
213
- }
77
+ ### Consume-Only 模式
214
78
 
215
- private async flushBuffer(): Promise<void> {
216
- if (!this.db || !this.writeBuffer) return;
217
-
218
- const transaction = this.db.transaction(STORE_NAME, 'readwrite');
219
- const store = transaction.objectStore(STORE_NAME);
220
-
221
- // 使用游标批量更新
222
- const cursor = await store.openCursor();
223
- while (cursor) {
224
- const updated = this.writeBuffer.find(
225
- item => item.deviceId === cursor.key
226
- );
227
- if (updated) {
228
- await cursor.update({
229
- ...cursor.value,
230
- data: [...cursor.value.data, ...updated.data]
231
- });
232
- }
233
- await cursor.continue();
234
- }
235
-
236
- this.writeBuffer = null;
237
- }
238
- ```
79
+ | 方法 | 说明 |
80
+ |------|------|
81
+ | `setConsumeOnlyMode(enable)` | 开启/关闭只采集不上报 |
82
+ | `isConsumeOnlyMode()` | 查询当前是否为只采集模式 |
83
+ | `toggleConsumeOnlyMode()` | 切换模式,返回新状态 |
239
84
 
240
- ## 加密模块设计
241
-
242
- ### 1. 加密架构设计
243
- ```mermaid
244
- sequenceDiagram
245
- participant SDK
246
- participant Crypto
247
- participant Storage
248
-
249
- SDK->>Crypto: setEncryptionKey() 设置密钥
250
- SDK->>Crypto: encryptData() 请求加密
251
- Crypto->>Crypto: 生成IV (12字节)
252
- Crypto->>Crypto: 使用AES-GCM加密
253
- Crypto-->>SDK: 返回Base64加密数据
254
- SDK->>Storage: 存储加密数据
255
- ```
85
+ ### 调试工具
256
86
 
257
- ### 2. 加密实现细节
258
- ```ts
259
- // 加密配置接口
260
- interface EncryptionConfig {
261
- enabled: boolean; // 加密开关
262
- algorithm: 'AES-GCM' | 'AES-CBC'; // 算法选择
263
- keyLength: 128 | 192 | 256; // 密钥长度
264
- autoRotate: boolean; // 密钥自动轮换
265
- rotationInterval: number; // 轮换间隔(小时)
266
- }
87
+ 通过 `debug` 对象访问:
267
88
 
268
- // 加密服务实现
269
- class EncryptionService {
270
- private key: CryptoKey | null = null;
271
- private config: EncryptionConfig = {
272
- enabled: false,
273
- algorithm: 'AES-GCM',
274
- keyLength: 256,
275
- autoRotate: true,
276
- rotationInterval: 24
277
- };
278
-
279
- async setKey(key: CryptoKey): Promise<void> {
280
- this.key = key;
281
- if (this.config.autoRotate) {
282
- this.scheduleKeyRotation();
283
- }
284
- }
285
-
286
- async encrypt(data: any): Promise<string> {
287
- if (!this.config.enabled || !this.key) {
288
- return JSON.stringify(data);
289
- }
290
-
291
- const iv = crypto.getRandomValues(new Uint8Array(12));
292
- const encoder = new TextEncoder();
293
- const encrypted = await crypto.subtle.encrypt(
294
- {
295
- name: this.config.algorithm,
296
- iv
297
- },
298
- this.key,
299
- encoder.encode(JSON.stringify(data))
300
- );
301
-
302
- // 返回包含元数据的加密数据
303
- return JSON.stringify({
304
- v: 1, // 版本号
305
- alg: this.config.algorithm,
306
- iv: arrayBufferToBase64(iv),
307
- data: arrayBufferToBase64(encrypted)
308
- });
309
- }
310
-
311
- private scheduleKeyRotation(): void {
312
- setInterval(async () => {
313
- const newKey = await this.generateKey();
314
- await this.rotateKey(newKey);
315
- }, this.config.rotationInterval * 3600000);
316
- }
317
- }
89
+ ```typescript
90
+ import { debug } from '@antglobal/rlog-sdk';
91
+
92
+ debug.getStorageAdapterType(); // 当前存储类型: 'indexeddb' | 'localstorage' | 'memory'
93
+ debug.getDeviceId(); // 设备 ID
94
+ debug.getSessionId(); // 当前 Tab 的 Session ID
95
+ debug.getStorageKey(); // 存储键 (deviceId_sessionId)
96
+ debug.resetUploadState(); // 重置上传状态
97
+ debug.getStorageState(); // Promise<{ adapterType, eventCount }>
98
+ debug.clearStorage(); // Promise<void> 清空存储
99
+ debug.getConfig(); // 当前 CDN 配置
100
+ debug.shouldRecordUrl(url); // 判断 URL 是否会被网络监控记录
318
101
  ```
319
102
 
320
- ### 3. 敏感数据脱敏
321
- ```ts
322
- // 脱敏配置
323
- interface SanitizationRule {
324
- selector: string; // CSS选择器
325
- type: 'mask' | 'hash' | 'remove'; // 脱敏类型
326
- hashAlgorithm?: 'SHA-1' | 'SHA-256'; // 哈希算法
327
- maskChar?: string; // 掩码字符
328
- maskLength?: number; // 掩码长度
329
- }
103
+ ## CDN 动态配置
104
+
105
+ 通过 `cdnConfigUrl` 传入远程 JSON 配置,SDK 会定期拉取更新。完整配置项:
330
106
 
331
- // 脱敏处理器
332
- class DataSanitizer {
333
- private rules: SanitizationRule[] = [
334
- {
335
- selector: 'input[type="password"]',
336
- type: 'mask',
337
- maskChar: '*',
338
- maskLength: 8
339
- },
340
- {
341
- selector: 'input[name="credit-card"]',
342
- type: 'hash',
343
- hashAlgorithm: 'SHA-256'
107
+ ```json
108
+ {
109
+ "enable": false,
110
+ "uploadInterval": 2000,
111
+ "configUpdateInterval": 300000,
112
+ "captureMode": "full",
113
+ "packEvents": false,
114
+ "clearStorageBeforeRecord": true,
115
+ "http": false,
116
+ "maxRetryCount": 3,
117
+ "consumeOnly": false,
118
+ "urlParamsToCache": [],
119
+ "sampling": {
120
+ "canvas": 15,
121
+ "mousemove": 50,
122
+ "scroll": 100,
123
+ "input": "last"
124
+ },
125
+ "ignoreClass": "rr-ignore",
126
+ "blockClass": "rr-block",
127
+ "maskTextClass": "rr-mask",
128
+ "console": {
129
+ "enable": false,
130
+ "level": ["log", "warn", "error", "info"],
131
+ "lengthThreshold": 1000,
132
+ "stringifyOptions": {
133
+ "stringLengthLimit": 500,
134
+ "numOfKeysLimit": 50,
135
+ "depthOfLimit": 4
344
136
  }
345
- ];
346
-
347
- sanitize(data: any): any {
348
- const result = { ...data };
349
-
350
- // 遍历DOM节点应用脱敏规则
351
- document.querySelectorAll('*').forEach(node => {
352
- const element = node as HTMLElement;
353
- this.rules.forEach(rule => {
354
- if (element.matches(rule.selector)) {
355
- switch (rule.type) {
356
- case 'mask':
357
- result.textContent = this.applyMask(
358
- element.textContent || '',
359
- rule.maskChar || '*',
360
- rule.maskLength || 8
361
- );
362
- break;
363
- case 'hash':
364
- result.textContent = this.hashContent(
365
- element.textContent || '',
366
- rule.hashAlgorithm || 'SHA-256'
367
- );
368
- break;
369
- case 'remove':
370
- result.remove();
371
- break;
372
- }
373
- }
374
- });
375
- });
376
-
377
- return result;
137
+ },
138
+ "routerMonitor": {
139
+ "enable": false,
140
+ "trackHashChange": true,
141
+ "trackHistoryChange": true,
142
+ "trackPageStayTime": true,
143
+ "ignoreRoutes": []
144
+ },
145
+ "errorCapture": {
146
+ "beforeDuration": 30000,
147
+ "afterDuration": 30000,
148
+ "httpErrorThreshold": 400
378
149
  }
379
150
  }
380
151
  ```
381
152
 
382
- ## 网络配置API参考
153
+ ### 配置说明
383
154
 
384
- ### 1. 配置方法
155
+ | 字段 | 默认值 | 说明 |
156
+ |------|--------|------|
157
+ | `enable` | `false` | 采集总开关 |
158
+ | `uploadInterval` | `2000` | 上传间隔(ms) |
159
+ | `configUpdateInterval` | `300000` | 配置刷新间隔(ms) |
160
+ | `captureMode` | `"full"` | `"full"` 全量录制 / `"error"` 错误触发录制 |
161
+ | `packEvents` | `false` | 是否压缩事件数据 |
162
+ | `clearStorageBeforeRecord` | `true` | 录制前是否清空存储 |
163
+ | `http` | `false` | 是否开启网络请求监控 |
164
+ | `maxRetryCount` | `3` | 上传失败最大重试次数 |
165
+ | `consumeOnly` | `false` | 只采集不上报 |
166
+ | `sampling.canvas` | `15` | Canvas 采样率(fps) |
167
+ | `sampling.mousemove` | `50` | 鼠标移动采样间隔(ms) |
168
+ | `sampling.scroll` | `100` | 滚动防抖间隔(ms) |
169
+ | `sampling.input` | `"last"` | `"all"` 全部 / `"last"` 仅最终值 |
170
+ | `errorCapture.beforeDuration` | `30000` | 错误前录制时长(ms) |
171
+ | `errorCapture.afterDuration` | `30000` | 错误后继续录制时长(ms) |
172
+ | `errorCapture.httpErrorThreshold` | `400` | HTTP 错误状态码阈值 |
385
173
 
386
- #### setWhiteListUrls(urls: string[])
387
- 设置白名单URL列表,只有这些接口会被记录和监控。
174
+ ## 采集模式
388
175
 
389
- **参数:**
390
- - `urls`: string[] - URL列表,支持完整URL和相对路径
176
+ ### Full 模式(默认)
391
177
 
392
- **示例:**
393
- ```javascript
394
- Rlog.setWhiteListUrls([
395
- 'https://api.example.com',
396
- '/api/v1/', // 相对路径
397
- '/ebank/api/v1/rlog/record'
398
- ]);
399
- ```
178
+ 持续录制所有用户操作,按 `uploadInterval` 定时上传,每批最多 100 条事件。
400
179
 
401
- #### setBlackListUrls(urls: string[])
402
- 设置黑名单URL列表,这些接口将不会被记录和监控。
180
+ ### Error 模式
403
181
 
404
- **参数:**
405
- - `urls`: string[] - URL列表,支持完整URL和相对路径
182
+ 事件持续写入本地存储,仅在错误发生时触发上传。上传时间窗口为 `[now - beforeDuration, now + afterDuration]`。若 `afterDuration` 期间再次发生错误,窗口自动延长。
406
183
 
407
- **示例:**
408
- ```javascript
409
- Rlog.setBlackListUrls([
410
- 'https://api.sensitive.com/user-info',
411
- '/api/auth/token',
412
- '/ebank/api/v1/rlog/record' // 避免循环上报
413
- ]);
414
- ```
184
+ ## 架构
415
185
 
416
- #### getWhiteListUrls(): string[]
417
- 获取当前白名单URL列表。
186
+ ```
187
+ src/
188
+ ├── index.ts # 公共 API 导出
189
+ └── lib/
190
+ ├── init.ts # SDK 初始化与销毁
191
+ ├── config.ts # CDN 配置管理
192
+ ├── rrweb.ts # rrweb 录制启动
193
+ ├── storage-manager.ts # 存储管理(序列化队列)
194
+ ├── uploader.ts # 上传调度(全量/错误模式)
195
+ ├── upload-worker-manager.ts # Web Worker 管理
196
+ ├── upload-worker.ts # Worker 上传逻辑
197
+ ├── net.ts # 网络监控(XHR/Fetch 拦截)
198
+ ├── api.ts # 上传接口
199
+ ├── request.ts # HTTP 请求工具
200
+ ├── router-monitor.ts # 路由监控
201
+ ├── error.ts # 错误捕获
202
+ ├── error-trigger.ts # 错误模式状态机
203
+ ├── utils.ts # 工具函数
204
+ ├── logger.ts # 日志输出
205
+ ├── constants.ts # 常量定义
206
+ └── drive/
207
+ ├── storage-interface.ts # StorageAdapter 接口
208
+ ├── indexeddb-adapt.ts # IndexedDB 适配器
209
+ ├── localstorage-adapt.ts # LocalStorage 适配器(含分布式锁)
210
+ ├── memory-adapt.ts # Memory 适配器
211
+ └── safe-storage.ts # 安全 KV 存储(降级到内存)
212
+ ```
418
213
 
419
- **返回值:**
420
- - string[] - 当前白名单URL列表
214
+ ## 多 Tab 并发
421
215
 
422
- #### getBlackListUrls(): string[]
423
- 获取当前黑名单URL列表。
216
+ - 每个标签页分配唯一 `sessionId`,存储键为 `deviceId_sessionId`
217
+ - Session 注册表追踪活跃标签页
218
+ - SDK 初始化时自动清理孤儿 session 的残留数据
219
+ - LocalStorage 操作通过分布式锁(CAS + 超时)保证原子性
424
220
 
425
- **返回值:**
426
- - string[] - 当前黑名单URL列表
221
+ ## 上传重试
427
222
 
428
- ### 2. 配置优先级
429
- 网络接口的过滤优先级如下:
430
- 1. **黑名单优先**:如果URL在黑名单中,无论是否在白名单都不会被记录
431
- 2. **白名单过滤**:只有在白名单中的URL才会被记录(如果不在黑名单中)
432
- 3. **默认行为**:如果白名单为空,则记录所有不在黑名单中的请求
223
+ 上传失败时事件回退到队列头部,下个周期重试。连续失败达到 `maxRetryCount` 后:
224
+ 1. 派发 `rlog-upload-failure` 自定义事件(window + rrweb)
225
+ 2. 停止 rrweb 录制
226
+ 3. 停止上传循环
433
227
 
434
- ### 3. 路径匹配规则
228
+ 监听失败事件:
435
229
 
436
- #### 完整URL匹配
437
230
  ```javascript
438
- // 匹配以指定URL开头的请求
439
- 'https://api.example.com/v1/users' // 匹配 https://api.example.com/v1/users/123
231
+ window.addEventListener('rlog-upload-failure', (e) => {
232
+ console.log('上传失败', e.detail);
233
+ });
440
234
  ```
441
235
 
442
- #### 相对路径匹配
443
- ```javascript
444
- // 匹配以指定路径开头的请求
445
- '/api/v1/' // 匹配 /api/v1/users, /api/v1/data 等
446
- '/ebank/api/v1/rlog/record' // 精确匹配该路径
447
- ```
236
+ ## 开发
448
237
 
449
- #### 域名匹配
450
- ```javascript
451
- // 匹配指定域名下的所有请求
452
- 'api.example.com' // 匹配该域名下的所有接口
238
+ ```bash
239
+ npm run dev # 开发模式
240
+ npm run build # 构建(ESM + CJS)
453
241
  ```
454
242
 
455
- ## 相关文档和示例
456
-
457
- ### 1. 路由监控功能
458
- - [详细使用指南](docs/ROUTER_MONITOR_GUIDE.md) - 包含完整的路由监控配置和使用示例
459
- - [在线示例](examples/test-router-monitor.html) - 可直接在浏览器中测试路由监控功能
460
-
461
- ### 2. 上传重试机制
462
- - [重试逻辑指南](docs/RETRY_LOGIC_GUIDE.md) - 上传失败后的重试策略和配置
463
- - [重试测试示例](examples/test-retry-logic.html) - 测试上传重试功能
464
-
465
- ### 3. 消费模式
466
- - [消费模式指南](docs/CONSUME_ONLY_MODE_GUIDE.md) - 仅消费数据的轻量级使用模式
467
- - [消费模式示例](examples/consume-only-mode.html) - 消费模式的实际应用示例
468
-
469
- ### 4. 取消方法
470
- - [取消方法指南](docs/CANCEL_METHOD_GUIDE.md) - 如何正确停止录制和数据收集
471
- - [取消方法示例](examples/test-cancel.html) - 演示如何正确停止录制和数据收集
472
-
473
- ## 改进建议实施状态
474
- | 改进项 | 实施状态 | 完成度 |
475
- |-------|----------|--------|
476
- | IndexedDB降级修复 | 已完成 | 100% |
477
- | 动态采样率调整 | 已完成 | 100% |
478
- | 路由监控功能 | 已完成 | 100% |
479
- | 错误处理优化 | 设计中 | 50% |
480
- | 上传重试机制 | 已完成 | 100% |
481
- | 消费模式支持 | 已完成 | 100% |
482
- | 取消方法支持 | 已完成 | 100% |
483
- | 移动端触控增强 | 未开始 | 0% |
484
- | 数据加密模块 | 设计完成 | 50% |
485
- | 数据压缩模块 | 未开始 | 0% |
243
+ ## License
244
+
245
+ MIT