@antglobal/rlog-sdk 0.0.1755855517-dev.11 → 0.0.1755855517-dev.13

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 (50) hide show
  1. package/dist/esm/lib/api.d.ts +10 -0
  2. package/dist/esm/lib/api.d.ts.map +1 -1
  3. package/dist/esm/lib/api.js +47 -31
  4. package/dist/esm/lib/config.d.ts +1 -0
  5. package/dist/esm/lib/config.d.ts.map +1 -1
  6. package/dist/esm/lib/config.js +2 -0
  7. package/dist/esm/lib/error.d.ts.map +1 -1
  8. package/dist/esm/lib/error.js +65 -138
  9. package/dist/esm/lib/init.d.ts.map +1 -1
  10. package/dist/esm/lib/init.js +14 -7
  11. package/dist/esm/lib/net.d.ts +1 -0
  12. package/dist/esm/lib/net.d.ts.map +1 -1
  13. package/dist/esm/lib/net.js +33 -2
  14. package/dist/esm/lib/router-monitor.d.ts.map +1 -1
  15. package/dist/esm/lib/router-monitor.js +100 -0
  16. package/dist/esm/lib/upload-worker-manager.d.ts +37 -0
  17. package/dist/esm/lib/upload-worker-manager.d.ts.map +1 -0
  18. package/dist/esm/lib/upload-worker-manager.js +482 -0
  19. package/dist/esm/lib/upload-worker.d.ts +59 -0
  20. package/dist/esm/lib/upload-worker.d.ts.map +1 -0
  21. package/dist/esm/lib/upload-worker.js +26 -0
  22. package/dist/esm/lib/uploader.d.ts +5 -0
  23. package/dist/esm/lib/uploader.d.ts.map +1 -1
  24. package/dist/esm/lib/uploader.js +58 -10
  25. package/dist/lib/lib/api.d.ts +10 -0
  26. package/dist/lib/lib/api.d.ts.map +1 -1
  27. package/dist/lib/lib/api.js +48 -31
  28. package/dist/lib/lib/config.d.ts +1 -0
  29. package/dist/lib/lib/config.d.ts.map +1 -1
  30. package/dist/lib/lib/config.js +2 -0
  31. package/dist/lib/lib/error.d.ts.map +1 -1
  32. package/dist/lib/lib/error.js +65 -138
  33. package/dist/lib/lib/init.d.ts.map +1 -1
  34. package/dist/lib/lib/init.js +13 -6
  35. package/dist/lib/lib/net.d.ts +1 -0
  36. package/dist/lib/lib/net.d.ts.map +1 -1
  37. package/dist/lib/lib/net.js +33 -1
  38. package/dist/lib/lib/router-monitor.d.ts.map +1 -1
  39. package/dist/lib/lib/router-monitor.js +100 -0
  40. package/dist/lib/lib/upload-worker-manager.d.ts +37 -0
  41. package/dist/lib/lib/upload-worker-manager.d.ts.map +1 -0
  42. package/dist/lib/lib/upload-worker-manager.js +491 -0
  43. package/dist/lib/lib/upload-worker.d.ts +59 -0
  44. package/dist/lib/lib/upload-worker.d.ts.map +1 -0
  45. package/dist/lib/lib/upload-worker.js +32 -0
  46. package/dist/lib/lib/uploader.d.ts +5 -0
  47. package/dist/lib/lib/uploader.d.ts.map +1 -1
  48. package/dist/lib/lib/uploader.js +58 -10
  49. package/dist/rlog-sdk.min.js +1 -1
  50. package/package.json +3 -2
