mon-reactive-h5 1.0.11 → 1.0.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.
@@ -0,0 +1,1079 @@
1
+ "use strict";
2
+
3
+ function _regenerator() {
4
+ /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */var e,
5
+ t,
6
+ r = "function" == typeof Symbol ? Symbol : {},
7
+ n = r.iterator || "@@iterator",
8
+ o = r.toStringTag || "@@toStringTag";
9
+ function i(r, n, o, i) {
10
+ var c = n && n.prototype instanceof Generator ? n : Generator,
11
+ u = Object.create(c.prototype);
12
+ return _regeneratorDefine2(u, "_invoke", function (r, n, o) {
13
+ var i,
14
+ c,
15
+ u,
16
+ f = 0,
17
+ p = o || [],
18
+ y = !1,
19
+ G = {
20
+ p: 0,
21
+ n: 0,
22
+ v: e,
23
+ a: d,
24
+ f: d.bind(e, 4),
25
+ d: function d(t, r) {
26
+ return i = t, c = 0, u = e, G.n = r, a;
27
+ }
28
+ };
29
+ function d(r, n) {
30
+ for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) {
31
+ var o,
32
+ i = p[t],
33
+ d = G.p,
34
+ l = i[2];
35
+ r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0));
36
+ }
37
+ if (o || r > 1) return a;
38
+ throw y = !0, n;
39
+ }
40
+ return function (o, p, l) {
41
+ if (f > 1) throw TypeError("Generator is already running");
42
+ for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) {
43
+ i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u);
44
+ try {
45
+ if (f = 2, i) {
46
+ if (c || (o = "next"), t = i[o]) {
47
+ if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object");
48
+ if (!t.done) return t;
49
+ u = t.value, c < 2 && (c = 0);
50
+ } else 1 === c && (t = i.return) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1);
51
+ i = e;
52
+ } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break;
53
+ } catch (t) {
54
+ i = e, c = 1, u = t;
55
+ } finally {
56
+ f = 1;
57
+ }
58
+ }
59
+ return {
60
+ value: t,
61
+ done: y
62
+ };
63
+ };
64
+ }(r, o, i), !0), u;
65
+ }
66
+ var a = {};
67
+ function Generator() {}
68
+ function GeneratorFunction() {}
69
+ function GeneratorFunctionPrototype() {}
70
+ t = Object.getPrototypeOf;
71
+ var c = [][n] ? t(t([][n]())) : (_regeneratorDefine2(t = {}, n, function () {
72
+ return this;
73
+ }), t),
74
+ u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c);
75
+ function f(e) {
76
+ return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine2(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e;
77
+ }
78
+ return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine2(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine2(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine2(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine2(u), _regeneratorDefine2(u, o, "Generator"), _regeneratorDefine2(u, n, function () {
79
+ return this;
80
+ }), _regeneratorDefine2(u, "toString", function () {
81
+ return "[object Generator]";
82
+ }), (_regenerator = function _regenerator() {
83
+ return {
84
+ w: i,
85
+ m: f
86
+ };
87
+ })();
88
+ }
89
+ function _regeneratorDefine2(e, r, n, t) {
90
+ var i = Object.defineProperty;
91
+ try {
92
+ i({}, "", {});
93
+ } catch (e) {
94
+ i = 0;
95
+ }
96
+ _regeneratorDefine2 = function _regeneratorDefine(e, r, n, t) {
97
+ function o(r, n) {
98
+ _regeneratorDefine2(e, r, function (e) {
99
+ return this._invoke(r, n, e);
100
+ });
101
+ }
102
+ r ? i ? i(e, r, {
103
+ value: n,
104
+ enumerable: !t,
105
+ configurable: !t,
106
+ writable: !t
107
+ }) : e[r] = n : (o("next", 0), o("throw", 1), o("return", 2));
108
+ }, _regeneratorDefine2(e, r, n, t);
109
+ }
110
+ function _classCallCheck(a, n) {
111
+ if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
112
+ }
113
+ function _defineProperties(e, r) {
114
+ for (var t = 0; t < r.length; t++) {
115
+ var o = r[t];
116
+ o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o);
117
+ }
118
+ }
119
+ function _createClass(e, r, t) {
120
+ return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", {
121
+ writable: !1
122
+ }), e;
123
+ }
124
+ function _toPropertyKey(t) {
125
+ var i = _toPrimitive(t, "string");
126
+ return "symbol" == _typeof(i) ? i : i + "";
127
+ }
128
+ function _toPrimitive(t, r) {
129
+ if ("object" != _typeof(t) || !t) return t;
130
+ var e = t[Symbol.toPrimitive];
131
+ if (void 0 !== e) {
132
+ var i = e.call(t, r || "default");
133
+ if ("object" != _typeof(i)) return i;
134
+ throw new TypeError("@@toPrimitive must return a primitive value.");
135
+ }
136
+ return ("string" === r ? String : Number)(t);
137
+ }
138
+ function _typeof(o) {
139
+ "@babel/helpers - typeof";
140
+
141
+ return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
142
+ return typeof o;
143
+ } : function (o) {
144
+ return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
145
+ }, _typeof(o);
146
+ }
147
+ var __awaiter = void 0 && (void 0).__awaiter || function (thisArg, _arguments, P, generator) {
148
+ function adopt(value) {
149
+ return value instanceof P ? value : new P(function (resolve) {
150
+ resolve(value);
151
+ });
152
+ }
153
+ return new (P || (P = Promise))(function (resolve, reject) {
154
+ function fulfilled(value) {
155
+ try {
156
+ step(generator.next(value));
157
+ } catch (e) {
158
+ reject(e);
159
+ }
160
+ }
161
+ function rejected(value) {
162
+ try {
163
+ step(generator["throw"](value));
164
+ } catch (e) {
165
+ reject(e);
166
+ }
167
+ }
168
+ function step(result) {
169
+ result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
170
+ }
171
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
172
+ });
173
+ };
174
+ (function (factory) {
175
+ if ((typeof module === "undefined" ? "undefined" : _typeof(module)) === "object" && _typeof(module.exports) === "object") {
176
+ var v = factory(require, exports);
177
+ if (v !== undefined) module.exports = v;
178
+ } else if (typeof define === "function" && define.amd) {
179
+ define(["require", "exports", "./BatchReporter", "./reporters"], factory);
180
+ }
181
+ })(function (require, exports) {
182
+ "use strict";
183
+
184
+ Object.defineProperty(exports, "__esModule", {
185
+ value: true
186
+ });
187
+ exports.MonitorSDK = void 0;
188
+ var BatchReporter_1 = require("./BatchReporter");
189
+ var reporters_1 = require("./reporters");
190
+ /**
191
+ * 前端监控SDK核心类
192
+ */
193
+ var MonitorSDK = /*#__PURE__*/function () {
194
+ /**
195
+ * 构造函数
196
+ * @param config SDK配置
197
+ */
198
+ function MonitorSDK(config) {
199
+ _classCallCheck(this, MonitorSDK);
200
+ // 记录上一页URL,用于单页应用路由变化时的referrer
201
+ this.lastPageUrl = document.referrer || '';
202
+ this.appId = config.appId || '';
203
+ this.reportUrl = config.reportUrl || '';
204
+ // 确保sampleRates是Record<string, number>类型
205
+ if (config.sampleRates) {
206
+ this.sampleRates = Object.keys(config.sampleRates).reduce(function (acc, key) {
207
+ var value = config.sampleRates[key];
208
+ acc[key] = value !== undefined ? value : 1;
209
+ return acc;
210
+ }, {});
211
+ } else {
212
+ this.sampleRates = {
213
+ pageview: 1,
214
+ jserror: 1,
215
+ api: 1,
216
+ resource: 1
217
+ };
218
+ }
219
+ this.batchReporter = new BatchReporter_1.BatchReporter({
220
+ url: this.reportUrl,
221
+ batchSize: config.batchSize || 10,
222
+ interval: config.interval || 5000
223
+ });
224
+ this.sessionId = this.generateSessionId();
225
+ // 优先使用配置中的userId,如果没有则尝试从token中提取
226
+ this.userId = config.userId || this.getUserIdFromToken();
227
+ // 获取版本号,PC端从process.env.VUE_APP_VERSION获取,小程序和APP使用各自的版本号
228
+ this.version = this.getAppVersion(config);
229
+ this.init();
230
+ }
231
+ /**
232
+ * 获取应用版本号
233
+ */
234
+ return _createClass(MonitorSDK, [{
235
+ key: "getAppVersion",
236
+ value: function getAppVersion(config) {
237
+ // 优先使用配置传入的版本号
238
+ if (config.version) {
239
+ return config.version;
240
+ }
241
+ // PC端尝试从环境变量获取
242
+ if (typeof process !== 'undefined' && process.env && process.env.VUE_APP_VERSION) {
243
+ return process.env.VUE_APP_VERSION;
244
+ }
245
+ // 小程序环境检测
246
+ if (typeof wx !== 'undefined' && wx.getSystemInfoSync) {
247
+ try {
248
+ var systemInfo = wx.getSystemInfoSync();
249
+ return systemInfo.AppVersion || systemInfo.version || '1.0.0';
250
+ } catch (e) {
251
+ // 忽略错误
252
+ }
253
+ }
254
+ // APP环境检测
255
+ if (typeof window !== 'undefined' && window.navigator && window.navigator.userAgent) {
256
+ // 根据实际APP的userAgent格式调整
257
+ var ua = window.navigator.userAgent;
258
+ // 这里可以根据具体APP的UA格式进行解析
259
+ }
260
+ return '1.0.0'; // 默认版本号
261
+ }
262
+ /**
263
+ * 生成会话ID
264
+ */
265
+ }, {
266
+ key: "generateSessionId",
267
+ value: function generateSessionId() {
268
+ return "".concat(Date.now(), "_").concat(Math.random().toString(36).substring(2, 9));
269
+ }
270
+ /**
271
+ * 从token中提取userId
272
+ * 小程序环境:直接从本地缓存中取"token"
273
+ * 网页环境:先尝试从sessionStorage中取"-token",再尝试从cookie里取"Admin-Token"
274
+ * 取出token后截取最后12位作为userid
275
+ */
276
+ }, {
277
+ key: "getUserIdFromToken",
278
+ value: function getUserIdFromToken() {
279
+ var token = null;
280
+ // 1. 先检查是否为小程序环境
281
+ try {
282
+ if (typeof wx !== 'undefined' && wx.getStorageSync) {
283
+ // 小程序环境,直接从本地缓存中获取token
284
+ var wxToken = wx.getStorageSync('token');
285
+ if (wxToken) {
286
+ token = wxToken;
287
+ }
288
+ }
289
+ } catch (error) {
290
+ console.warn('Failed to get token from wx storage:', error);
291
+ }
292
+ // 2. 如果不是小程序环境或未获取到token,尝试从sessionStorage中获取token
293
+ if (!token) {
294
+ try {
295
+ if (typeof window !== 'undefined' && window.sessionStorage) {
296
+ token = sessionStorage.getItem('-token');
297
+ }
298
+ } catch (error) {
299
+ console.warn('Failed to get token from sessionStorage:', error);
300
+ }
301
+ }
302
+ // 3. 如果sessionStorage中没有token,尝试从cookie中获取
303
+ if (!token) {
304
+ try {
305
+ if (typeof document !== 'undefined') {
306
+ var cookieMatch = document.cookie.match(/Admin-Token=([^;]+)/);
307
+ if (cookieMatch && cookieMatch[1]) {
308
+ token = cookieMatch[1];
309
+ }
310
+ }
311
+ } catch (error) {
312
+ console.warn('Failed to get token from cookie:', error);
313
+ }
314
+ }
315
+ // 4. 从token中提取userId(截取最后12位)
316
+ if (token && token.length >= 12) {
317
+ return token.slice(-12);
318
+ }
319
+ return undefined;
320
+ }
321
+ /**
322
+ * 初始化SDK
323
+ */
324
+ }, {
325
+ key: "init",
326
+ value: function init() {
327
+ var _this = this;
328
+ // 初始化各类监控
329
+ this.initPageViewMonitor();
330
+ this.initErrorMonitor();
331
+ this.initApiMonitor();
332
+ this.initResourceMonitor();
333
+ // 页面卸载时清理
334
+ window.addEventListener('unload', function () {
335
+ _this.cleanup();
336
+ });
337
+ }
338
+ /**
339
+ * 清理资源
340
+ */
341
+ }, {
342
+ key: "cleanup",
343
+ value: function cleanup() {
344
+ if (this.originalXHRSend) {
345
+ XMLHttpRequest.prototype.send = this.originalXHRSend;
346
+ }
347
+ // 销毁批量上报器
348
+ if (this.batchReporter) {
349
+ this.batchReporter.destroy();
350
+ }
351
+ }
352
+ /**
353
+ * 页面浏览监控
354
+ */
355
+ }, {
356
+ key: "initPageViewMonitor",
357
+ value: function initPageViewMonitor() {
358
+ var _this2 = this;
359
+ var startTime = Date.now();
360
+ var pageInfo = {
361
+ pageUrl: window.location.href,
362
+ pageTitle: document.title,
363
+ referrer: document.referrer,
364
+ timestamp: startTime
365
+ };
366
+ // 更新lastPageUrl为当前页面URL
367
+ this.lastPageUrl = window.location.href;
368
+ // 页面加载完成上报
369
+ window.addEventListener('load', function () {
370
+ var performanceData = _this2.getPerformanceData();
371
+ _this2.reportPageView(Object.assign(Object.assign({}, pageInfo), {
372
+ duration: Date.now() - startTime,
373
+ isFirstVisit: _this2.isFirstVisit(),
374
+ performance: performanceData
375
+ }));
376
+ });
377
+ // 单页应用路由变化监控
378
+ if (window.history.pushState) {
379
+ var originalPushState = window.history.pushState;
380
+ var originalReplaceState = window.history.replaceState;
381
+ var handleHistoryChange = function handleHistoryChange() {
382
+ // 获取当前URL
383
+ var currentUrl = window.location.href;
384
+ // 只有当URL真正变化时才上报,避免replaceState导致的重复上报
385
+ if (currentUrl !== _this2.lastPageUrl) {
386
+ _this2.reportPageView({
387
+ pageUrl: currentUrl,
388
+ pageTitle: document.title,
389
+ referrer: _this2.lastPageUrl,
390
+ timestamp: Date.now(),
391
+ duration: 0,
392
+ isFirstVisit: false,
393
+ performance: _this2.getPerformanceData()
394
+ });
395
+ // 更新上一页URL为当前URL
396
+ _this2.lastPageUrl = currentUrl;
397
+ }
398
+ };
399
+ window.history.pushState = function () {
400
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
401
+ args[_key] = arguments[_key];
402
+ }
403
+ originalPushState.apply(this, args);
404
+ handleHistoryChange();
405
+ };
406
+ window.history.replaceState = function () {
407
+ // 保存调用前的URL
408
+ var prevUrl = window.location.href;
409
+ for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
410
+ args[_key2] = arguments[_key2];
411
+ }
412
+ originalReplaceState.apply(this, args);
413
+ handleHistoryChange();
414
+ };
415
+ // 监听popstate事件
416
+ window.addEventListener('popstate', handleHistoryChange);
417
+ }
418
+ }
419
+ /**
420
+ * 错误监控
421
+ */
422
+ }, {
423
+ key: "initErrorMonitor",
424
+ value: function initErrorMonitor() {
425
+ var _this3 = this;
426
+ // JS错误
427
+ window.addEventListener('error', function (event) {
428
+ _this3.reportJSError({
429
+ message: event.message,
430
+ errorType: event.error ? event.error.name : 'Error',
431
+ file: event.filename,
432
+ line: event.lineno || 0,
433
+ column: event.colno || 0,
434
+ stack: event.error ? event.error.stack || '' : '',
435
+ url: window.location.href,
436
+ timestamp: Date.now()
437
+ });
438
+ });
439
+ // Promise错误
440
+ window.addEventListener('unhandledrejection', function (event) {
441
+ _this3.reportJSError({
442
+ message: event.reason ? String(event.reason) : 'Promise rejection',
443
+ errorType: 'PromiseRejection',
444
+ file: '',
445
+ line: 0,
446
+ column: 0,
447
+ stack: event.reason ? event.reason.stack || '' : '',
448
+ url: window.location.href,
449
+ timestamp: Date.now()
450
+ });
451
+ });
452
+ }
453
+ /**
454
+ * API监控
455
+ */
456
+ }, {
457
+ key: "initApiMonitor",
458
+ value: function initApiMonitor() {
459
+ // 生成请求ID
460
+ var generateRequestId = function generateRequestId() {
461
+ return "".concat(Date.now(), "_").concat(Math.random().toString(36).substring(2, 11));
462
+ };
463
+ // 解析URL,分离基础URL和完整URL
464
+ var parseUrl = function parseUrl(urlStr) {
465
+ try {
466
+ var urlList = urlStr.split('?');
467
+ // 基础URL(不包含查询参数和hash)
468
+ var baseUrl = urlList[0];
469
+ // 完整URL(包含查询参数和hash)
470
+ var fullUrl = urlStr;
471
+ return {
472
+ baseUrl: baseUrl,
473
+ fullUrl: fullUrl
474
+ };
475
+ } catch (_a) {
476
+ // 如果URL解析失败,则使用原始URL
477
+ return {
478
+ baseUrl: urlStr,
479
+ fullUrl: urlStr
480
+ };
481
+ }
482
+ };
483
+ // 重写fetch
484
+ // this.originalFetch = window.fetch;
485
+ // window.fetch = async (...args) => {
486
+ // const [url, options] = args;
487
+ // const urlStr = typeof url === 'string' ? url : url.toString();
488
+ // // 排除SDK自身的上报请求,避免死循环
489
+ // // 1. 检查是否有特殊标记表示这是SDK内部请求
490
+ // const isSdkInternalRequest = options?.headers?.['x-sdk-internal'] === 'true';
491
+ // // 2. 检查是否是已知的SDK上报路径,包括批量上报相关路径
492
+ // const knownReportPaths = ['/v1/report/collect', '/v1/report/collectImg', '/api/report/collect'];
493
+ // const isKnownReportPath = knownReportPaths.some(path => urlStr.includes(path));
494
+ // // 3. 检查是否是配置的上报URL
495
+ // const isConfiguredReportUrl = this.reportUrl && urlStr.includes(this.reportUrl);
496
+ // // 4. 对于没有头信息的请求(如sendBeacon和img上报),增加更严格的路径匹配
497
+ // const isBatchReportPath = urlStr.includes('/v1/report/collect') || urlStr.includes('/v1/report/collectImg');
498
+ // // 如果是SDK自身的上报请求,则直接使用原始fetch
499
+ // if (isSdkInternalRequest || isKnownReportPath || isConfiguredReportUrl || isBatchReportPath) {
500
+ // return this.originalFetch!(...args);
501
+ // }
502
+ // const startTime = Date.now();
503
+ // const method = options?.method || 'GET';
504
+ // const requestId = generateRequestId();
505
+ // const { baseUrl, fullUrl } = parseUrl(urlStr);
506
+ // try {
507
+ // const response = await this.originalFetch!(...args);
508
+ // const reportData = {
509
+ // requestId,
510
+ // url: baseUrl,
511
+ // fullUrl,
512
+ // method,
513
+ // status: response.status,
514
+ // isError: response.status >= 400,
515
+ // responseTime: Date.now() - startTime,
516
+ // timestamp: startTime,
517
+ // pageUrl: window.location.href
518
+ // };
519
+ // // 上报API数据
520
+ // this.reportApi(reportData);
521
+ // return response;
522
+ // } catch (error) {
523
+ // const reportData = {
524
+ // requestId,
525
+ // url: baseUrl,
526
+ // fullUrl,
527
+ // method,
528
+ // status: 0,
529
+ // isError: true,
530
+ // errorType: (error as Error).name || 'FetchError',
531
+ // responseTime: Date.now() - startTime,
532
+ // timestamp: startTime,
533
+ // pageUrl: window.location.href
534
+ // };
535
+ // // 上报错误API
536
+ // this.reportApi(reportData);
537
+ // throw error;
538
+ // }
539
+ // };
540
+ // 重写XMLHttpRequest
541
+ var originalXHROpen = XMLHttpRequest.prototype.open;
542
+ var originalSend = XMLHttpRequest.prototype.send;
543
+ this.originalXHRSend = originalSend;
544
+ var xhrMap = new WeakMap();
545
+ var that = this;
546
+ // 覆盖XMLHttpRequest.open方法
547
+ var originalOpen = originalXHROpen;
548
+ XMLHttpRequest.prototype.open = function (method, url, async, username, password) {
549
+ var urlStr = typeof url === 'string' ? url : url.toString();
550
+ // 排除SDK自身的上报请求,避免死循环
551
+ // 1. 检查是否有特殊标记表示这是SDK内部请求(通过自定义属性)
552
+ if (this._isSdkInternalRequest) {
553
+ return originalOpen.call(this, method, url, async === undefined ? true : async, username, password);
554
+ }
555
+ // 2. 检查是否是已知的SDK上报路径,包括批量上报相关路径
556
+ var knownReportPaths = ['/v1/report/collect', '/v1/report/collectImg', '/api/report/collect'];
557
+ var isKnownReportPath = knownReportPaths.some(function (path) {
558
+ return urlStr.includes(path);
559
+ });
560
+ // 3. 检查是否是配置的上报URL
561
+ var isConfiguredReportUrl = that.reportUrl && urlStr.includes(that.reportUrl);
562
+ // 4. 对于没有头信息的请求(如sendBeacon和img上报),增加更严格的路径匹配
563
+ var isBatchReportPath = urlStr.includes('/v1/report/collect') || urlStr.includes('/v1/report/collectImg');
564
+ // 如果是SDK自身的上报请求,则直接使用原始open方法
565
+ if (isKnownReportPath || isConfiguredReportUrl || isBatchReportPath) {
566
+ return originalOpen.call(this, method, url, async === undefined ? true : async, username, password);
567
+ }
568
+ var _parseUrl = parseUrl(urlStr),
569
+ baseUrl = _parseUrl.baseUrl,
570
+ fullUrl = _parseUrl.fullUrl;
571
+ var requestId = generateRequestId();
572
+ xhrMap.set(this, {
573
+ startTime: Date.now(),
574
+ url: baseUrl,
575
+ fullUrl: fullUrl,
576
+ method: method || 'GET',
577
+ requestId: requestId
578
+ });
579
+ return originalOpen.call(this, method, url, async === undefined ? true : async, username, password);
580
+ };
581
+ XMLHttpRequest.prototype.send = function () {
582
+ var _this4 = this;
583
+ var xhrInfo = xhrMap.get(this);
584
+ for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
585
+ args[_key3] = arguments[_key3];
586
+ }
587
+ if (!xhrInfo) {
588
+ // @ts-ignore
589
+ return originalSend.apply(this, args);
590
+ }
591
+ // 获取请求体大小(字节)
592
+ var requestBodySize = 0;
593
+ if (args && args[0] !== undefined && args[0] !== null) {
594
+ if (typeof args[0] === 'string') {
595
+ // 字符串请求体,使用TextEncoder获取字节长度
596
+ try {
597
+ requestBodySize = new TextEncoder().encode(args[0]).length;
598
+ } catch (e) {
599
+ // 降级方案:估算字节长度
600
+ requestBodySize = args[0].length;
601
+ }
602
+ } else if (args[0] instanceof FormData) {
603
+ // FormData请求体,尝试估算大小
604
+ // 注意:由于安全限制,无法精确获取FormData的大小
605
+ requestBodySize = -1; // 表示未知大小
606
+ } else if (args[0] instanceof Blob) {
607
+ // Blob/File请求体
608
+ requestBodySize = args[0].size;
609
+ } else {
610
+ // 其他类型,尝试转换为字符串估算
611
+ try {
612
+ var str = JSON.stringify(args[0]);
613
+ requestBodySize = new TextEncoder().encode(str).length;
614
+ } catch (e) {
615
+ requestBodySize = -1;
616
+ }
617
+ }
618
+ }
619
+ // 保存请求体大小到xhrInfo中
620
+ Object.assign(xhrInfo, {
621
+ requestBodySize: requestBodySize
622
+ });
623
+ this.addEventListener('loadend', function () {
624
+ var endTime = Date.now();
625
+ var responseTime = endTime - xhrInfo.startTime;
626
+ var status = _this4.status;
627
+ // 获取响应体大小(字节)
628
+ var responseBodySize = 0;
629
+ try {
630
+ if (_this4.responseText) {
631
+ responseBodySize = new TextEncoder().encode(_this4.responseText).length;
632
+ } else if (_this4.response) {
633
+ if (typeof _this4.response === 'string') {
634
+ responseBodySize = new TextEncoder().encode(_this4.response).length;
635
+ } else if (_this4.response instanceof ArrayBuffer) {
636
+ responseBodySize = _this4.response.byteLength;
637
+ } else if (_this4.response instanceof Blob) {
638
+ responseBodySize = _this4.response.size;
639
+ } else {
640
+ // 尝试JSON序列化估算
641
+ try {
642
+ var _str = JSON.stringify(_this4.response);
643
+ responseBodySize = new TextEncoder().encode(_str).length;
644
+ } catch (e) {
645
+ responseBodySize = -1;
646
+ }
647
+ }
648
+ }
649
+ } catch (e) {
650
+ // 如果无法获取响应体大小,设置为-1
651
+ responseBodySize = -1;
652
+ }
653
+ var reportData = {
654
+ requestId: xhrInfo.requestId,
655
+ url: xhrInfo.url,
656
+ fullUrl: xhrInfo.fullUrl,
657
+ method: xhrInfo.method,
658
+ status: status,
659
+ isError: status >= 400 || _this4.status === 0,
660
+ responseTime: responseTime,
661
+ timestamp: xhrInfo.startTime,
662
+ pageUrl: window.location.href,
663
+ errorType: status === 0 ? 'NetworkError' : "HTTP".concat(status),
664
+ requestBodySize: requestBodySize,
665
+ responseBodySize: responseBodySize
666
+ };
667
+ // 上报API数据
668
+ that.reportApi(reportData);
669
+ });
670
+ return originalSend.apply(this, args);
671
+ };
672
+ }
673
+ /**
674
+ * 资源监控
675
+ */
676
+ }, {
677
+ key: "initResourceMonitor",
678
+ value: function initResourceMonitor() {
679
+ var _this5 = this;
680
+ // 通过PerformanceObserver监控资源加载
681
+ if ('PerformanceObserver' in window) {
682
+ try {
683
+ var observer = new PerformanceObserver(function (list) {
684
+ list.getEntries().forEach(function (entry) {
685
+ if (entry.entryType === 'resource') {
686
+ var resourceEntry = entry;
687
+ // 检查资源是否加载失败 - 使用类型断言处理responseStatus
688
+ var typedEntry = resourceEntry;
689
+ if (typedEntry.responseStatus && typedEntry.responseStatus >= 400) {
690
+ _this5.reportResource({
691
+ url: resourceEntry.name,
692
+ type: _this5.getResourceType(resourceEntry.name),
693
+ status: typedEntry.responseStatus,
694
+ timestamp: resourceEntry.startTime,
695
+ pageUrl: window.location.href,
696
+ duration: resourceEntry.duration,
697
+ size: resourceEntry.transferSize || 0,
698
+ initiator: resourceEntry.initiatorType
699
+ });
700
+ }
701
+ }
702
+ });
703
+ });
704
+ observer.observe({
705
+ entryTypes: ['resource'],
706
+ buffered: true
707
+ });
708
+ } catch (error) {
709
+ console.error('PerformanceObserver初始化失败:', error);
710
+ }
711
+ }
712
+ // 监听资源错误事件
713
+ window.addEventListener('error', function (event) {
714
+ if (event.target && (event.target instanceof HTMLScriptElement || event.target instanceof HTMLLinkElement || event.target instanceof HTMLImageElement || event.target instanceof HTMLAudioElement || event.target instanceof HTMLVideoElement)) {
715
+ var target = event.target;
716
+ _this5.reportResource({
717
+ url: target.src || target.href || '',
718
+ type: _this5.getResourceType(target.src || target.href || ''),
719
+ status: 0,
720
+ errorType: 'loaderror',
721
+ timestamp: Date.now(),
722
+ pageUrl: window.location.href,
723
+ initiator: target.tagName.toLowerCase(),
724
+ duration: 0,
725
+ size: 0
726
+ });
727
+ }
728
+ }, true);
729
+ }
730
+ /**
731
+ * 获取资源类型
732
+ */
733
+ }, {
734
+ key: "getResourceType",
735
+ value: function getResourceType(url) {
736
+ var _a;
737
+ var ext = (_a = url.split('?')[0].split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
738
+ if (!ext) return 'other';
739
+ if (['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'bmp', 'ico'].indexOf(ext) !== -1) return 'image';
740
+ if (['js'].indexOf(ext) !== -1) return 'js';
741
+ if (['css'].indexOf(ext) !== -1) return 'css';
742
+ if (['woff', 'woff2', 'ttf', 'eot', 'otf'].indexOf(ext) !== -1) return 'font';
743
+ if (['mp4', 'webm', 'ogg'].indexOf(ext) !== -1) return 'video';
744
+ if (['mp3', 'wav', 'ogg'].indexOf(ext) !== -1) return 'audio';
745
+ return 'other';
746
+ }
747
+ /**
748
+ * 获取性能数据
749
+ */
750
+ }, {
751
+ key: "getPerformanceData",
752
+ value: function getPerformanceData() {
753
+ var timing = performance.timing;
754
+ return {
755
+ navigationStart: timing.navigationStart,
756
+ domContentLoadedEventEnd: timing.domContentLoadedEventEnd,
757
+ loadEventEnd: timing.loadEventEnd
758
+ };
759
+ }
760
+ /**
761
+ * 判断是否首次访问
762
+ */
763
+ }, {
764
+ key: "isFirstVisit",
765
+ value: function isFirstVisit() {
766
+ var key = "first_visit_".concat(this.appId);
767
+ if (!localStorage.getItem(key)) {
768
+ localStorage.setItem(key, 'true');
769
+ return true;
770
+ }
771
+ return false;
772
+ }
773
+ /**
774
+ * 上报页面浏览
775
+ */
776
+ }, {
777
+ key: "reportPageView",
778
+ value: function reportPageView(data) {
779
+ var payload = {
780
+ type: 'pageview',
781
+ data: Object.assign({
782
+ appId: this.appId,
783
+ version: this.version,
784
+ sessionId: this.sessionId,
785
+ userId: this.userId,
786
+ deviceInfo: this.getDeviceInfo(),
787
+ networkInfo: this.getNetworkInfo()
788
+ }, data)
789
+ };
790
+ this.doReport(payload, 'pageview');
791
+ }
792
+ /**
793
+ * 上报JS错误
794
+ */
795
+ }, {
796
+ key: "reportJSError",
797
+ value: function reportJSError(data) {
798
+ var payload = {
799
+ type: 'jserror',
800
+ data: Object.assign({
801
+ appId: this.appId,
802
+ version: this.version,
803
+ sessionId: this.sessionId,
804
+ userId: this.userId,
805
+ deviceInfo: this.getDeviceInfo()
806
+ }, data)
807
+ };
808
+ this.doReport(payload, 'jserror');
809
+ }
810
+ /**
811
+ * 上报API数据
812
+ */
813
+ }, {
814
+ key: "reportApi",
815
+ value: function reportApi(data) {
816
+ var payload = {
817
+ type: 'api',
818
+ data: Object.assign({
819
+ appId: this.appId,
820
+ version: this.version,
821
+ sessionId: this.sessionId,
822
+ userId: this.userId,
823
+ networkInfo: this.getNetworkInfo()
824
+ }, data)
825
+ };
826
+ this.doReport(payload, 'api');
827
+ }
828
+ /**
829
+ * 上报资源错误
830
+ */
831
+ }, {
832
+ key: "reportResource",
833
+ value: function reportResource(data) {
834
+ var payload = {
835
+ type: 'resource',
836
+ data: Object.assign({
837
+ appId: this.appId,
838
+ version: this.version,
839
+ sessionId: this.sessionId,
840
+ userId: this.userId
841
+ }, data)
842
+ };
843
+ this.doReport(payload, 'resource');
844
+ }
845
+ /**
846
+ * 统一上报处理
847
+ */
848
+ }, {
849
+ key: "doReport",
850
+ value: function doReport(payload, type) {
851
+ var _a;
852
+ // 采样处理
853
+ var sampleRate = (_a = this.sampleRates[type]) !== null && _a !== void 0 ? _a : 1;
854
+ if (Math.random() > sampleRate) return;
855
+ // 数据脱敏
856
+ var sanitizedPayload = Object.assign(Object.assign({}, payload), {
857
+ data: this.sanitizeData(Object.assign(Object.assign({}, payload.data), {
858
+ version: this.version
859
+ }))
860
+ });
861
+ // 根据数据类型选择上报方式
862
+ if (type === 'pageview' && typeof navigator.sendBeacon === 'function') {
863
+ // 页面浏览使用sendBeacon
864
+ (0, reporters_1.reportByImg)(sanitizedPayload, this.reportUrl);
865
+ } else if (type === 'jserror' || type === 'resource') {
866
+ // 错误数据立即上报
867
+ // reportByApi(sanitizedPayload, this.reportUrl).catch(() => {
868
+ // // 降级到img上报
869
+ // reportByImg(sanitizedPayload, this.reportUrl);
870
+ // });
871
+ (0, reporters_1.reportWithFallback)(sanitizedPayload, this.reportUrl);
872
+ } else {
873
+ // 其他数据批量上报
874
+ this.batchReporter.report(sanitizedPayload);
875
+ }
876
+ }
877
+ /**
878
+ * 获取设备信息
879
+ */
880
+ }, {
881
+ key: "getDeviceInfo",
882
+ value: function getDeviceInfo() {
883
+ var ua = navigator.userAgent;
884
+ return {
885
+ browser: this.getBrowser(ua),
886
+ browserVersion: this.getBrowserVersion(ua),
887
+ os: this.getOS(ua),
888
+ osVersion: this.getOSVersion(ua),
889
+ deviceType: this.getDeviceType(),
890
+ screenWidth: window.screen.width,
891
+ screenHeight: window.screen.height,
892
+ language: navigator.language || ''
893
+ };
894
+ }
895
+ /**
896
+ * 获取网络信息
897
+ */
898
+ }, {
899
+ key: "getNetworkInfo",
900
+ value: function getNetworkInfo() {
901
+ // 安全地获取网络信息
902
+ var connection = navigator.connection || null;
903
+ if (connection) {
904
+ return {
905
+ type: connection.effectiveType || 'unknown',
906
+ effectiveType: connection.effectiveType || 'unknown'
907
+ };
908
+ }
909
+ return {
910
+ type: 'unknown',
911
+ effectiveType: 'unknown'
912
+ };
913
+ }
914
+ /**
915
+ * 获取浏览器信息
916
+ */
917
+ }, {
918
+ key: "getBrowser",
919
+ value: function getBrowser(ua) {
920
+ if (ua.includes('Chrome')) return 'Chrome';
921
+ if (ua.includes('Safari') && !ua.includes('Chrome')) return 'Safari';
922
+ if (ua.includes('Firefox')) return 'Firefox';
923
+ if (ua.includes('Edge')) return 'Edge';
924
+ if (ua.includes('Trident') || ua.includes('MSIE')) return 'IE';
925
+ return 'Unknown';
926
+ }
927
+ /**
928
+ * 获取浏览器版本
929
+ */
930
+ }, {
931
+ key: "getBrowserVersion",
932
+ value: function getBrowserVersion(ua) {
933
+ // 简化版本,实际项目中可能需要更复杂的正则匹配
934
+ var versionRegex = /(Chrome|Safari|Firefox|Edge|MSIE)\/?\s*(\d+\.\d*)/i;
935
+ var match = ua.match(versionRegex);
936
+ return match ? match[2] : 'Unknown';
937
+ }
938
+ /**
939
+ * 获取操作系统
940
+ */
941
+ }, {
942
+ key: "getOS",
943
+ value: function getOS(ua) {
944
+ if (ua.includes('Windows')) return 'Windows';
945
+ if (ua.includes('Mac OS')) return 'MacOS';
946
+ if (ua.includes('iOS')) return 'iOS';
947
+ if (ua.includes('Android')) return 'Android';
948
+ if (ua.includes('Linux')) return 'Linux';
949
+ return 'Unknown';
950
+ }
951
+ /**
952
+ * 获取操作系统版本
953
+ */
954
+ }, {
955
+ key: "getOSVersion",
956
+ value: function getOSVersion(ua) {
957
+ // 简化版本
958
+ if (ua.includes('Windows')) {
959
+ if (ua.includes('Windows NT 10.0')) return '10';
960
+ if (ua.includes('Windows NT 6.3')) return '8.1';
961
+ if (ua.includes('Windows NT 6.2')) return '8';
962
+ if (ua.includes('Windows NT 6.1')) return '7';
963
+ return 'Unknown';
964
+ }
965
+ return 'Unknown';
966
+ }
967
+ /**
968
+ * 获取设备类型
969
+ */
970
+ }, {
971
+ key: "getDeviceType",
972
+ value: function getDeviceType() {
973
+ var ua = navigator.userAgent;
974
+ if (/mobile|android|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(ua)) {
975
+ return 'mobile';
976
+ }
977
+ return 'desktop';
978
+ }
979
+ /**
980
+ * 数据脱敏
981
+ */
982
+ }, {
983
+ key: "sanitizeData",
984
+ value: function sanitizeData(data) {
985
+ // 深拷贝数据,避免修改原始数据
986
+ var sanitized = JSON.parse(JSON.stringify(data));
987
+ // 脱敏处理函数
988
+ var _sanitize = function sanitize(obj) {
989
+ if (!obj || _typeof(obj) !== 'object') return obj;
990
+ // 遍历对象属性
991
+ Object.keys(obj).forEach(function (key) {
992
+ // 对常见敏感字段进行脱敏
993
+ if (['password', 'token', 'auth', 'credential', 'key'].some(function (sensitive) {
994
+ return key.toLowerCase().includes(sensitive);
995
+ })) {
996
+ obj[key] = '***';
997
+ }
998
+ // 邮箱脱敏
999
+ else if (key.toLowerCase().includes('email') && typeof obj[key] === 'string') {
1000
+ obj[key] = obj[key].replace(/(.{2})(.*)(@.*)/, '$1***$3');
1001
+ }
1002
+ // 手机号脱敏
1003
+ else if (key.toLowerCase().includes('phone') && typeof obj[key] === 'string') {
1004
+ obj[key] = obj[key].replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
1005
+ }
1006
+ // 递归处理嵌套对象
1007
+ else if (_typeof(obj[key]) === 'object') {
1008
+ _sanitize(obj[key]);
1009
+ }
1010
+ });
1011
+ };
1012
+ _sanitize(sanitized);
1013
+ return sanitized;
1014
+ }
1015
+ /**
1016
+ * 上报自定义事件
1017
+ */
1018
+ }, {
1019
+ key: "reportCustomEvent",
1020
+ value: function reportCustomEvent(eventType, eventData) {
1021
+ var _a;
1022
+ // 根据采样率决定是否上报
1023
+ var sampleRate = (_a = this.sampleRates['custom']) !== null && _a !== void 0 ? _a : 1;
1024
+ if (Math.random() > sampleRate) {
1025
+ return;
1026
+ }
1027
+ var reportData = {
1028
+ type: 'custom',
1029
+ data: {
1030
+ appId: this.appId,
1031
+ version: this.version,
1032
+ sessionId: this.sessionId,
1033
+ userId: this.userId,
1034
+ eventName: eventType,
1035
+ eventData: this.sanitizeData(eventData),
1036
+ timestamp: Date.now(),
1037
+ pageUrl: window.location.href
1038
+ }
1039
+ };
1040
+ // 使用批量上报
1041
+ this.batchReporter.report(reportData);
1042
+ }
1043
+ /**
1044
+ * 立即上报缓冲区数据
1045
+ */
1046
+ }, {
1047
+ key: "flush",
1048
+ value: function flush() {
1049
+ return __awaiter(this, void 0, void 0, /*#__PURE__*/_regenerator().m(function _callee() {
1050
+ return _regenerator().w(function (_context) {
1051
+ while (1) switch (_context.n) {
1052
+ case 0:
1053
+ if (!this.batchReporter) {
1054
+ _context.n = 1;
1055
+ break;
1056
+ }
1057
+ _context.n = 1;
1058
+ return this.batchReporter.flush();
1059
+ case 1:
1060
+ return _context.a(2);
1061
+ }
1062
+ }, _callee, this);
1063
+ }));
1064
+ }
1065
+ /**
1066
+ * 销毁SDK实例
1067
+ */
1068
+ }, {
1069
+ key: "destroy",
1070
+ value: function destroy() {
1071
+ this.cleanup();
1072
+ this.batchReporter.destroy();
1073
+ }
1074
+ }]);
1075
+ }();
1076
+ exports.MonitorSDK = MonitorSDK;
1077
+ exports.default = MonitorSDK;
1078
+ });
1079
+ //# sourceMappingURL=MonitorSDK.js.map