@@ -0,0 +1,491 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.destroyWorker = destroyWorker;
7
+ exports.initWorkerUpload = initWorkerUpload;
8
+ exports.isUsingWorkerMode = isUsingWorkerMode;
9
+ exports.setWorkerErrorModeUploading = setWorkerErrorModeUploading;
10
+ exports.setWorkerErrorModeWindowStart = setWorkerErrorModeWindowStart;
11
+ exports.updateWorkerConfig = updateWorkerConfig;
12
+ var _uploadWorker = require("./upload-worker");
13
+ var _storageManager = require("./storage-manager");
14
+ var _utils = require("./utils");
15
+ var _config = require("./config");
16
+ var _api = require("./api");
17
+ var _net = require("./net");
18
+ var _rrweb = require("rrweb");
19
+ var _init = require("./init");
20
+ var _logger = _interopRequireDefault(require("./logger"));
21
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
22
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
23
+ function _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ _regeneratorRuntime = function _regeneratorRuntime() { return e; }; var t, e = {}, r = Object.prototype, n = r.hasOwnProperty, o = Object.defineProperty || function (t, e, r) { t[e] = r.value; }, i = "function" == typeof Symbol ? Symbol : {}, a = i.iterator || "@@iterator", c = i.asyncIterator || "@@asyncIterator", u = i.toStringTag || "@@toStringTag"; function define(t, e, r) { return Object.defineProperty(t, e, { value: r, enumerable: !0, configurable: !0, writable: !0 }), t[e]; } try { define({}, ""); } catch (t) { define = function define(t, e, r) { return t[e] = r; }; } function wrap(t, e, r, n) { var i = e && e.prototype instanceof Generator ? e : Generator, a = Object.create(i.prototype), c = new Context(n || []); return o(a, "_invoke", { value: makeInvokeMethod(t, r, c) }), a; } function tryCatch(t, e, r) { try { return { type: "normal", arg: t.call(e, r) }; } catch (t) { return { type: "throw", arg: t }; } } e.wrap = wrap; var h = "suspendedStart", l = "suspendedYield", f = "executing", s = "completed", y = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var p = {}; define(p, a, function () { return this; }); var d = Object.getPrototypeOf, v = d && d(d(values([]))); v && v !== r && n.call(v, a) && (p = v); var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p); function defineIteratorMethods(t) { ["next", "throw", "return"].forEach(function (e) { define(t, e, function (t) { return this._invoke(e, t); }); }); } function AsyncIterator(t, e) { function invoke(r, o, i, a) { var c = tryCatch(t[r], t, o); if ("throw" !== c.type) { var u = c.arg, h = u.value; return h && "object" == _typeof(h) && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) { invoke("next", t, i, a); }, function (t) { invoke("throw", t, i, a); }) : e.resolve(h).then(function (t) { u.value = t, i(u); }, function (t) { return invoke("throw", t, i, a); }); } a(c.arg); } var r; o(this, "_invoke", { value: function value(t, n) { function callInvokeWithMethodAndArg() { return new e(function (e, r) { invoke(t, n, e, r); }); } return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(e, r, n) { var o = h; return function (i, a) { if (o === f) throw new Error("Generator is already running"); if (o === s) { if ("throw" === i) throw a; return { value: t, done: !0 }; } for (n.method = i, n.arg = a;;) { var c = n.delegate; if (c) { var u = maybeInvokeDelegate(c, n); if (u) { if (u === y) continue; return u; } } if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) { if (o === h) throw o = s, n.arg; n.dispatchException(n.arg); } else "return" === n.method && n.abrupt("return", n.arg); o = f; var p = tryCatch(e, r, n); if ("normal" === p.type) { if (o = n.done ? s : l, p.arg === y) continue; return { value: p.arg, done: n.done }; } "throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg); } }; } function maybeInvokeDelegate(e, r) { var n = r.method, o = e.iterator[n]; if (o === t) return r.delegate = null, "throw" === n && e.iterator.return && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y; var i = tryCatch(o, e.iterator, r.arg); if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y; var a = i.arg; return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y); } function pushTryEntry(t) { var e = { tryLoc: t[0] }; 1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e); } function resetTryEntry(t) { var e = t.completion || {}; e.type = "normal", delete e.arg, t.completion = e; } function Context(t) { this.tryEntries = [{ tryLoc: "root" }], t.forEach(pushTryEntry, this), this.reset(!0); } function values(e) { if (e || "" === e) { var r = e[a]; if (r) return r.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) { var o = -1, i = function next() { for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next; return next.value = t, next.done = !0, next; }; return i.next = i; } } throw new TypeError(_typeof(e) + " is not iterable"); } return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), o(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) { var e = "function" == typeof t && t.constructor; return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name)); }, e.mark = function (t) { return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t; }, e.awrap = function (t) { return { __await: t }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () { return this; }), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) { void 0 === i && (i = Promise); var a = new AsyncIterator(wrap(t, r, n, o), i); return e.isGeneratorFunction(r) ? a : a.next().then(function (t) { return t.done ? t.value : a.next(); }); }, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () { return this; }), define(g, "toString", function () { return "[object Generator]"; }), e.keys = function (t) { var e = Object(t), r = []; for (var n in e) r.push(n); return r.reverse(), function next() { for (; r.length;) { var t = r.pop(); if (t in e) return next.value = t, next.done = !1, next; } return next.done = !0, next; }; }, e.values = values, Context.prototype = { constructor: Context, reset: function reset(e) { if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t); }, stop: function stop() { this.done = !0; var t = this.tryEntries[0].completion; if ("throw" === t.type) throw t.arg; return this.rval; }, dispatchException: function dispatchException(e) { if (this.done) throw e; var r = this; function handle(n, o) { return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o; } for (var o = this.tryEntries.length - 1; o >= 0; --o) { var i = this.tryEntries[o], a = i.completion; if ("root" === i.tryLoc) return handle("end"); if (i.tryLoc <= this.prev) { var c = n.call(i, "catchLoc"), u = n.call(i, "finallyLoc"); if (c && u) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } else if (c) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); } else { if (!u) throw new Error("try statement without catch or finally"); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } } } }, abrupt: function abrupt(t, e) { for (var r = this.tryEntries.length - 1; r >= 0; --r) { var o = this.tryEntries[r]; if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) { var i = o; break; } } i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null); var a = i ? i.completion : {}; return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a); }, complete: function complete(t, e) { if ("throw" === t.type) throw t.arg; return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y; }, finish: function finish(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y; } }, catch: function _catch(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.tryLoc === t) { var n = r.completion; if ("throw" === n.type) { var o = n.arg; resetTryEntry(r); } return o; } } throw new Error("illegal catch attempt"); }, delegateYield: function delegateYield(e, r, n) { return this.delegate = { iterator: values(e), resultName: r, nextLoc: n }, "next" === this.method && (this.arg = t), y; } }, e; }
24
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
25
+ function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } /**
26
+ * Upload Worker 管理器
27
+ *
28
+ * 职责:
29
+ * - Worker 生命周期管理(创建、销毁、降级)
30
+ * - 将 Worker 脚本以 inline Blob 方式加载
31
+ * - 封装 postMessage/onmessage 通信
32
+ * - 处理 Worker 回传的消息,调用对应的主线程逻辑
33
+ * - 提供与现有 uploader.ts 相同的对外 API
34
+ */
35
+ // Worker 实例
36
+ var worker = null;
37
+
38
+ // Worker 是否就绪
39
+ var workerReady = false;
40
+
41
+ // 是否正在使用 Worker 模式
42
+ var isWorkerMode = false;
43
+
44
+ // 当前配置缓存
45
+ var currentServ = '';
46
+ var currentAppId = '';
47
+
48
+ // 错误模式状态
49
+ var errorModeUploading = false;
50
+ var errorModeWindowStart = 0;
51
+
52
+ // 上传锁(Worker 模式下用于防止并发数据读取)
53
+ var isFetchingBatch = false;
54
+
55
+ // batchId 计数器
56
+ var batchIdCounter = 0;
57
+
58
+ /**
59
+ * 生成唯一的 batchId
60
+ */
61
+ function generateBatchId() {
62
+ return "batch_".concat(Date.now(), "_").concat(++batchIdCounter);
63
+ }
64
+
65
+ /**
66
+ * 创建内联 Worker
67
+ * 使用 Blob URL 方式,避免额外的文件加载问题
68
+ */
69
+ function createInlineWorker() {
70
+ try {
71
+ // 检查 Worker 是否可用
72
+ if (typeof Worker === 'undefined') {
73
+ return null;
74
+ }
75
+ var workerCode = (0, _uploadWorker.getUploadWorkerCode)();
76
+ var blob = new Blob([workerCode], {
77
+ type: 'application/javascript'
78
+ });
79
+ var url = URL.createObjectURL(blob);
80
+ var w = new Worker(url);
81
+ // 创建后立即释放 Blob URL,Worker 已经加载了代码
82
+ URL.revokeObjectURL(url);
83
+ return w;
84
+ } catch (e) {
85
+ _logger.default.warn('Failed to create inline Worker, will fallback to main thread:', e);
86
+ return null;
87
+ }
88
+ }
89
+
90
+ /**
91
+ * 处理 Worker 发来的消息
92
+ */
93
+ function handleWorkerMessage(e) {
94
+ var msg = e.data;
95
+ if (!msg || !msg.type) return;
96
+ switch (msg.type) {
97
+ case 'READY':
98
+ workerReady = true;
99
+ _logger.default.log('Upload Worker is ready');
100
+ break;
101
+ case 'REQUEST_BATCH':
102
+ handleRequestBatch(msg.mode);
103
+ break;
104
+ case 'UPLOAD_SUCCESS':
105
+ handleUploadSuccess(msg.batchId);
106
+ break;
107
+ case 'UPLOAD_FAILURE':
108
+ handleUploadFailure(msg.batchId, msg.error, msg.failureCount);
109
+ break;
110
+ case 'MAX_RETRY_REACHED':
111
+ handleMaxRetryReached(msg.batchId, msg.error);
112
+ break;
113
+ }
114
+ }
115
+
116
+ /**
117
+ * 处理 Worker 请求数据批次
118
+ * Worker 内部定时器触发,主线程从 storage 读取数据后发给 Worker
119
+ */
120
+ function handleRequestBatch(_x) {
121
+ return _handleRequestBatch.apply(this, arguments);
122
+ } // 待处理的批次元数据
123
+ function _handleRequestBatch() {
124
+ _handleRequestBatch = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(mode) {
125
+ var currentConfig, isErrorMode, events, windowStart, config, consumeOnly, queryParams, customHeaders, batchId;
126
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
127
+ while (1) switch (_context.prev = _context.next) {
128
+ case 0:
129
+ if (!isFetchingBatch) {
130
+ _context.next = 2;
131
+ break;
132
+ }
133
+ return _context.abrupt("return");
134
+ case 2:
135
+ // 检查采集总开关
136
+ currentConfig = (0, _config.getConfig)();
137
+ if (currentConfig.enable) {
138
+ _context.next = 6;
139
+ break;
140
+ }
141
+ _logger.default.log('SDK is disabled by config, skipping batch request');
142
+ return _context.abrupt("return");
143
+ case 6:
144
+ isErrorMode = currentConfig.captureMode === 'error'; // 错误模式下,如果未处于 uploading 状态,跳过
145
+ if (!(isErrorMode && !errorModeUploading)) {
146
+ _context.next = 9;
147
+ break;
148
+ }
149
+ return _context.abrupt("return");
150
+ case 9:
151
+ _context.prev = 9;
152
+ isFetchingBatch = true;
153
+ windowStart = 0;
154
+ if (!isErrorMode) {
155
+ _context.next = 20;
156
+ break;
157
+ }
158
+ // 错误模式:按时间范围提取事件
159
+ windowStart = errorModeWindowStart > 0 ? errorModeWindowStart : Date.now();
160
+ _context.next = 16;
161
+ return _storageManager.storage.pullByTimeRange((0, _utils.getDeviceId)(), windowStart, Date.now());
162
+ case 16:
163
+ events = _context.sent;
164
+ errorModeWindowStart = 0;
165
+ _context.next = 23;
166
+ break;
167
+ case 20:
168
+ _context.next = 22;
169
+ return _storageManager.storage.pull((0, _utils.getDeviceId)(), 100);
170
+ case 22:
171
+ events = _context.sent;
172
+ case 23:
173
+ if (!(!events || events.length === 0)) {
174
+ _context.next = 26;
175
+ break;
176
+ }
177
+ isFetchingBatch = false;
178
+ return _context.abrupt("return");
179
+ case 26:
180
+ // 检查是否只消费不上报
181
+ config = (0, _config.getConfig)();
182
+ consumeOnly = sessionStorage.getItem('RLOG_CONSUME_ONLY') === 'YES' || config.consumeOnly;
183
+ if (!consumeOnly) {
184
+ _context.next = 32;
185
+ break;
186
+ }
187
+ _logger.default.log('Consume only mode, skip upload');
188
+ isFetchingBatch = false;
189
+ return _context.abrupt("return");
190
+ case 32:
191
+ // 构建查询参数
192
+ queryParams = (0, _api.buildQueryParams)({
193
+ appId: currentAppId,
194
+ deviceId: (0, _utils.getDeviceId)(),
195
+ data: events
196
+ }); // 获取自定义请求头
197
+ customHeaders = (0, _net.getCustomHeaders)(); // 生成 batchId 并记录元数据(用于成功/失败回调)
198
+ batchId = generateBatchId(); // 将批次元数据存储起来,供回调使用
199
+ pendingBatches.set(batchId, {
200
+ events: events,
201
+ isErrorMode: isErrorMode,
202
+ windowStart: windowStart
203
+ });
204
+
205
+ // 发送数据给 Worker 执行上传
206
+ sendToWorker({
207
+ type: 'UPLOAD_BATCH',
208
+ batchId: batchId,
209
+ events: events,
210
+ queryParams: queryParams,
211
+ customHeaders: customHeaders
212
+ });
213
+ isFetchingBatch = false;
214
+ _context.next = 44;
215
+ break;
216
+ case 40:
217
+ _context.prev = 40;
218
+ _context.t0 = _context["catch"](9);
219
+ isFetchingBatch = false;
220
+ _logger.default.error('Error fetching batch for Worker:', _context.t0);
221
+ case 44:
222
+ case "end":
223
+ return _context.stop();
224
+ }
225
+ }, _callee, null, [[9, 40]]);
226
+ }));
227
+ return _handleRequestBatch.apply(this, arguments);
228
+ }
229
+ var pendingBatches = new Map();
230
+
231
+ /**
232
+ * 处理上传成功
233
+ */
234
+ function handleUploadSuccess(_x2) {
235
+ return _handleUploadSuccess.apply(this, arguments);
236
+ }
237
+ /**
238
+ * 处理上传失败(未达到最大重试次数)
239
+ */
240
+ function _handleUploadSuccess() {
241
+ _handleUploadSuccess = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(batchId) {
242
+ var batch, lastEvent;
243
+ return _regeneratorRuntime().wrap(function _callee2$(_context2) {
244
+ while (1) switch (_context2.prev = _context2.next) {
245
+ case 0:
246
+ batch = pendingBatches.get(batchId);
247
+ if (batch) {
248
+ _context2.next = 3;
249
+ break;
250
+ }
251
+ return _context2.abrupt("return");
252
+ case 3:
253
+ pendingBatches.delete(batchId);
254
+
255
+ // 错误模式:上传成功后移除已上传的事件
256
+ if (!(batch.isErrorMode && batch.windowStart > 0 && batch.events.length > 0)) {
257
+ _context2.next = 9;
258
+ break;
259
+ }
260
+ _context2.next = 7;
261
+ return _storageManager.storage.removeByTimeRange((0, _utils.getDeviceId)(), batch.windowStart);
262
+ case 7:
263
+ // 更新窗口起点为最后一个事件的时间戳
264
+ lastEvent = batch.events[batch.events.length - 1];
265
+ if (lastEvent && lastEvent.timestamp) {
266
+ errorModeWindowStart = lastEvent.timestamp;
267
+ }
268
+ case 9:
269
+ case "end":
270
+ return _context2.stop();
271
+ }
272
+ }, _callee2);
273
+ }));
274
+ return _handleUploadSuccess.apply(this, arguments);
275
+ }
276
+ function handleUploadFailure(_x3, _x4, _x5) {
277
+ return _handleUploadFailure.apply(this, arguments);
278
+ }
279
+ /**
280
+ * 处理达到最大重试次数
281
+ */
282
+ function _handleUploadFailure() {
283
+ _handleUploadFailure = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(batchId, error, failureCount) {
284
+ var batch;
285
+ return _regeneratorRuntime().wrap(function _callee3$(_context3) {
286
+ while (1) switch (_context3.prev = _context3.next) {
287
+ case 0:
288
+ batch = pendingBatches.get(batchId);
289
+ if (batch) {
290
+ _context3.next = 3;
291
+ break;
292
+ }
293
+ return _context3.abrupt("return");
294
+ case 3:
295
+ pendingBatches.delete(batchId);
296
+ _logger.default.warn("Upload failed ".concat(failureCount, " time(s), will retry in next cycle:"), error);
297
+
298
+ // 将事件放回存储头部,保持时间戳顺序
299
+ _context3.next = 7;
300
+ return _storageManager.storage.unshiftBatch((0, _utils.getDeviceId)(), batch.events);
301
+ case 7:
302
+ case "end":
303
+ return _context3.stop();
304
+ }
305
+ }, _callee3);
306
+ }));
307
+ return _handleUploadFailure.apply(this, arguments);
308
+ }
309
+ function handleMaxRetryReached(_x6, _x7) {
310
+ return _handleMaxRetryReached.apply(this, arguments);
311
+ }
312
+ /**
313
+ * 向 Worker 发送消息
314
+ */
315
+ function _handleMaxRetryReached() {
316
+ _handleMaxRetryReached = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(batchId, error) {
317
+ var batch, config, maxRetryCount, customEvent;
318
+ return _regeneratorRuntime().wrap(function _callee4$(_context4) {
319
+ while (1) switch (_context4.prev = _context4.next) {
320
+ case 0:
321
+ batch = pendingBatches.get(batchId);
322
+ if (batch) {
323
+ _context4.next = 3;
324
+ break;
325
+ }
326
+ return _context4.abrupt("return");
327
+ case 3:
328
+ pendingBatches.delete(batchId);
329
+ config = (0, _config.getConfig)();
330
+ maxRetryCount = config.maxRetryCount || 3;
331
+ _logger.default.warn("Upload failed ".concat(maxRetryCount, " times consecutively, stopping upload"));
332
+
333
+ // 将事件放回存储
334
+ _context4.next = 9;
335
+ return _storageManager.storage.unshiftBatch((0, _utils.getDeviceId)(), batch.events);
336
+ case 9:
337
+ // 创建并派发自定义事件
338
+ customEvent = new CustomEvent('rlog-upload-failure', {
339
+ detail: {
340
+ error: error,
341
+ retryCount: maxRetryCount,
342
+ appId: currentAppId,
343
+ deviceId: (0, _utils.getDeviceId)()
344
+ }
345
+ });
346
+ if (typeof window !== 'undefined') {
347
+ window.dispatchEvent(customEvent);
348
+ }
349
+
350
+ // 使用 addCustomEvent 记录上传失败事件
351
+ try {
352
+ _rrweb.record.addCustomEvent('rlog-upload-failure', {
353
+ error: error,
354
+ retryCount: maxRetryCount,
355
+ appId: currentAppId,
356
+ deviceId: (0, _utils.getDeviceId)(),
357
+ timestamp: Date.now()
358
+ });
359
+ } catch (e) {
360
+ _logger.default.warn('Failed to record upload failure event via addCustomEvent:', e);
361
+ }
362
+
363
+ // 停止 Worker
364
+ destroyWorker();
365
+
366
+ // 停止 rrweb 录制
367
+ setTimeout(function () {
368
+ (0, _init.cancelRlog)();
369
+ }, 0);
370
+ _logger.default.error('Upload and recording stopped due to repeated failures');
371
+ case 15:
372
+ case "end":
373
+ return _context4.stop();
374
+ }
375
+ }, _callee4);
376
+ }));
377
+ return _handleMaxRetryReached.apply(this, arguments);
378
+ }
379
+ function sendToWorker(command) {
380
+ if (worker && workerReady) {
381
+ worker.postMessage(command);
382
+ }
383
+ }
384
+
385
+ /**
386
+ * 处理 Worker 错误
387
+ */
388
+ function handleWorkerError(e) {
389
+ _logger.default.error('Upload Worker error:', e.message);
390
+ // Worker 出错时销毁,后续由 uploader.ts 降级到主线程
391
+ destroyWorker();
392
+ }
393
+
394
+ // ==================== 对外 API ====================
395
+
396
+ /**
397
+ * 尝试初始化 Worker 模式
398
+ * @returns 是否成功启用 Worker 模式
399
+ */
400
+ function initWorkerUpload(serv, appId) {
401
+ currentServ = serv;
402
+ currentAppId = appId;
403
+
404
+ // 尝试创建 Worker
405
+ var w = createInlineWorker();
406
+ if (!w) {
407
+ isWorkerMode = false;
408
+ return false;
409
+ }
410
+ worker = w;
411
+ worker.onmessage = handleWorkerMessage;
412
+ worker.onerror = handleWorkerError;
413
+
414
+ // 发送启动指令
415
+ var config = (0, _config.getConfig)();
416
+ var startConfig = {
417
+ serv: serv,
418
+ appId: appId,
419
+ deviceId: (0, _utils.getDeviceId)(),
420
+ uploadInterval: config.uploadInterval,
421
+ maxRetryCount: config.maxRetryCount || 3
422
+ };
423
+ worker.postMessage({
424
+ type: 'START',
425
+ config: startConfig
426
+ });
427
+ isWorkerMode = true;
428
+ _logger.default.log('Upload Worker mode initialized');
429
+ return true;
430
+ }
431
+
432
+ /**
433
+ * 销毁 Worker
434
+ */
435
+ function destroyWorker() {
436
+ if (worker) {
437
+ try {
438
+ worker.postMessage({
439
+ type: 'STOP'
440
+ });
441
+ worker.terminate();
442
+ } catch (e) {
443
+ // 忽略终止错误
444
+ }
445
+ worker = null;
446
+ }
447
+ workerReady = false;
448
+ isWorkerMode = false;
449
+ isFetchingBatch = false;
450
+ errorModeUploading = false;
451
+ errorModeWindowStart = 0;
452
+ batchIdCounter = 0;
453
+ pendingBatches.clear();
454
+ }
455
+
456
+ /**
457
+ * 是否正在使用 Worker 模式
458
+ */
459
+ function isUsingWorkerMode() {
460
+ return isWorkerMode && worker !== null;
461
+ }
462
+
463
+ /**
464
+ * 设置错误模式上传状态(Worker 模式)
465
+ */
466
+ function setWorkerErrorModeUploading(uploading) {
467
+ errorModeUploading = uploading;
468
+
469
+ // 同步通知 Worker
470
+ sendToWorker({
471
+ type: 'SET_ERROR_MODE_UPLOADING',
472
+ uploading: uploading
473
+ });
474
+ }
475
+
476
+ /**
477
+ * 设置错误模式上传时间窗口起点(Worker 模式)
478
+ */
479
+ function setWorkerErrorModeWindowStart(startTime) {
480
+ errorModeWindowStart = startTime;
481
+ }
482
+
483
+ /**
484
+ * 更新 Worker 配置
485
+ */
486
+ function updateWorkerConfig(config) {
487
+ sendToWorker({
488
+ type: 'UPDATE_CONFIG',
489
+ config: config
490
+ });
491
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Upload Worker 脚本
3
+ *
4
+ * 在 Web Worker 中执行上传任务,将 JSON 序列化 + FormData 构建 + XHR 上传
5
+ * 从主线程移到 Worker 线程,避免阻塞 UI。
6
+ *
7
+ * 通信协议:
8
+ * 主线程 → Worker: WorkerCommand
9
+ * Worker → 主线程: WorkerMessage
10
+ */
11
+ export interface WorkerConfig {
12
+ serv: string;
13
+ appId: string;
14
+ deviceId: string;
15
+ uploadInterval: number;
16
+ maxRetryCount: number;
17
+ }
18
+ export type WorkerCommand = {
19
+ type: 'START';
20
+ config: WorkerConfig;
21
+ } | {
22
+ type: 'STOP';
23
+ } | {
24
+ type: 'UPLOAD_BATCH';
25
+ batchId: string;
26
+ events: any[];
27
+ queryParams: Record<string, string>;
28
+ customHeaders: Record<string, string>;
29
+ } | {
30
+ type: 'UPDATE_CONFIG';
31
+ config: Partial<WorkerConfig>;
32
+ } | {
33
+ type: 'SET_ERROR_MODE_UPLOADING';
34
+ uploading: boolean;
35
+ };
36
+ export type WorkerMessage = {
37
+ type: 'READY';
38
+ } | {
39
+ type: 'REQUEST_BATCH';
40
+ mode: 'full' | 'error';
41
+ } | {
42
+ type: 'UPLOAD_SUCCESS';
43
+ batchId: string;
44
+ } | {
45
+ type: 'UPLOAD_FAILURE';
46
+ batchId: string;
47
+ error: string;
48
+ failureCount: number;
49
+ } | {
50
+ type: 'MAX_RETRY_REACHED';
51
+ batchId: string;
52
+ error: string;
53
+ };
54
+ /**
55
+ * 返回 Worker 脚本的源代码字符串
56
+ * 用于通过 Blob URL 内联创建 Worker
57
+ */
58
+ export declare function getUploadWorkerCode(): string;
59
+ //# sourceMappingURL=upload-worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-worker.d.ts","sourceRoot":"","sources":["../../../src/lib/upload-worker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;CACvB;AAGD,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,GAAG,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACpI;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,0BAA0B,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC;AAG7D,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAChF;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAIlE;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAsN5C"}
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getUploadWorkerCode = getUploadWorkerCode;
7
+ /**
8
+ * Upload Worker 脚本
9
+ *
10
+ * 在 Web Worker 中执行上传任务,将 JSON 序列化 + FormData 构建 + XHR 上传
11
+ * 从主线程移到 Worker 线程,避免阻塞 UI。
12
+ *
13
+ * 通信协议:
14
+ * 主线程 → Worker: WorkerCommand
15
+ * Worker → 主线程: WorkerMessage
16
+ */
17
+
18
+ // ==================== 类型定义 ====================
19
+
20
+ // 主线程 → Worker
21
+
22
+ // Worker → 主线程
23
+
24
+ // ==================== Worker 代码(字符串形式) ====================
25
+
26
+ /**
27
+ * 返回 Worker 脚本的源代码字符串
28
+ * 用于通过 Blob URL 内联创建 Worker
29
+ */
30
+ function getUploadWorkerCode() {
31
+ return "\n'use strict';\n\n// ===== Worker \u5185\u90E8\u72B6\u6001 =====\nvar config = null;\nvar pollTimer = null;\nvar isRunning = false;\nvar errorModeUploading = false;\nvar failureCountMap = {};\n\n// ===== UUID \u751F\u6210 =====\nfunction generateUUID() {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {\n var r = (Math.random() * 16) | 0;\n var v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n}\n\n// ===== \u6784\u5EFA\u4E0A\u4F20 URL =====\nfunction buildUploadUrl(serv, queryParams) {\n var params = [];\n for (var key in queryParams) {\n if (queryParams.hasOwnProperty(key) && queryParams[key] != null && queryParams[key] !== '') {\n params.push(encodeURIComponent(key) + '=' + encodeURIComponent(queryParams[key]));\n }\n }\n var queryString = params.join('&');\n return serv + (queryString ? '?' + queryString : '');\n}\n\n// ===== \u6267\u884C\u4E0A\u4F20 =====\nfunction performUpload(msg) {\n var batchId = msg.batchId;\n var events = msg.events;\n var queryParams = msg.queryParams;\n var customHeaders = msg.customHeaders;\n\n try {\n // JSON \u5E8F\u5217\u5316\u5728 Worker \u4E2D\u6267\u884C\uFF0C\u4E0D\u963B\u585E\u4E3B\u7EBF\u7A0B\n var jsonStr = JSON.stringify(events);\n var blob = new Blob([jsonStr], { type: 'application/json' });\n var formData = new FormData();\n formData.append('file', blob, generateUUID() + '.json');\n\n var url = buildUploadUrl(config ? config.serv : '', queryParams);\n\n var xhr = new XMLHttpRequest();\n xhr.open('POST', url, true);\n xhr.timeout = 10000;\n\n // \u8BBE\u7F6E\u81EA\u5B9A\u4E49\u8BF7\u6C42\u5934\n if (customHeaders) {\n for (var key in customHeaders) {\n if (customHeaders.hasOwnProperty(key)) {\n xhr.setRequestHeader(key, customHeaders[key]);\n }\n }\n }\n\n xhr.onreadystatechange = function() {\n if (xhr.readyState === 4) {\n if (xhr.status >= 200 && xhr.status < 300) {\n // \u68C0\u67E5\u4E1A\u52A1\u5C42 success \u5B57\u6BB5\n var uploadSuccess = true;\n var errorMessage = '';\n try {\n var responseData = JSON.parse(xhr.responseText);\n if (responseData && typeof responseData === 'object' && responseData.success === false) {\n uploadSuccess = false;\n errorMessage = responseData.errorMessage || 'Upload failed with success=false';\n }\n } catch(e) {\n // \u65E0\u6CD5\u89E3\u6790 JSON\uFF0C\u89C6\u4E3A\u6210\u529F\n }\n\n if (uploadSuccess) {\n // \u4E0A\u4F20\u6210\u529F\uFF0C\u91CD\u7F6E\u5931\u8D25\u8BA1\u6570\n var batchKey = config ? (config.appId + '_' + config.deviceId) : batchId;\n delete failureCountMap[batchKey];\n self.postMessage({ type: 'UPLOAD_SUCCESS', batchId: batchId });\n } else {\n handleFailure(batchId, errorMessage);\n }\n } else {\n handleFailure(batchId, 'HTTP ' + xhr.status + ': ' + xhr.statusText);\n }\n }\n };\n\n xhr.onerror = function() {\n handleFailure(batchId, 'Network error');\n };\n\n xhr.ontimeout = function() {\n handleFailure(batchId, 'Request timeout');\n };\n\n xhr.send(formData);\n } catch (e) {\n handleFailure(batchId, 'Upload exception: ' + (e.message || String(e)));\n }\n}\n\n// ===== \u5904\u7406\u4E0A\u4F20\u5931\u8D25 =====\nfunction handleFailure(batchId, errorMessage) {\n var batchKey = config ? (config.appId + '_' + config.deviceId) : batchId;\n var currentCount = failureCountMap[batchKey] || 0;\n var newCount = currentCount + 1;\n failureCountMap[batchKey] = newCount;\n\n var maxRetry = (config && config.maxRetryCount) ? config.maxRetryCount : 3;\n\n if (newCount >= maxRetry) {\n // \u8FBE\u5230\u6700\u5927\u91CD\u8BD5\u6B21\u6570\n delete failureCountMap[batchKey];\n self.postMessage({\n type: 'MAX_RETRY_REACHED',\n batchId: batchId,\n error: errorMessage\n });\n } else {\n self.postMessage({\n type: 'UPLOAD_FAILURE',\n batchId: batchId,\n error: errorMessage,\n failureCount: newCount\n });\n }\n}\n\n// ===== \u8F6E\u8BE2\u8C03\u5EA6 =====\nfunction startPolling() {\n if (pollTimer) {\n clearInterval(pollTimer);\n }\n\n var interval = (config && config.uploadInterval) ? config.uploadInterval : 2000;\n\n pollTimer = setInterval(function() {\n if (!isRunning) return;\n\n // \u5411\u4E3B\u7EBF\u7A0B\u8BF7\u6C42\u6570\u636E\u6279\u6B21\n // \u4E3B\u7EBF\u7A0B\u4F1A\u6839\u636E\u5F53\u524D\u6A21\u5F0F\uFF08full/error\uFF09\u548C\u72B6\u6001\u51B3\u5B9A\u662F\u5426\u63D0\u4F9B\u6570\u636E\n self.postMessage({\n type: 'REQUEST_BATCH',\n mode: errorModeUploading ? 'error' : 'full'\n });\n }, interval);\n}\n\nfunction stopPolling() {\n if (pollTimer) {\n clearInterval(pollTimer);\n pollTimer = null;\n }\n}\n\n// ===== \u6E05\u7406 =====\nfunction cleanup() {\n isRunning = false;\n stopPolling();\n failureCountMap = {};\n config = null;\n errorModeUploading = false;\n}\n\n// ===== \u6D88\u606F\u5904\u7406 =====\nself.onmessage = function(e) {\n var msg = e.data;\n if (!msg || !msg.type) return;\n\n switch (msg.type) {\n case 'START':\n config = msg.config;\n isRunning = true;\n failureCountMap = {};\n startPolling();\n break;\n\n case 'STOP':\n cleanup();\n break;\n\n case 'UPLOAD_BATCH':\n if (isRunning) {\n performUpload(msg);\n }\n break;\n\n case 'UPDATE_CONFIG':\n if (msg.config) {\n for (var key in msg.config) {\n if (msg.config.hasOwnProperty(key) && config) {\n config[key] = msg.config[key];\n }\n }\n // \u5982\u679C uploadInterval \u53D8\u4E86\uFF0C\u91CD\u542F\u8F6E\u8BE2\n if (msg.config.uploadInterval && isRunning) {\n startPolling();\n }\n }\n break;\n\n case 'SET_ERROR_MODE_UPLOADING':\n errorModeUploading = msg.uploading;\n break;\n }\n};\n\n// Worker \u5C31\u7EEA\u901A\u77E5\nself.postMessage({ type: 'READY' });\n";
32
+ }
@@ -1,15 +1,19 @@
1
1
  /**
2
2
  * 设置错误模式上传状态
3
3
  * 由 ErrorTrigger 调用:错误触发时设置为 true,cooldown 结束时设置为 false
4
+ * 自动分发到 Worker 模式或主线程模式
4
5
  */
5
6
  export declare function setErrorModeUploading(uploading: boolean): void;
6
7
  /**
7
8
  * 设置错误模式上传时间窗口起点
8
9
  * 由 ErrorTrigger 调用,记录错误触发前的时间窗口起点
10
+ * 自动分发到 Worker 模式或主线程模式
9
11
  */
10
12
  export declare function setErrorModeWindowStart(startTime: number): void;
11
13
  /**
12
14
  * 启动数据上传循环
15
+ * 优先尝试 Worker 模式,失败则降级到主线程模式
16
+ *
13
17
  * 全量模式:持续轮询上传
14
18
  * 错误模式:idle 时跳过上传,uploading 时轮询上传(由 ErrorTrigger 控制状态)
15
19
  * @param serv 服务器地址
@@ -18,6 +22,7 @@ export declare function setErrorModeWindowStart(startTime: number): void;
18
22
  export declare function startUploadLoop(serv: string, appId: string): void;
19
23
  /**
20
24
  * 取消上传循环
25
+ * 同时处理 Worker 模式和主线程模式
21
26
  */
22
27
  export declare function cancelUploadLoop(): void;
23
28
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"uploader.d.ts","sourceRoot":"","sources":["../../../src/lib/uploader.ts"],"names":[],"mappings":"AAuBA;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CAE9D;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE/D;AAyGD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAmIjE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAMtC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C"}
1
+ {"version":3,"file":"uploader.d.ts","sourceRoot":"","sources":["../../../src/lib/uploader.ts"],"names":[],"mappings":"AAgCA;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI,CAM9D;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAM/D;AAqPD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAYjE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAWvC;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAYtC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C"}