PageSourceSearch

https://www.xt.com/_static/public-json-config/js/xt-monitor/index-test.umd.js

js xt.com collected 2026-09-24 18:38:15 UTC 92,043 bytes, 2,381 lines download raw bytes

1(function (global, factory) {
2  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3  typeof define === 'function' && define.amd ? define(['exports'], factory) :
4  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.XTMonitor = {}));
5})(this, (function (exports) { 'use strict';
6
7  var name = "@xt/monitor";
8  var version$1 = "1.0.5";
9  var description = "XT monitoring package";
10  var main = "dist/index.cjs.js";
11  var module = "dist/index.esm.js";
12  var types = "dist/index.d.ts";
13  var scripts = {
14  	build: "npm run jest && gulp build",
15  	"build:patch": "npm run jest && npm run release:patch && gulp build",
16  	"build:minor": "npm run jest && npm run release:minor && gulp build",
17  	"build:major": "npm run jest && npm run release:major && gulp build",
18  	watch: "gulp watch",
19  	jest: "jest",
20  	"jest:watch": "jest --watch",
21  	"serve:test": "node e2e/test-server.js",
22  	"serve:test:watch": "nodemon --watch dist --watch e2e/public/dist --ext js,html,json --exec \"node e2e/test-server.js\"",
23  	"dev:e2e": "concurrently \"npm run watch\" \"npm run serve:test:watch\"",
24  	e2e: "playwright test",
25  	"e2e:ui": "playwright test --ui",
26  	"e2e:report": "playwright show-report",
27  	dev: "npm run build -- --mode=local && npm run serve:test",
28  	"test:server": "node e2e/test-server.js",
29  	release: "standard-version",
30  	"release:dry": "standard-version --dry-run",
31  	"release:major": "standard-version --release-as major",
32  	"release:minor": "standard-version --release-as minor",
33  	"release:patch": "standard-version --release-as patch",
34  	prerelease: "standard-version --prerelease alpha"
35  };
36  var peerDependencies = {
37  };
38  var devDependencies = {
39  	"@playwright/test": "^1.55.0",
40  	"@rollup/plugin-commonjs": "^22.0.2",
41  	"@rollup/plugin-json": "^4.1.0",
42  	"@rollup/plugin-node-resolve": "^16.0.1",
43  	"@rollup/plugin-replace": "^6.0.2",
44  	"@rollup/plugin-typescript": "^8.5.0",
45  	"@types/jest": "^30.0.0",
46  	"@types/minimatch": "^6.0.0",
47  	"@types/node": "^20.4.5",
48  	compression: "^1.8.1",
49  	concurrently: "^9.2.1",
50  	cors: "^2.8.5",
51  	cros: "^1.1.0",
52  	dotenv: "^17.2.1",
53  	"dts-bundle": "^0.7.3",
54  	express: "^5.1.0",
55  	gulp: "^5.0.0",
56  	"gulp-typescript": "^6.0.0-alpha.1",
57  	jest: "^30.0.5",
58  	"jest-environment-jsdom": "^30.0.5",
59  	nodemon: "^3.1.10",
60  	"npm-cli-login": "^1.0.0",
61  	playwright: "^1.55.0",
62  	rollup: "^2.79.2",
63  	"rollup-plugin-terser": "^7.0.2",
64  	shelljs: "^0.10.0",
65  	"standard-version": "^9.5.0",
66  	"ts-jest": "^29.4.1",
67  	"ts-node": "^10.9.1",
68  	tslib: "^2.6.0",
69  	typescript: "^5.8.3",
70  	ws: "^8.18.3",
71  	yargs: "^18.0.0"
72  };
73  var dependencies = {
74  	"web-vitals": "^5.1.0",
75  	dsbridge: "^3.1.4"
76  };
77  var pkg = {
78  	name: name,
79  	version: version$1,
80  	description: description,
81  	main: main,
82  	module: module,
83  	types: types,
84  	scripts: scripts,
85  	peerDependencies: peerDependencies,
86  	devDependencies: devDependencies,
87  	dependencies: dependencies
88  };
89
90  const version = pkg.version;
91  const postUrl = "https://test-trace.hmswork.space/web" ;
92  const mode = "test" ;
93  var cfg = {
94      version,
95      postUrl,
96      mode
97  };
98
99  exports.ReportTypeEnum = void 0;
100  (function (ReportTypeEnum) {
101      ReportTypeEnum["EVENT"] = "event";
102      ReportTypeEnum["ERROR"] = "error";
103      ReportTypeEnum["PERFORMANCE"] = "performance";
104      ReportTypeEnum["API"] = "api";
105      ReportTypeEnum["SOCKET"] = "web-socket"; // socket 相关
106  })(exports.ReportTypeEnum || (exports.ReportTypeEnum = {}));
107
108  exports.ReportNameEnum = void 0;
109  (function (ReportNameEnum) {
110      // api 相关
111      ReportNameEnum["FETCH_SUCCESS"] = "fetch_success";
112      ReportNameEnum["FETCH_HTTP_ERROR"] = "fetch_http_error";
113      ReportNameEnum["FETCH_NETWORK_ERROR"] = "fetch_network_error";
114      ReportNameEnum["XHR_SUCCESS"] = "xhr_success";
115      ReportNameEnum["XHR_HTTP_ERROR"] = "xhr_http_error";
116      ReportNameEnum["XHR_NETWORK_ERROR"] = "xhr_network_error";
117      ReportNameEnum["XHR_ERROR"] = "xhr_error";
118      ReportNameEnum["XHR_TIMEOUT"] = "xhr_timeout";
119      ReportNameEnum["XHR_DETAIL"] = "xhr_detail";
120      ReportNameEnum["API_PERFORMANCE"] = "api_performance";
121      // 错误相关
122      ReportNameEnum["JS_ERROR"] = "js_error";
123      ReportNameEnum["RESOURCE_ERROR"] = "resource_error";
124      ReportNameEnum["PROMISE_ERROR"] = "promise_error";
125      // 页面相关
126      ReportNameEnum["CLICK"] = "click";
127      ReportNameEnum["VISIBILITY_CHANGE"] = "visibility_change";
128      ReportNameEnum["PAGE_VIEW"] = "page_view";
129      ReportNameEnum["TAB_CHANGE"] = "tab_change";
130      ReportNameEnum["WEB_VITAL"] = "web_vital";
131      // WebSocket 相关
132      ReportNameEnum["WS_CONNECTING"] = "ws_connecting";
133      ReportNameEnum["WS_CONNECT"] = "ws_connect";
134      ReportNameEnum["WS_DISCONNECT"] = "ws_disconnect";
135      ReportNameEnum["WS_ERROR"] = "ws_error";
136      // WS_MESSAGE = 'ws_message',           // WebSocket 消息
137      ReportNameEnum["WS_RECONNECT"] = "ws_reconnect";
138      ReportNameEnum["WS_PERFORMANCE"] = "ws_performance";
139      ReportNameEnum["WS_SEND_ERROR"] = "ws_send_error";
140      // WS_MESSAGE_ERROR = 'ws_message_error', // WebSocket 消息错误
141      // WS_MESSAGE_PARSE_ERROR = 'ws_message_parse_error' // WebSocket 消息解析错误
142      // 控制台相关 event 类型
143      ReportNameEnum["CONSOLE_ERROR"] = "console_error";
144      ReportNameEnum["CONSOLE_WARN"] = "console_warn";
145      ReportNameEnum["CONSOLE_INFO"] = "console_info";
146      ReportNameEnum["CONSOLE_DEBUG"] = "console_debug";
147      ReportNameEnum["CONSOLE_LOG"] = "console_log"; // console.log 信息
148  })(exports.ReportNameEnum || (exports.ReportNameEnum = {}));
149
150  /**
151   * 资源加载错误
152   * @param error
153   */
154  const resourceError = (error) => {
155      // 区分资源加载错误与 JS 运行时错误:
156      // - 运行时错误会有 error.error(Error 对象),不应当由资源上报处理
157      // - 资源错误的 event.target 是 HTMLElement(如 <img>, <link>, <script>),且 event.error 通常为 undefined
158      if (error && error.error) {
159          // 是 JS runtime error,交由 window.onerror / 其他错误处理器处理
160          return;
161      }
162      const target = error === null || error === void 0 ? void 0 : error.target;
163      if (!target || !(target instanceof HTMLElement)) {
164          // 不是资源元素,忽略
165          return;
166      }
167      const meta = {
168          tagName: target.tagName,
169          src: target.src || target.href,
170          outerHTML: target.outerHTML,
171      };
172      // 仅在确认为资源加载失败时上报
173      report(exports.ReportTypeEnum.ERROR, exports.ReportNameEnum.RESOURCE_ERROR, {
174          message: `Resource load failed: ${(meta.src) || meta.tagName}`,
175          type: "resource",
176      }, meta);
177  };
178  /**
179   * Promise 未处理的拒绝错误
180   * @param event
181   */
182  const unhandledrejection = (event) => {
183      const reason = event === null || event === void 0 ? void 0 : event.reason;
184      report(exports.ReportTypeEnum.ERROR, exports.ReportNameEnum.PROMISE_ERROR, {
185          message: (reason === null || reason === void 0 ? void 0 : reason.message) || String(reason),
186          type: "promise",
187          stack: (reason === null || reason === void 0 ? void 0 : reason.stack) || null
188      });
189  };
190  /** 原始的 window.onerror */
191  let oldWinError = window.onerror;
192  /**
193   * 开启错误监听
194   */
195  function setupErrorListeners() {
196      /** 资源加载错误 */
197      window.addEventListener("error", resourceError, true);
198      oldWinError = window.onerror;
199      /** js 运行错误 */
200      window.onerror = function (event, source, lineno, colno, error) {
201          report(exports.ReportTypeEnum.ERROR, exports.ReportNameEnum.JS_ERROR, {
202              message: (error === null || error === void 0 ? void 0 : error.message) || String(event),
203              stack: error === null || error === void 0 ? void 0 : error.stack,
204              type: "javascript",
205              source,
206              lineno,
207              colno,
208          });
209      };
210      /** Promise 未处理的拒绝错误 */
211      window.addEventListener("unhandledrejection", unhandledrejection, false);
212  }
213  function disabledErrorListener() {
214      // 注意:注册时使用了 capture = true,需要以相同参数移除
215      window.removeEventListener("error", resourceError, true);
216      window.removeEventListener("unhandledrejection", unhandledrejection, false);
217      window.onerror = oldWinError;
218  }
219  var errorMonitor = {
220      setupErrorListeners,
221      disabledErrorListener,
222  };
223
224  // 保存原始的 console 方法
225  let originalConsole;
226  /**
227   * 覆盖 console 方法来监控日志输出
228   */
229  function overrideConsole() {
230      originalConsole = {
231          log: console.log,
232          warn: console.warn,
233          error: console.error,
234          info: console.info,
235          debug: console.debug,
236      };
237      // 覆盖 console.log
238      console.log = function (...args) {
239          const logData = {
240              level: "log",
241              args: args,
242              timestamp: Date.now(),
243          };
244          // 上报日志数据
245          report(exports.ReportTypeEnum.EVENT, exports.ReportNameEnum.CONSOLE_LOG, logData);
246          // 调用原始方法
247          originalConsole.log.apply(console, args);
248      };
249      // 覆盖 console.warn
250      console.warn = function (...args) {
251          const logData = {
252              level: "warn",
253              args: args,
254              timestamp: Date.now(),
255          };
256          report(exports.ReportTypeEnum.EVENT, exports.ReportNameEnum.CONSOLE_WARN, logData);
257          originalConsole.warn.apply(console, args);
258      };
259      // 覆盖 console.error
260      console.error = function (...args) {
261          const logData = {
262              level: "error",
263              args: args,
264              timestamp: Date.now(),
265              stack: new Error().stack,
266          };
267          report(exports.ReportTypeEnum.ERROR, exports.ReportNameEnum.CONSOLE_ERROR, logData);
268          originalConsole.error.apply(console, args);
269      };
270      // 覆盖 console.info
271      console.info = function (...args) {
272          const logData = {
273              level: "info",
274              args: args,
275              timestamp: Date.now(),
276          };
277          report(exports.ReportTypeEnum.EVENT, exports.ReportNameEnum.CONSOLE_INFO, logData);
278          originalConsole.info.apply(console, args);
279      };
280      // 覆盖 console.debug
281      console.debug = function (...args) {
282          const logData = {
283              level: "debug",
284              args: args,
285              timestamp: Date.now(),
286          };
287          report(exports.ReportTypeEnum.EVENT, exports.ReportNameEnum.CONSOLE_DEBUG, logData);
288          originalConsole.debug.apply(console, args);
289      };
290  }
291  /**
292   * 获取原始的 console 方法
293   */
294  function getOriginalConsole() {
295      if (!originalConsole) {
296          // throw new Error('Console methods have not been overridden yet.');
297          return {
298              log: console.log,
299              warn: console.warn,
300              error: console.error,
301              info: console.info,
302              debug: console.debug,
303          };
304      }
305      return originalConsole;
306  }
307
308  const measureRequestMap = new Map(); // measureName -> requestId
309  // 允许的时间误差范围(毫秒)
310  let TIME_TOLERANCE = 50;
311  let performanceObservers;
312  /**
313   * 检测 WebView 能力
314   * @returns
315   */
316  function detectWebViewCapabilities() {
317      const capabilities = {
318          isWebView: false,
319          supportPerformanceObserver: false,
320          supportResourceTiming: false,
321          supportUserTiming: false,
322          webViewType: 'unknown'
323      };
324      // 检测 WebView 环境
325      const ua = navigator.userAgent;
326      if (/iPhone|iPad/.test(ua)) {
327          if (/Version\/[\d.]+.*Safari/.test(ua)) {
328              capabilities.webViewType = 'safari';
329          }
330          else {
331              capabilities.isWebView = true;
332              capabilities.webViewType = 'ios-webview';
333          }
334      }
335      else if (/Android/.test(ua)) {
336          if (/Chrome\/[\d.]+/.test(ua) && !/wv/.test(ua)) {
337              capabilities.webViewType = 'chrome';
338          }
339          else {
340              capabilities.isWebView = true;
341              capabilities.webViewType = 'android-webview';
342          }
343      }
344      // 检测 API 支持
345      capabilities.supportPerformanceObserver = 'PerformanceObserver' in window;
346      capabilities.supportResourceTiming = 'PerformanceResourceTiming' in window;
347      capabilities.supportUserTiming = 'performance' in window &&
348          typeof performance.mark === 'function' &&
349          typeof performance.measure === 'function';
350      return capabilities;
351  }
352  /**
353   * 监听网络性能数据 - 使用 User Timing API 方案
354   */
355  function setupPerformanceObserver() {
356      const OControl = getOriginalConsole();
357      const capabilities = detectWebViewCapabilities();
358      if (!capabilities.supportPerformanceObserver) {
359          OControl.warn('PerformanceObserver not supported, using fallback');
360          return setupFallbackPerformanceMonitor();
361      }
362      try {
363          // 资源监听器
364          const resourceObserver = new PerformanceObserver((list) => {
365              const entries = list.getEntries();
366              for (const entry of entries) {
367                  if (entry.entryType === 'resource' &&
368                      (entry.initiatorType === 'fetch' ||
369                          entry.initiatorType === 'xmlhttprequest')) {
370                      handleResourceTiming(entry);
371                  }
372              }
373          });
374          // 测量监听器 - 增加错误处理
375          const measureObserver = new PerformanceObserver((list) => {
376              try {
377                  const entries = list.getEntries();
378                  for (const entry of entries) {
379                      if (entry.entryType === 'measure' && entry.name.startsWith('api-request-')) {
380                          handleApiMeasure(entry);
381                      }
382                  }
383              }
384              catch (error) {
385                  OControl.warn('measureObserver error:', error);
386              }
387          });
388          // 安全的 observe 调用
389          try {
390              resourceObserver.observe({ entryTypes: ['resource'] });
391          }
392          catch (error) {
393              OControl.warn('Resource observer setup failed:', error);
394          }
395          try {
396              measureObserver.observe({ entryTypes: ['measure'] });
397          }
398          catch (error) {
399              OControl.warn('Measure observer setup failed:', error);
400          }
401          return { resourceObserver, measureObserver };
402      }
403      catch (error) {
404          OControl.error('Failed to setup PerformanceObserver:', error);
405          return setupFallbackPerformanceMonitor();
406      }
407  }
408  /**
409   * 降级方案 - 定时轮询
410   */
411  function setupFallbackPerformanceMonitor() {
412      const OControl = getOriginalConsole();
413      let isRunning = true;
414      const processedResources = new Set();
415      const processedMeasures = new Set();
416      const pollPerformanceEntries = () => {
417          if (!isRunning)
418              return;
419          try {
420              // 处理资源条目
421              const resources = performance.getEntriesByType('resource');
422              resources.forEach(entry => {
423                  const key = `${entry.name}-${entry.startTime}`;
424                  if (!processedResources.has(key) &&
425                      (entry.initiatorType === 'fetch' || entry.initiatorType === 'xmlhttprequest')) {
426                      processedResources.add(key);
427                      handleResourceTiming(entry);
428                  }
429              });
430              // 处理测量条目
431              const measures = performance.getEntriesByType('measure');
432              measures.forEach(entry => {
433                  const key = `${entry.name}-${entry.startTime}`;
434                  if (!processedMeasures.has(key) && entry.name.startsWith('api-request-')) {
435                      processedMeasures.add(key);
436                      handleApiMeasure(entry);
437                  }
438              });
439          }
440          catch (error) {
441              OControl.warn('Fallback performance monitor error:', error);
442          }
443          setTimeout(pollPerformanceEntries, 1000); // 1秒轮询
444      };
445      setTimeout(pollPerformanceEntries, 100); // 延迟启动
446      return {
447          resourceObserver: { disconnect: () => { isRunning = false; } },
448          measureObserver: { disconnect: () => { isRunning = false; } }
449      };
450  }
451  /**
452   * 处理资源时序数据
453   */
454  function handleResourceTiming(resourceEntry) {
455      var _a;
456      const url = resourceEntry.name;
457      // 策略1: 遍历所有相关的 measure,通过时间和 URL 匹配
458      const allMeasures = performance.getEntriesByType('measure');
459      const apiMeasures = allMeasures.filter(m => m.name.startsWith('api-request-'));
460      for (const measure of apiMeasures) {
461          const requestId = measureRequestMap.get(measure.name) || ((_a = measure.detail) === null || _a === void 0 ? void 0 : _a.requestId);
462          if (!requestId)
463              continue;
464          const metadata = requestMetadata.get(requestId);
465          if (!metadata)
466              continue;
467          // 匹配条件:URL 相同 且 开始时间接近
468          if (metadata.url === url &&
469              Math.abs(measure.startTime - resourceEntry.startTime) <= TIME_TOLERANCE) {
470              const performanceData = {
471                  url: metadata.url,
472                  type: metadata.type,
473                  startTime: resourceEntry.startTime,
474                  duration: resourceEntry.duration,
475                  name: `${metadata.method} ${metadata.url}`,
476                  requestId,
477                  // 性能细节
478                  dns: resourceEntry.domainLookupEnd - resourceEntry.domainLookupStart,
479                  tcp: resourceEntry.connectEnd - resourceEntry.connectStart,
480                  ssl: resourceEntry.secureConnectionStart > 0
481                      ? resourceEntry.connectEnd - resourceEntry.secureConnectionStart
482                      : 0,
483                  ttfb: resourceEntry.responseStart - resourceEntry.requestStart,
484                  responseTime: resourceEntry.responseEnd - resourceEntry.responseStart,
485                  transferSize: resourceEntry.transferSize,
486                  encodedBodySize: resourceEntry.encodedBodySize,
487                  decodedBodySize: resourceEntry.decodedBodySize,
488                  status: metadata.status,
489                  success: metadata.success,
490              };
491              // 上报性能数据
492              report(exports.ReportTypeEnum.API, exports.ReportNameEnum.API_PERFORMANCE, performanceData);
493              // 清理数据 - 添加 cleanup 调用
494              if (metadata.performanceMark) {
495                  metadata.performanceMark.cleanup();
496              }
497              requestMetadata.delete(requestId);
498              performance.clearMeasures(measure.name);
499              measureRequestMap.delete(measure.name);
500              return; // 找到匹配项后退出
501          }
502      }
503  }
504  /**
505   * 处理 API 测量数据 - 改进版
506   */
507  function handleApiMeasure(measure) {
508      var _a;
509      const OControl = getOriginalConsole();
510      try {
511          const requestId = measureRequestMap.get(measure.name) || ((_a = measure.detail) === null || _a === void 0 ? void 0 : _a.requestId);
512          if (!requestId) {
513              // 从 measure name 解析 requestId
514              const prefix = 'api-request-';
515              if (measure.name.startsWith(prefix)) {
516                  const parsedRequestId = measure.name.slice(prefix.length);
517                  const metadata = requestMetadata.get(parsedRequestId);
518                  if (metadata) {
519                      // 尝试找到对应的 resource timing
520                      tryMatchResourceTiming(measure, parsedRequestId, metadata);
521                  }
522              }
523              return;
524          }
525          const metadata = requestMetadata.get(requestId);
526          if (!metadata)
527              return;
528          // 尝试匹配 resource timing
529          tryMatchResourceTiming(measure, requestId, metadata);
530      }
531      catch (error) {
532          OControl.warn('handleApiMeasure error:', error);
533      }
534  }
535  /**
536   * 尝试匹配 resource timing
537   */
538  function tryMatchResourceTiming(measure, requestId, metadata) {
539      const findMatchingResource = () => {
540          const resources = performance.getEntriesByType('resource');
541          return resources.find(r => {
542              return r.name === metadata.url &&
543                  Math.abs(r.startTime - measure.startTime) <= TIME_TOLERANCE &&
544                  (r.initiatorType === 'fetch' || r.initiatorType === 'xmlhttprequest');
545          });
546      };
547      let resource = findMatchingResource();
548      if (!resource) {
549          // 短延迟后重试一次
550          setTimeout(() => {
551              const r = findMatchingResource();
552              if (r) {
553                  handleResourceTiming(r);
554              }
555          }, 100);
556      }
557      else {
558          handleResourceTiming(resource);
559      }
560  }
561  /**
562   * 增强版请求标记 - WebView 兼容
563   */
564  function createRequestMark(requestId, url) {
565      if (!('performance' in window)) {
566          return createFallbackMark(requestId, url);
567      }
568      const OControl = getOriginalConsole();
569      const capabilities = detectWebViewCapabilities();
570      if (!capabilities.supportUserTiming) {
571          return createFallbackMark(requestId, url);
572      }
573      try {
574          const measureName = `api-request-${requestId}`;
575          const startMarkName = `api-start-${requestId}`;
576          const endMarkName = `api-end-${requestId}`;
577          measureRequestMap.set(measureName, requestId);
578          // 安全的 mark 创建
579          try {
580              performance.mark(startMarkName);
581          }
582          catch (markError) {
583              OControl.warn('Failed to create start mark:', markError);
584              return createFallbackMark(requestId, url);
585          }
586          return {
587              markEnd: () => {
588                  try {
589                      performance.mark(endMarkName);
590                      performance.measure(measureName, startMarkName, endMarkName);
591                      // 尝试设置 detail,但不强制要求
592                      try {
593                          const measures = performance.getEntriesByName(measureName, 'measure');
594                          if (measures.length > 0) {
595                              measures[0].detail = { requestId, url };
596                          }
597                      }
598                      catch (detailError) {
599                          // 忽略 detail 设置失败
600                      }
601                  }
602                  catch (error) {
603                      OControl.warn('Failed to create performance measure:', error);
604                  }
605              },
606              cleanup: () => {
607                  var _a, _b, _c;
608                  try {
609                      (_a = performance.clearMarks) === null || _a === void 0 ? void 0 : _a.call(performance, startMarkName);
610                      (_b = performance.clearMarks) === null || _b === void 0 ? void 0 : _b.call(performance, endMarkName);
611                      (_c = performance.clearMeasures) === null || _c === void 0 ? void 0 : _c.call(performance, measureName);
612                      measureRequestMap.delete(measureName);
613                  }
614                  catch (error) {
615                      // 忽略清理错误
616                  }
617              }
618          };
619      }
620      catch (error) {
621          OControl.warn('Failed to create performance mark:', error);
622          return createFallbackMark(requestId, url);
623      }
624  }
625  /**
626   * 降级标记方案 - 使用简单时间记录
627   */
628  function createFallbackMark(requestId, url) {
629      const startTime = performance.now();
630      return {
631          markEnd: () => {
632              const endTime = performance.now();
633              const duration = endTime - startTime;
634              // 直接触发处理,不依赖 PerformanceObserver
635              setTimeout(() => {
636                  handleFallbackTiming(requestId, url, startTime, duration);
637              }, 0);
638          },
639          cleanup: () => {
640              // 清理 requestMetadata
641              requestMetadata.delete(requestId);
642          }
643      };
644  }
645  /**
646   * 降级时序处理
647   */
648  function handleFallbackTiming(requestId, url, startTime, duration) {
649      const metadata = requestMetadata.get(requestId);
650      if (!metadata)
651          return;
652      // 创建基础性能数据(没有详细的网络时序)
653      const performanceData = {
654          url: metadata.url,
655          type: metadata.type,
656          startTime,
657          duration,
658          name: `${metadata.method} ${metadata.url}`,
659          requestId,
660          status: metadata.status,
661          success: metadata.success,
662          // WebView 中可能无法获取的详细时序,设为 0 或 undefined
663          dns: 0,
664          tcp: 0,
665          ssl: 0,
666          ttfb: 0,
667          responseTime: duration, // 使用总时长作为响应时间
668      };
669      report(exports.ReportTypeEnum.API, exports.ReportNameEnum.API_PERFORMANCE, performanceData);
670      // 清理数据 - 添加 cleanup 调用
671      if (metadata.performanceMark) {
672          metadata.performanceMark.cleanup();
673      }
674      requestMetadata.delete(requestId);
675  }
676  function setupApiPerformanceMonitoring() {
677      const capabilities = detectWebViewCapabilities();
678      // 根据环境调整配置
679      if (capabilities.isWebView) {
680          // WebView 环境,使用更保守的配置
681          TIME_TOLERANCE = 200; // 增加时间容错
682      }
683      performanceObservers = setupPerformanceObserver();
684  }
685  function disableApiPerformanceMonitoring() {
686      if (performanceObservers) {
687          performanceObservers.resourceObserver.disconnect();
688          performanceObservers.measureObserver.disconnect();
689          performanceObservers = undefined;
690      }
691      // 清理请求元数据和性能标记
692      for (const [requestId, metadata] of requestMetadata) {
693          if (metadata.performanceMark) {
694              metadata.performanceMark.cleanup();
695          }
696      }
697      requestMetadata.clear();
698      measureRequestMap.clear(); // 清理映射
699  }
700
701  var PlatformTypeEnum;
702  (function (PlatformTypeEnum) {
703      PlatformTypeEnum["WEB"] = "web";
704      PlatformTypeEnum["H5"] = "h5";
705      PlatformTypeEnum["XT_DESKTOP"] = "X-Desktop";
706  })(PlatformTypeEnum || (PlatformTypeEnum = {}));
707
708  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
709
710  var bridge = {
711      default:commonjsGlobal,// for typescript
712      call: function (method, args, cb) {
713          var ret = '';
714          if (typeof args == 'function') {
715              cb = args;
716              args = {};
717          }
718          var arg={data:args===undefined?null:args};
719          if (typeof cb == 'function') {
720              var cbName = 'dscb' + window.dscb++;
721              window[cbName] = cb;
722              arg['_dscbstub'] = cbName;
723          }
724          arg = JSON.stringify(arg);
725
726          //if in webview that dsBridge provided, call!
727          if(window._dsbridge){
728             ret=  _dsbridge.call(method, arg);
729          }else if(window._dswk||navigator.userAgent.indexOf("_dsbridge")!=-1){
730             ret = prompt("_dsbridge=" + method, arg);
731          }
732
733         return  JSON.parse(ret||'{}').data
734      },
735      register: function (name, fun, asyn) {
736          var q = asyn ? window._dsaf : window._dsf;
737          if (!window._dsInit) {
738              window._dsInit = true;
739              //notify native that js apis register successfully on next event loop
740              setTimeout(function () {
741                  bridge.call("_dsb.dsinit");
742              }, 0);
743          }
744          if (typeof fun == "object") {
745              q._obs[name] = fun;
746          } else {
747              q[name] = fun;
748          }
749      },
750      registerAsyn: function (name, fun) {
751          this.register(name, fun, true);
752      },
753      hasNativeMethod: function (name, type) {
754          return this.call("_dsb.hasNativeMethod", {name: name, type:type||"all"});
755      },
756      disableJavascriptDialogBlock: function (disable) {
757          this.call("_dsb.disableJavascriptDialogBlock", {
758              disable: disable !== false
759          });
760      }
761  };
762
763  !function () {
764      if (window._dsf) return;
765      var ob = {
766          _dsf: {
767              _obs: {}
768          },
769          _dsaf: {
770              _obs: {}
771          },
772          dscb: 0,
773          dsBridge: bridge,
774          close: function () {
775              bridge.call("_dsb.closePage");
776          },
777          _handleMessageFromNative: function (info) {
778              var arg = JSON.parse(info.data);
779              var ret = {
780                  id: info.callbackId,
781                  complete: true
782              };
783              var f = this._dsf[info.method];
784              var af = this._dsaf[info.method];
785              var callSyn = function (f, ob) {
786                  ret.data = f.apply(ob, arg);
787                  bridge.call("_dsb.returnValue", ret);
788              };
789              var callAsyn = function (f, ob) {
790                  arg.push(function (data, complete) {
791                      ret.data = data;
792                      ret.complete = complete!==false;
793                      bridge.call("_dsb.returnValue", ret);
794                  });
795                  f.apply(ob, arg);
796              };
797              if (f) {
798                  callSyn(f, this._dsf);
799              } else if (af) {
800                  callAsyn(af, this._dsaf);
801              } else {
802                  //with namespace
803                  var name = info.method.split('.');
804                  if (name.length<2) return;
805                  var method=name.pop();
806                  var namespace=name.join('.');
807                  var obs = this._dsf._obs;
808                  var ob = obs[namespace] || {};
809                  var m = ob[method];
810                  if (m && typeof m == "function") {
811                      callSyn(m, ob);
812                      return;
813                  }
814                  obs = this._dsaf._obs;
815                  ob = obs[namespace] || {};
816                  m = ob[method];
817                  if (m && typeof m == "function") {
818                      callAsyn(m, ob);
819                      return;
820                  }
821              }
822          }
823      };
824      for (var attr in ob) {
825          window[attr] = ob[attr];
826      }
827      bridge.register("_hasJavascriptMethod", function (method, tag) {
828           var name = method.split('.');
829           if(name.length<2) {
830             return !!(_dsf[name]||_dsaf[name])
831           }else {
832             // with namespace
833             var method=name.pop();
834             var namespace=name.join('.');
835             var ob=_dsf._obs[namespace]||_dsaf._obs[namespace];
836             return ob&&!!ob[method]
837           }
838      });
839  }();
840
841  var dsbridge = bridge;
842
843  var NativeAPI;
844  (function (NativeAPI) {
845      NativeAPI["SESSION_ID"] = "sessionId";
846      NativeAPI["CLIENT_ID"] = "clientId";
847  })(NativeAPI || (NativeAPI = {}));
848  function call(api, params, callback) {
849      const oControl = getOriginalConsole();
850      if (typeof window == "undefined")
851          return;
852      try {
853          if (dsbridge.hasNativeMethod(api)) {
854              return dsbridge.call(api, params, callback);
855          }
856          else {
857              oControl.warn("【logErr】没有找到对应的Native方法:%s", api);
858          }
859      }
860      catch (e) {
861          oControl.error("【logErr】call %s:%o", api, e);
862      }
863  }
864  function getSessionId() {
865      return call(NativeAPI.SESSION_ID) || "";
866  }
867  function getClientId() {
868      return call(NativeAPI.CLIENT_ID) || "";
869  }
870  var jsbridge = {
871      getSessionId,
872      getClientId,
873      call,
874  };
875
876  var OSTypeEnum;
877  (function (OSTypeEnum) {
878      OSTypeEnum["IOS"] = "ios";
879      OSTypeEnum["ANDROID"] = "android";
880      OSTypeEnum["MAC"] = "mac";
881      OSTypeEnum["WINDOWS"] = "windows";
882      OSTypeEnum["UNKNOWN"] = "unknown";
883  })(OSTypeEnum || (OSTypeEnum = {}));
884
885  function getDeviceInfo() {
886      const ua = navigator === null || navigator === void 0 ? void 0 : navigator.userAgent;
887      if (!ua)
888          return {};
889      return {
890          userAgent: ua,
891          language: navigator === null || navigator === void 0 ? void 0 : navigator.language,
892          os: getOS(),
893      };
894  }
895  function getOS() {
896      const ua = window.navigator.userAgent.toLowerCase();
897      if (ua.includes("iphone") || ua.includes("ipad") || ua.includes("ipod")) {
898          return OSTypeEnum.IOS;
899      }
900      if (ua.includes("android")) {
901          return OSTypeEnum.ANDROID;
902      }
903      if (ua.includes("macintosh")) {
904          return OSTypeEnum.MAC;
905      }
906      if (ua.includes("windows")) {
907          return OSTypeEnum.WINDOWS;
908      }
909      return OSTypeEnum.UNKNOWN;
910  }
911  function isDesktop() {
912      var _a, _b;
913      const ua = ((_b = (_a = window === null || window === void 0 ? void 0 : window.navigator) === null || _a === void 0 ? void 0 : _a.userAgent) === null || _b === void 0 ? void 0 : _b.toLowerCase()) || "";
914      if (ua.includes("xt-desktop")) {
915          return true;
916      }
917      return false;
918  }
919  function getPlatform() {
920      const os = getOS();
921      if (os === OSTypeEnum.IOS || os === OSTypeEnum.ANDROID) {
922          return PlatformTypeEnum.H5;
923      }
924      if (isDesktop()) {
925          return PlatformTypeEnum.XT_DESKTOP;
926      }
927      return PlatformTypeEnum.WEB;
928  }
929
930  const _CLIENT_CODE_KEY = "__xt_client_code__";
931  const generateUniqueIdentifier = function () {
932      // 增强版:时间戳 + 更长随机字符串 + 计数器
933      const timestamp = Date.now().toString(36);
934      const random = Math.random().toString(36).substring(2, 15); // 13位随机字符
935      const counter = ((Math.random() * 1000) | 0).toString(36); // 3位计数器
936      return `${timestamp}-${random}-${counter}`;
937  };
938  const createClientCode = function () {
939      let code = "";
940      if (window.localStorage) {
941          code = window.localStorage.getItem(_CLIENT_CODE_KEY) || "";
942          if (!code) {
943              code = generateUniqueIdentifier();
944              window.localStorage.setItem(_CLIENT_CODE_KEY, code);
945          }
946      }
947      return code;
948  };
949  const getUserId = () => {
950      getUserId.userId = getUserId.userId || 0;
951      // 检查是否在浏览器环境中
952      if (typeof window === "undefined" || typeof document === "undefined") {
953          return getUserId.userId;
954      }
955      try {
956          var cookie = (document === null || document === void 0 ? void 0 : document.cookie) || "";
957          if (getUserId.cookie === cookie)
958              return getUserId.userId;
959          getUserId.cookie = cookie;
960          var tokenPart = cookie.split("token=")[1];
961          if (!tokenPart)
962              return getUserId.userId;
963          getUserId.userId = JSON.parse(atob(tokenPart.split(".")[1])).userId || 0;
964          return getUserId.userId;
965      }
966      catch (e) {
967          return getUserId.userId;
968      }
969  };
970  function getClientCode() {
971      let clientCode = "";
972      // 检查是否在浏览器环境中
973      if (typeof window === "undefined" || typeof document === "undefined") {
974          return "";
975      }
976      // native 优先通过 jsbridge 获取 clientId
977      if (getPlatform() === PlatformTypeEnum.H5) {
978          const clientId = jsbridge.getClientId();
979          if (clientId) {
980              return clientId;
981          }
982      }
983      // 如果不是 H5 平台或未能从 H5 容器获取 clientId,则ç”
983Ÿæˆæ–°çš„唯一标识符
984      try {
985          clientCode = document.cookie.split("clientCode=")[1].split(";")[0];
986          if (!clientCode) {
987              clientCode = createClientCode();
988          }
989      }
990      catch (e) {
991          clientCode = createClientCode();
992      }
993      return clientCode;
994  }
995
996  /**
997   * 监听 fetch 请求
998   */
999  function overrideFetch() {
1000      if (!window.fetch)
1001          return;
1002      const originFetch = window.fetch;
1003      window.fetch = function (input, init) {
1004          const url = typeof input === "string" ? input : input.toString();
1005          const method = (init === null || init === void 0 ? void 0 : init.method) || "GET";
1006          const requestId = generateUniqueIdentifier();
1007          // 创建性能标记
1008          const performanceMark = createRequestMark(requestId, url);
1009          // 存储请求信息
1010          requestMetadata.set(requestId, {
1011              url,
1012              method,
1013              type: API_TYPE.FETCH,
1014              startTime: performance.now(),
1015              performanceMark,
1016          });
1017          return originFetch
1018              .call(this, input, init)
1019              .then((response) => {
1020              // 结束性能标记
1021              const metadata = requestMetadata.get(requestId);
1022              if (metadata === null || metadata === void 0 ? void 0 : metadata.performanceMark) {
1023                  metadata.performanceMark.markEnd();
1024              }
1025              // 更新请求结果信息
1026              if (metadata) {
1027                  metadata.status = response.status;
1028                  metadata.success = response.ok;
1029              }
1030              // 上报基础成功信息(性能数据由 PerformanceObserver 处理)
1031              report(exports.ReportTypeEnum.API, exports.ReportNameEnum.FETCH_SUCCESS, {
1032                  url,
1033                  type: API_TYPE.FETCH,
1034                  name: `${method} ${url}`,
1035                  status: response.status,
1036                  statusText: response.statusText,
1037                  success: response.ok,
1038                  requestId,
1039              });
1040              // 如果状态码表示错误,也要记录
1041              if (!response.ok) {
1042                  report(exports.ReportTypeEnum.API, exports.ReportNameEnum.FETCH_HTTP_ERROR, {
1043                      url,
1044                      type: API_TYPE.FETCH,
1045                      name: `${method} ${url}`,
1046                      status: response.status,
1047                      statusText: response.statusText,
1048                      message: `HTTP ${response.status}: ${response.statusText}`,
1049                      requestId,
1050                  });
1051              }
1052              return response;
1053          })
1054              .catch((error) => {
1055              // 结束性能标记
1056              const metadata = requestMetadata.get(requestId);
1057              if (metadata === null || metadata === void 0 ? void 0 : metadata.performanceMark) {
1058                  metadata.performanceMark.markEnd();
1059              }
1060              // 更新请求结果信息
1061              if (metadata) {
1062                  metadata.success = false;
1063              }
1064              // 记录网络错误或其他异常
1065              report(exports.ReportTypeEnum.API, exports.ReportNameEnum.FETCH_NETWORK_ERROR, {
1066                  url,
1067                  type: API_TYPE.FETCH,
1068                  name: `${method} ${url}`,
1069                  error: error.message,
1070                  stack: error.stack,
1071                  success: false,
1072                  requestId,
1073              });
1074              throw error; // 重新抛出错误,保持原有行为
1075          });
1076      };
1077  }
1078  /**
1079   * 监听 XMLHttpRequest 请求
1080   */
1081  function overrideXHR() {
1082      if (!window.XMLHttpRequest)
1083          return;
1084      const OriginalXHR = window.XMLHttpRequest;
1085      function MonitorXMLHttpRequest() {
1086          const xhr = new OriginalXHR();
1087          let url;
1088          let method;
1089          let requestId;
1090          let performanceMark;
1091          // 重写 open 方法来获取请求信息
1092          const originalOpen = xhr.open;
1093          xhr.open = function (method_, url_, ...args) {
1094              method = method_;
1095              url = typeof url_ === "string" ? url_ : url_.toString();
1096              requestId = generateUniqueIdentifier();
1097              // 创建性能标记
1098              performanceMark = createRequestMark(requestId, url);
1099              // 存储请求信息
1100              requestMetadata.set(requestId, {
1101                  url,
1102                  method,
1103                  type: API_TYPE.XHR,
1104                  startTime: performance.now(),
1105                  performanceMark,
1106              });
1107              return originalOpen.apply(this, [method_, url_, ...args]);
1108          };
1109          // 新增:重写 send 方法,记录请求体
1110          const originalSend = xhr.send;
1111          xhr.send = function (body) {
1112              // 记录请求参数
1113              xhr._requestBody = body;
1114              return originalSend.apply(this, [body]);
1115          };
1116          // 监听状态变化
1117          xhr.addEventListener("readystatechange", function () {
1118              if (xhr.readyState === 4) {
1119                  // 请求完成
1120                  // 结束性能标记
1121                  if (performanceMark) {
1122                      performanceMark.markEnd();
1123                  }
1124                  // 更新请求结果信息
1125                  const metadata = requestMetadata.get(requestId);
1126                  if (metadata) {
1127                      metadata.status = xhr.status;
1128                      metadata.success = xhr.status >= 200 && xhr.status < 400;
1129                  }
1130                  const apiInfo = {
1131                      url,
1132                      type: API_TYPE.XHR,
1133                      name: `${method} ${url}`,
1134                      method,
1135                      status: xhr.status,
1136                      statusText: xhr.statusText,
1137                      requestId,
1138                  };
1139                  if (xhr.status === 0) {
1140                      // 网络错误或请求被取消
1141                      report(exports.ReportTypeEnum.API, exports.ReportNameEnum.XHR_NETWORK_E
1141RROR, Object.assign(Object.assign({}, apiInfo), { message: "Network error or request cancelled", success: false }));
1142                  }
1143                  else if (xhr.status >= 400) {
1144                      // HTTP 错误
1145                      report(exports.ReportTypeEnum.API, exports.ReportNameEnum.XHR_HTTP_ERROR, Object.assign(Object.assign({}, apiInfo), { message: `HTTP ${xhr.status}: ${xhr.statusText}` }));
1146                  }
1147                  else {
1148                      try {
1149                          // 获取请求参数
1150                          const requestParams = xhr._requestBody;
1151                          // 获取响应内容(注意:可能是文本或json,且大对象不建议直接上报)
1152                          let response = undefined;
1153                          const [, queryString] = xhr.responseURL.split("?");
1154                          try {
1155                              response =
1156                                  xhr.responseType === "" || xhr.responseType === "text"
1157                                      ? xhr.responseText
1158                                      : xhr.response;
1159                          }
1160                          catch (_a) { }
1161                          let responseObject = undefined;
1162                          if (typeof response === "string" && response) {
1163                              try {
1164                                  responseObject = JSON.parse(response);
1165                              }
1166                              catch (_b) {
1167                                  responseObject = response;
1168                              }
1169                          }
1170                          report(exports.ReportTypeEnum.API, exports.ReportNameEnum.XHR_DETAIL, Object.assign(Object.assign({}, apiInfo), { requestParams, response: responseObject, queryString, success: true }));
1171                      }
1172                      catch (e) {
1173                          // 忽略序列化或读取异常
1174                      }
1175                      // 成功请求
1176                      report(exports.ReportTypeEnum.API, exports.ReportNameEnum.XHR_SUCCESS, Object.assign(Object.assign({}, apiInfo), { success: true }));
1177                  }
1178              }
1179          });
1180          // 监听错误事件
1181          xhr.addEventListener("error", function (error) {
1182              if (performanceMark) {
1183                  performanceMark.markEnd();
1184              }
1185              const metadata = requestMetadata.get(requestId);
1186              if (metadata) {
1187                  metadata.success = false;
1188              }
1189              report(exports.ReportTypeEnum.API, exports.ReportNameEnum.XHR_ERROR, {
1190                  url,
1191                  type: API_TYPE.XHR,
1192                  name: `${method} ${url}`,
1193                  method,
1194                  message: "XMLHttpRequest error",
1195                  success: false,
1196                  requestId,
1197                  error,
1198              });
1199          });
1200          // 监听超时事件
1201          xhr.addEventListener("timeout", function () {
1202              if (performanceMark) {
1203                  performanceMark.markEnd();
1204              }
1205              const metadata = requestMetadata.get(requestId);
1206              if (metadata) {
1207                  metadata.success = false;
1208              }
1209              report(exports.ReportTypeEnum.API, exports.ReportNameEnum.XHR_TIMEOUT, {
1210                  url,
1211                  type: API_TYPE.XHR,
1212                  name: `${method} ${url}`,
1213                  method,
1214                  message: "XMLHttpRequest timeout",
1215                  success: false,
1216                  requestId,
1217              });
1218          });
1219          return xhr;
1220      }
1221      // 保持原型链和静态属性
1222      MonitorXMLHttpRequest.prototype = OriginalXHR.prototype;
1223      Object.setPrototypeOf(MonitorXMLHttpRequest, OriginalXHR);
1224      // 安全复制静态属性:使用描述符并跳过不可写或会报错的属性
1225      Object.getOwnPropertyNames(OriginalXHR).forEach((prop) => {
1226          // 跳过 prototype/name/length 等不应被覆盖的内置属性
1227          if (prop === "prototype" || prop === "name" || prop === "length")
1228              return;
1229          const desc = Object.getOwnPropertyDescriptor(OriginalXHR, prop);
1230          if (!desc)
1231              return;
1232          // 如果属性是不可配置且目标已有同名不可配置属性,跳过
1233          try {
1234              Object.defineProperty(MonitorXMLHttpRequest, prop, desc);
1235          }
1236          catch (e) {
1237              // 忽略无法定义的属性(如只读内置属性)
1238          }
1239      });
1240      window.XMLHttpRequest = MonitorXMLHttpRequest;
1241  }
1242
1243  var API_TYPE;
1244  (function (API_TYPE) {
1245      API_TYPE["FETCH"] = "fetch";
1246      API_TYPE["XHR"] = "xhr";
1247  })(API_TYPE || (API_TYPE = {}));
1248  // 存储请求的额外信息,使用 requestId 作为 key
1249  const requestMetadata = new Map();
1250  function setupListenerApi() {
1251      setupApiPerformanceMonitoring();
1252      overrideFetch();
1253      overrideXHR();
1254  }
1255  // 在 restoreAPI 中清理映射
1256  function disableListenerApi() {
1257      disableApiPerformanceMonitoring();
1258  }
1259  var apiMonitor = {
1260      setupListenerApi,
1261      disableListenerApi,
1262  };
1263
1264  const SESSION_KEY = "__xt_tracker_session_id__";
1265  const SESSION_EXPIRE_MINUTES = 30; // 过期时间
1266  function createSessionId() {
1267      // 优先从 H5 容器获取 sessionId
1268      if (PlatformTypeEnum.H5 === getPlatform()) {
1269          const sessionId = jsbridge.getSessionId();
1270          if (sessionId) {
1271              return sessionId;
1272          }
1273      }
1274      // 如果不是 H5 平台或未能从 H5 容器获取 sessionId,则生成新的唯一标识符
1275      return generateUniqueIdentifier();
1276  }
1277  /**
1278   * 创建或更新会话
1279   * @returns {SessionInfo} 会话信息
1280   */
1281  function createOrUpdateSession() {
1282      const now = Date.now();
1283      const sessionStr = sessionStorage.getItem(SESSION_KEY);
1284      let sessionData = {
1285          sessionId: "",
1286          sessionStartTime: now,
1287          sessionDuration: 0,
1288          lastActive: now,
1289      };
1290      if (sessionStr) {
1291          try {
1292              sessionData = JSON.parse(sessionStr);
1293              const inactiveTime = (now - sessionData.lastActive) / (1000 * 60);
1294              // 如果会话在过期时间内,则更新会话
1295              if (inactiveTime < SESSION_EXPIRE_MINUTES) {
1296                  sessionData.sessionDuration = now - sessionData.sessionStartTime || 0;
1297                  sessionData.lastActive = now;
1298                  localStorage.setItem(SESSION_KEY, JSON.stringify(sessionData));
1299                  return sessionData;
1300              }
1301          }
1302          catch (e) {
1303              // ignore
1304          }
1305      }
1306      // 创建新会话, 如果会话已过期也会创建新的会话
1307      const newSession = {
1308          sessionId: createSessionId(),
1309          sessionStartTime: now,
1310          sessionDuration: 0,
1311          lastActive: now,
1312      };
1313      sessionStorage.setItem(SESSION_KEY, JSON.stringify(newSession));
1314      return newSession;
1315  }
1316
1317  /******************************************************************************
1318  Copyright (c) Microsoft Corporation.
1319
1320  Permission to use, copy, modify, and/or distribute this software for any
1321  purpose with or without fee is hereby granted.
1322
1323  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
1324  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1325  AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1326  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1327  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1328  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1329  PERFORMANCE OF THIS SOFTWARE.
1330  ***************************************************************************** */
1331
1332  function __awaiter(thisArg, _arguments, P, generator) {
1333      function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1334      return new (P || (P = Promise))(function (resolve, reject) {
1335          function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
1336          function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
1337          function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
1338          step((generator = generator.apply(thisArg, _arguments || [])).next());
1339      });
1340  }
1341
1342  typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
1343      var e = new Error(message);
1344      return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1345  };
1346
1347  let lastPageUrl = window.location.href;
1348  function getPageInfo() {
1349      var _a;
1350      const page = {
1351          url: (_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.href,
1352          title: document === null || document === void 0 ? void 0 : document.title,
1353          referrer: document.referrer
1354              ? document.referrer
1355              : lastPageUrl !== window.location.href
1356                  ? lastPageUrl
1357                  : "",
1358      };
1359      lastPageUrl = window.location.href;
1360      return page;
1361  }
1362  /**
1363   * 监听页面卸载事件, 刷新 & 关闭
1364   * @param event
1365   */
1366  const beforeunloadHandler = (event) => {
1367      flushImmediateReports();
1368      apiMonitor.disableListenerApi();
1369      errorMonitor.disabledErrorListener();
1370      window.removeEventListener("beforeunload", beforeunloadHandler, true);
1371      window.removeEventListener("visibilitychange", visibilitychangeHandler, true);
1372      window.removeEventListener("blur", blurHandler, true);
1373      window.removeEventListener("focus", focusHandler, true);
1374      document.removeEventListener("click", onClick, true);
1375  };
1376  const visibilitychangeHandler = (event) => {
1377      report(exports.ReportTypeEnum.EVENT, exports.ReportNameEnum.VISIBILITY_CHANGE, {
1378          state: document.visibilityState,
1379      });
1380      if (!document.hidden) {
1381          flushImmediateReports();
1382      }
1383  };
1384  /** 上报 pv */
1385  const pv = function (args) {
1386      report(exports.ReportTypeEnum.EVENT, exports.ReportNameEnum.PAGE_VIEW, { args }, undefined, true);
1387  };
1388  /** 监控 pv 上报 */
1389  const pvListener = function () {
1390      const { history } = window || {};
1391      const originalPushState = history === null || history === void 0 ? void 0 : history.pushState;
1392      const originalReplaceState = history === null || history === void 0 ? void 0 : history.replaceState;
1393      if (!originalPushState || !originalReplaceState)
1394          return;
1395      history.pushState = function (...args) {
1396          // 处理 pushState 逻辑
1397          originalPushState.apply(this, args);
1398          pv(args);
1399      };
1400      history.replaceState = function (...args) {
1401          // 处理 replaceState 逻辑
1402          originalReplaceState.apply(this, args);
1403          const pageInfo = getPageInfo();
1404          if (pageInfo.url !== lastPageUrl) {
1405              pv(args);
1406          }
1407      };
1408  };
1409  const blurHandler = function (event) {
1410      report(exports.ReportTypeEnum.EVENT, exports.ReportNameEnum.TAB_CHANGE, { type: "blur" });
1411  };
1412  const focusHandler = function (event) {
1413      report(exports.ReportTypeEnum.EVENT, exports.ReportNameEnum.TAB_CHANGE, { type: "focus" });
1414  };
1415  const onClick = (e) => __awaiter(void 0, void 0, void 0, function* () {
1416      const target = e.target;
1417      if (!target)
1418          return;
1419      if (target === document.documentElement) {
1420          // target 是 html 根目录
1421          return;
1422      }
1423      if (target === document.body) {
1424          // target 是 body 元素
1425          return;
1426      }
1427      let outerHTML = target.outerHTML;
1428      if (outerHTML && outerHTML.length > 1000) {
1429          outerHTML = outerHTML.substring(0, 1000);
1430      }
1431      const meta = {
1432          tagName: target.tagName,
1433          id: target.id,
1434          className: target.className,
1435          outerHTML,
1436      };
1437      report(exports.ReportTypeEnum.EVENT, exports.ReportNameEnum.CLICK, e, meta);
1438  });
1439  function setupListenerPage() {
1440      // "beforeunload" 在页面刷新、关闭、跳转时触发,适合做离开上报,但部分浏览器可能限制异步操作
1441      window === null || window === void 0 ? void 0 : window.addEventListener("beforeunload", beforeunloadHandler, true);
1442      // "visibilitychange" 主要用于页面可见性变化,不一定代表离开页面,不建议单独用于离开上报
1443      window === null || window === void 0 ? void 0 : window.addEventListener("visibilitychange", visibilitychangeHandler, true);
1444      // tab 切换监听
1445      window.addEventListener("blur", blurHandler, true);
1446      window.addEventListener("focus", focusHandler, true);
1447      /** 监听页面上的点击事件 */
1448      document.addEventListener("click", onClick, true);
1449      // 监听 pv 上报
1450      pvListener();
1451  }
1452  var page = {
1453      setupListenerPage,
1454      getPageInfo,
1455      pv,
1456  };
1457
1458  // src/monitor/socket.ts
1459  // WebSocket 连接映射,用于跟踪每个连接的状态
1460  const socketConnections = new Map();
1461  /**
1462   * 计算消息大小(字节)
1463   */
1464  function getMessageSize(data) {
1465      if (typeof data === "string") {
1466          return new Blob([data]).size;
1467      }
1468      if (data instanceof ArrayBuffer) {
1469          return data.byteLength;
1470      }
1471      if (data instanceof Blob) {
1472          return data.size;
1473      }
1474      return 0;
1475  }
1476  /**
1477   * 计算延迟
1478   */
1479  function calculateLatency(connectionData) {
1480      const { latencyHistory } = connectionData;
1481      if (latencyHistory.length === 0)
1482          return 0;
1483      const sum = latencyHistory.reduce((a, b) => a + b, 0);
1484      return Math.round(sum / latencyHistory.length);
1485  }
1486  /**
1487   * 覆盖原生 WebSocket
1488   */
1489  function overrideWebSocket() {
1490      if (!window.WebSocket)
1491          return;
1492      const OriginalWebSocket = window.WebSocket;
1493      const OControl = getOriginalConsole();
1494      function MonitorWebSocket(url, protocols) {
1495          const socketUrl = url.toString();
1496          const socketProtocol = Array.isArray(protocols)
1497              ? protocols.join(",")
1498              : protocols || "";
1499          const socketId = generateUniqueIdentifier();
1500          const connectStartTime = Date.now();
1501          // 初始化连接数据
1502          const connectionData = {
1503              url: socketUrl,
1504              protocol: socketProtocol,
1505              connectTime: connectStartTime,
1506              messageCount: 0,
1507              sentBytes: 0,
1508              receivedBytes: 0,
1509              reconnectCount: 0,
1510              latencyHistory: [],
1511          };
1512          // 创建原始 WebSocket 实例
1513          const ws = new OriginalWebSocket(url, protocols);
1514          const connectingInfo = Object.assign(Object.assign({}, connectionData), { readyState: ws.readyState });
1515          report(exports.ReportTypeEnum.SOCKET, exports.ReportNameEnum.WS_CONNECTING, connectingInfo);
1516          // 立即设置连接数据映射
1517          socketConnections.set(ws, connectionData);
1518          // 监听连接打开
1519          ws.addEventListener("open", function (event) {
1520              const connectTime = Date.now() - connectStartTime;
1521              const socketInfo = {
1522                  url: socketUrl,
1523                  protocol: socketProtocol,
1524                  readyState: ws.readyState,
1525                  connectTime,
1526                  duration: connectTime,
1527                  messageCount: 0,
1528                  sentBytes: 0,
1529                  receivedBytes: 0,
1530                  socketId,
1531              };
1532              report(exports.ReportTypeEnum.SOCKET, exports.ReportNameEnum.WS_CONNECT, socketInfo);
1533          });
1534          // 监听连接关闭
1535          ws.addEventListener("close", function (event) {
1536              const data = socketConnections.get(ws);
1537              if (data) {
1538                  const totalDuration = Date.now() - data.connectTime;
1539                  const socketInfo = {
1540                      url: socketUrl,
1541                      protocol: socketProtocol,
1542                      readyState: ws.readyState,
1543                      duration: totalDuration,
1544                      messageCount: data.messageCount,
1545                      sentBytes: data.sentBytes,
1546                      receivedBytes: data.receivedBytes,
1547                      reconnectCount: data.reconnectCount,
1548                      latency: calculateLatency(data),
1549                      // 从 CloseEvent.code 读取关闭码;若未提供则为 undefined
1550                      errorCode: typeof event.code === "number" ? event.code : undefined,
1551                      errorMessage: event.reason || getCloseReasonText(event.code),
1552                      socketId,
1553                      wasClean: event.wasClean,
1554                      closeCode: event.code,
1555                      closeReason: event.reason,
1556                  };
1557                  report(exports.ReportTypeEnum.SOCKET, exports.ReportNameEnum.WS_DISCONNECT, socketInfo);
1558                  socketConnections.delete(ws);
1559              }
1560          });
1561          // 监听消息接收
1562          ws.addEventListener("message", function (event) {
1563              const data = socketConnections.get(ws);
1564              if (data) {
1565                  const messageSize = getMessageSize(event.data);
1566                  data.messageCount++;
1567                  data.receivedBytes += messageSize;
1568                  // 检测 pong 响应计算延迟
1569                  if (event.data === "pong" && data.lastPingTime) {
1570                      const latency = Date.now() - data.lastPingTime;
1571                      data.latencyHistory.push(latency);
1572                      if (data.latencyHistory.length > 10) {
1573                          data.latencyHistory.shift();
1574                      }
1575                      data.lastPingTime = undefined;
1576                  }
1577              }
1578          });
1579          // 监听错误 - 增强错误处理
1580          ws.addEventListener("error", function (event) {
1581              const data = socketConnections.get(ws);
1582              // 尝试从事件中获取更多错误信息
1583              let errorMessage = "WebSocket connection error";
1584              let errorType = "connection";
1585              // 检查不同类型的错误
1586              if (ws.readyState === WebSocket.CONNECTING) {
1587                  errorType = "connection_failed";
1588                  errorMessage = "Failed to establish WebSocket connection";
1589              }
1590              else if (ws.readyState === WebSocket.OPEN) {
1591                  errorType = "runtime_error";
1592                  errorMessage = "WebSocket runtime error";
1593              }
1594              else if (ws.readyState === WebSocket.CLOSING ||
1595                  ws.readyState === WebSocket.CLOSED) {
1596                  errorType = "disconnection_error";
1597                  errorMessage = "WebSocket disconnection error";
1598              }
1599              // 检查网络错误
1600              if (navigator.onLine === false) {
1601                  errorType = "network_offline";
1602                  errorMessage = "Network is offline";
1603              }
1604              const socketInfo = {
1605                  url: socketUrl,
1606                  protocol: socketProtocol,
1607                  readyState: ws.readyState,
1608                  errorType,
1609                  errorMessage,
1610                  messageCount: (data === null || data === void 0 ? void 0 : data.messageCount) || 0,
1611                  sentBytes: (data === null || data === void 0 ? void 0 : data.sentBytes) || 0,
1612                  receivedBytes: (data === null || data === void 0 ? void 0 : data.receivedBytes) || 0,
1613                  reconnectCount: (data === null || data === void 0 ? void 0 : data.reconnectCount) || 0,
1614              };
1615              report(exports.ReportTypeEnum.SOCKET, exports.ReportNameEnum.WS_ER
1615ROR, socketInfo);
1616          });
1617          // 重写 send 方法,添加发送错误处理
1618          const originalSend = ws.send.bind(ws);
1619          ws.send = function (data) {
1620              var _a, _b;
1621              const connectionData = socketConnections.get(ws);
1622              // Transparency rule: behave EXACTLY like the native WebSocket.send(), never
1623              // adding or removing an exception.
1624              //   - CLOSING / CLOSED: native silently DISCARDS the message (no throw). The
1625              //     original wrapper threw here, turning a normally-silent no-op into an
1626              //     exception that escaped to window.onerror (a trade-page heartbeat firing
1627              //     on a backgrounded app webview) — the bulk of the "WebSocket is
1628              //     CLOSING/CLOSED" reports. Record telemetry and return, matching native.
1629              //   - CONNECTING: native THROWS InvalidStateError; we deliberately do NOT
1630              //     intercept it (it falls through to originalSend below) so that behavior
1631              //     is preserved unchanged. Heartbeats start on 'open', so this is rarely hit.
1632              if (ws.readyState === WebSocket.CLOSING ||
1633                  ws.readyState === WebSocket.CLOSED) {
1634                  report(exports.ReportTypeEnum.SOCKET, exports.ReportNameEnum.WS_SEND_ERROR, {
1635                      url: socketUrl,
1636                      protocol: socketProtocol,
1637                      readyState: ws.readyState,
1638                      errorMessage: `Send skipped: WebSocket is ${getReadyStateText(ws.readyState)}`,
1639                      messageCount: (connectionData === null || connectionData === void 0 ? void 0 : connectionData.messageCount) || 0,
1640                      sentBytes: (connectionData === null || connectionData === void 0 ? void 0 : connectionData.sentBytes) || 0,
1641                      socketId,
1642                      // Do NOT log the raw frame: trade login frames carry token/apiKey/sign as
1643                      // a JSON string that sensitive() cannot scrub. Report only shape + size.
1644                      dataType: typeof data === "string"
1645                          ? "string"
1646                          : ((_a = data === null || data === void 0 ? void 0 : data.constructor) === null || _a === void 0 ? void 0 : _a.name) || typeof data,
1647                      byteLength: getMessageSize(data),
1648                  });
1649                  return;
1650              }
1651              try {
1652                  if (connectionData) {
1653                      const messageSize = getMessageSize(data);
1654                      connectionData.sentBytes += messageSize;
1655                      connectionData.messageCount++;
1656                      // 检测 ping 消息
1657                      if (data === "ping") {
1658                          connectionData.lastPingTime = Date.now();
1659                      }
1660                  }
1661                  return originalSend.call(this, data);
1662              }
1663              catch (error) {
1664                  // Reached for a CONNECTING send (native InvalidStateError) or a genuine
1665                  // OPEN-state send failure — both are native behavior; report + re-throw.
1666                  const cd = socketConnections.get(ws);
1667                  const socketInfo = {
1668                      url: socketUrl,
1669                      protocol: socketProtocol,
1670                      readyState: ws.readyState,
1671                      errorMessage: `Send message failed: ${error === null || error === void 0 ? void 0 : error.message}`,
1672                      messageCount: (cd === null || cd === void 0 ? void 0 : cd.messageCount) || 0,
1673                      sentBytes: (cd === null || cd === void 0 ? void 0 : cd.sentBytes) || 0,
1674                      socketId,
1675                      error: error.message,
1676                      // Do NOT log the raw frame (token/apiKey/sign leak); report shape + size.
1677                      dataType: typeof data === "string"
1678                          ? "string"
1679                          : ((_b = data === null || data === void 0 ? void 0 : data.constructor) === null || _b === void 0 ? void 0 : _b.name) || typeof data,
1680                      byteLength: getMessageSize(data),
1681                  };
1682                  report(exports.ReportTypeEnum.SOCKET, exports.ReportNameEnum.WS_SEND_ERROR, socketInfo);
1683                  throw error;
1684              }
1685          };
1686          return ws;
1687      }
1688      // 复制静态属性
1689      Object.setPrototypeOf(MonitorWebSocket, OriginalWebSocket);
1690      MonitorWebSocket.prototype = OriginalWebSocket.prototype;
1691      // 安全复制静态常量
1692      try {
1693          Object.defineProperty(MonitorWebSocket, "CONNECTING", {
1694              value: OriginalWebSocket.CONNECTING,
1695              writable: false,
1696          });
1697          Object.defineProperty(MonitorWebSocket, "OPEN", {
1698              value: OriginalWebSocket.OPEN,
1699              writable: false,
1700          });
1701          Object.defineProperty(MonitorWebSocket, "CLOSING", {
1702              value: OriginalWebSocket.CLOSING,
1703              writable: false,
1704          });
1705          Object.defineProperty(MonitorWebSocket, "CLOSED", {
1706              value: OriginalWebSocket.CLOSED,
1707              writable: false,
1708          });
1709      }
1710      catch (e) {
1711          // 如果无法定义,跳过
1712      }
1713      // 安全复制其他静态属性
1714      Object.getOwnPropertyNames(OriginalWebSocket).forEach((prop) => {
1715          if (prop === "prototype" || prop === "name" || prop === "length")
1716              return;
1717          if (prop === "CONNECTING" ||
1718              prop === "OPEN" ||
1719              prop === "CLOSING" ||
1720              prop === "CLOSED")
1721              return;
1722          const desc = Object.getOwnPropertyDescriptor(OriginalWebSocket, prop);
1723          if (!desc)
1724              return;
1725          try {
1726              Object.defineProperty(MonitorWebSocket, prop, desc);
1727          }
1728          catch (e) {
1729              // 忽略无法定义的属性
1730          }
1731      });
1732      window.WebSocket = MonitorWebSocket;
1733      OControl.log("WebSocket monitoring enabled");
1734  }
1735  /**
1736   * 获取 WebSocket 关闭码对应的文本描述
1737   */
1738  function getCloseReasonText(code) {
1739      const closeCodeMap = {
1740          1000: "Normal Closure",
1741          1001: "Going Away",
1742          1002: "Protocol Error",
1743          1003: "Unsupported Data",
1744          1004: "Reserved",
1745          1005: "No Status Received",
1746          1006: "Abnormal Closure",
1747          1007: "Invalid Frame Payload Data",
1748          1008: "Policy Violation",
1749          1009: "Message Too Big",
1750          1010: "Mandatory Extension",
1751          1011: "Internal Server Error",
1752          1015: "TLS Handshake",
1753      };
1754      return closeCodeMap[code] || `Unknown Code: ${code}`;
1755  }
1756  /**
1757   * 获取 WebSocket 状态对应的文本描述
1758   */
1759  function getReadyStateText(readyState) {
1760      const stateMap = {
1761          0: "CONNECTING",
1762          1: "OPEN",
1763          2: "CLOSING",
1764          3: "CLOSED",
1765      };
1766      return stateMap[readyState] || `Unknown State: ${readyState}`;
1767  }
1768  /**
1769   * 手动上报 WebSocket 重连事件
1770   */
1771  function reportWebSocketReconnect$1(url, reconnectCount, reconnectInterval) {
1772      const socketInfo = {
1773          url,
1774          protocol: "",
1775          readyState: WebSocket.CONNECTING,
1776          reconnectCount,
1777          reconnectInterval,
1778      };
1779      report(exports.ReportTypeEnum.SOCKET, exports.ReportNameEnum.WS_RECONNECT, socketInfo);
1780  }
1781  /**
1782   * 上报 WebSocket 性能数据
1783   */
1784  function reportWebSocketPerformance$1() {
1785      for (const [ws, data] of socketConnections) {
1786          if (ws.readyState === WebSocket.OPEN) {
1787              const currentTime = Date.now();
1788              const totalDuration = currentTime - data.connectTime;
1789              const socketInfo = {
1790                  url: data.url,
1791                  protocol: data.protocol,
1792                  readyState: ws.readyState,
1793                  bufferedAmount: ws.bufferedAmount,
1794                  duration: totalDuration,
1795                  messageCount: data.messageCount,
1796                  sentBytes: data.sentBytes,
1797                  receivedBytes: data.receivedBytes,
1798                  reconnectCount: data.reconnectCount,
1799                  latency: calculateLatency(data),
1800              };
1801              report(exports.ReportTypeEnum.SOCKET, exports.ReportNameEnum.WS_PERFORMANCE, socketInfo);
1802          }
1803      }
1804  }
1805  /**
1806   * 清理 WebSocket 监控
1807   */
1808  function disableWebSocketMonitoring() {
1809      socketConnections.clear();
1810  }
1811  /**
1812   * 启动 WebSocket 监控
1813   */
1814  function setupWebSocketMonitoring() {
1815      overrideWebSocket();
1816      // 定期上报性能数据(可选)
1817      setInterval(() => {
1818          reportWebSocketPerformance$1();
1819      }, 30000); // 每30秒上报一次性能数据
1820  }
1821  var socket = {
1822      setupWebSocketMonitoring,
1823      disableWebSocketMonitoring,
1824      overrideWebSocket,
1825      reportWebSocketReconnect: reportWebSocketReconnect$1,
1826      reportWebSocketPerformance: reportWebSocketPerformance$1,
1827  };
1828
1829  const initData = {
1830      initialized: false,
1831      projectName: "default",
1832      postUrl: cfg.postUrl, // 上报地址
1833      enableConsoleMonitor: false,
1834      enableSocketMonitor: false,
1835      env: "",
1836  };
1837  /**
1838   * 初始化监控 SDK
1839   *
1840   * 该函数用于初始化监控系统,包括设置项目参数、用户信息、上报地址、控制台和 WebSocket 监控等。
1841   * 会自动防止重复初始化,并在页面加载完成后执行初始化流程。
1842   *
1843   * @param initDataParam 初始化参数,可包含项目名、上报地址、用户 ID、客户端 ID、是否启用控制台/Socket 监控等
1844   *
1845   * - projectName: 项目名称
1846   * - postUrl: 日志上报地址
1847   * - uid: 用户 ID
1848   * - clientId: 客户端 ID
1849   * - enableConsoleMonitor: 是否启用控制台监控
1850   * - enableSocketMonitor: 是否启用 WebSocket 监控
1851   *
1852   * 初始化内容包括:
1853   * - 设置全局参数
1854   * - 启用控制台监控(可选)
1855   * - 初始化 session
1856   * - 启动错误、API、WebSocket 监控
1857   * - 首次上报 PV
1858   * - 绑定页面交互事件
1859   *
1860   * 只有在 document.readyState 为 complete 时才会执行初始化,否则会等待页面加载完成。
1861   */
1862  function initMonitor(initDataParam) {
1863      function doInit() {
1864          // 防止重复初始化
1865          if (initData.initialized)
1866              return;
1867          initData.projectName = initDataParam.projectName || "default"; // 项目名称
1868          initData.postUrl = initDataParam.postUrl || cfg.postUrl; // 上报地址
1869          initData.uid = initDataParam.uid || getUserId(); // 用户 ID
1870          initData.clientId = initDataParam.clientId || getClientCode(); // 客户端 ID
1871          initData.enableConsoleMonitor = initDataParam.enableConsoleMonitor || false;
1872          initData.enableSocketMonitor = initDataParam.enableSocketMonitor || false;
1873          initData.env = initDataParam.env || "";
1874          // 启用 console 监控
1875          if (initData.enableConsoleMonitor) {
1876              overrideConsole();
1877          }
1878          const OConsole = getOriginalConsole();
1879          // 初始化 session
1880          createOrUpdateSession();
1881          errorMonitor.setupErrorListeners(); // 错误监控开启
1882          apiMonitor.setupListenerApi(); // api监控
1883          if (initData.enableSocketMonitor) {
1884              socket.setupWebSocketMonitoring(); // WebSocket监控
1885          }
1886          report$1.initBeforeQueue();
1887          page.pv(); // 第一次进来上报 pv
1888          page.setupListenerPage(); // 页面交互监控
1889          OConsole.info("Monitor SDK version is:", cfg.version);
1890          OConsole.info("Initializing monitor with project:", initDataParam.projectName);
1891          initData.initialized = true;
1892      }
1893      if (document.readyState === "loading") {
1894          // DOM 还在加载中,等待 DOMContentLoaded
1895          document.addEventListener("DOMContentLoaded", doInit, { once: true });
1896      }
1897      else {
1898          // DOM 已经加载完成(interactive 或 complete),立即初始化
1899          doInit();
1900      }
1901  }
1902  function getMonitorInitData() {
1903      return initData;
1904  }
1905
1906  /**
1907   * 构建监控信息
1908   * @param type 监控类型
1909   * @param name 监控名称
1910   * @param params 监控参数
1911   * @param metadata 监控元数据
1912   * @param immediately 是否立即上报
1913   */
1914  function buildMintor(type, name, params = {}, metadata = {}, immediately = false) {
1915      var _a, _b;
1916      const initialMonitorData = getMonitorInitData();
1917      const preMonitorInfo = {
1918          projectName: initialMonitorData.projectName || "",
1919          ct: Date.now(),
1920          timezone: (_b = (_a = Intl === null || Intl === void 0 ? void 0 : Intl.DateTimeFormat()) === null || _a === void 0 ? void 0 : _a.resolvedOptions()) === null || _b === void 0 ? void 0 : _b.timeZone,
1921          version: cfg.version,
1922          platform: getPlatform(),
1923          immediately,
1924          type,
1925          env: initialMonitorData.env || "",
1926      };
1927      preMonitorInfo.session = createOrUpdateSession(); // 更新或者创建 session
1928      preMonitorInfo.page = page.getPageInfo(); // 获取当前页面信息
1929      preMonitorInfo.device = getDeviceInfo(); // 获取当前设备信息
1930      if (!initialMonitorData.uid) {
1931          initialMonitorData.uid = getUserId();
1932      }
1933      if (!initialMonitorData.clientId) {
1934          initialMonitorData.clientId = getClientCode();
1935      }
1936      preMonitorInfo.user = {
1937          uid: initialMonitorData.uid || "",
1938          clientId: initialMonitorData.clientId || "",
1939      };
1940      const baseEvent = {
1941          name: name,
1942          params,
1943          metadata,
1944      };
1945      if (type === exports.ReportTypeEnum.EVENT) {
1946          preMonitorInfo.event = baseEvent;
1947      }
1948      if (type === exports.ReportTypeEnum.PERFORMANCE) {
1949          preMonitorInfo.performance = Object.assign(Object.assign({}, baseEvent), { params: params });
1950      }
1951      if (type === exports.ReportTypeEnum.ERROR) {
1952          preMonitorInfo.error = Object.assign(Object.assign({}, baseEvent), { params: params });
1953      }
1954      if (type === exports.ReportTypeEnum.API) {
1955          preMonitorInfo.api = Object.assign(Object.assign({}, baseEvent), { params: params });
1956      }
1957      // 添加 WebSocket 支持
1958      if (type === exports.ReportTypeEnum.SOCKET) {
1959          preMonitorInfo.socket = Object.assign(Object.assign({}, baseEvent), { params: params });
1960      }
1961      return preMonitorInfo;
1962  }
1963
1964  /**
1965   * 移除对象中的敏感信息(如 token、authorization、password),并避免循环引用
1966   * @param data 需要处理的数据对象
1967   * @returns 处理后的对象
1968   */
1969  function sensitive(data) {
1970      if (!data || typeof data !== "object")
1971          return data;
1972      const cache = typeof WeakMap !== "undefined"
1973          ? new WeakMap()
1974          : new Map();
1975      function isSensitiveKey(lcKey) {
1976          // 精准与常见变体匹配(避免过度匹配普通字段)
1977          if (lcKey === "authorization" || lcKey === "password" || lcKey === "token")
1978              return true;
1979          if (/access[_-]?token$/.test(lcKey))
1980              return true; // access_token, access-token
1981          if (/^auth(?:orization|token)?$/.test(lcKey))
1982              return true; // auth, authToken, authorization
1983          return false;
1984      }
1985      function walk(obj) {
1986          if (obj === null || typeof obj !== "object")
1987              return obj;
1988          // 特殊类型处理
1989          if (obj instanceof Date)
1990              return obj.toISOString();
1991          if (obj instanceof Error)
1992              return { name: obj.name, message: obj.message, stack: obj.stack };
1993          if (cache.has(obj))
1994              return cache.get(obj);
1995          // Map / Set 处理
1996          if (obj instanceof Map) {
1997              const o = {};
1998              cache.set(obj, o);
1999              for (const [k, v] of obj.entries()) {
2000                  o[k] = walk(v);
2001              }
2002              return o;
2003          }
2004          if (obj instanceof Set) {
2005              const arr = [];
2006              cache.set(obj, arr);
2007              for (const v of obj)
2008                  arr.push(walk(v));
2009              return arr;
2010          }
2011          const res = Array.isArray(obj) ? [] : {};
2012          cache.set(obj, res);
2013          for (const k in obj) {
2014              if (!Object.prototype.hasOwnProperty.call(obj, k))
2015                  continue;
2016              const val = obj[k];
2017              const lcKey = k.toLowerCase();
2018              if (isSensitiveKey(lcKey)) {
2019                  res[k] = "***";
2020                  continue;
2021              }
2022              if (lcKey === "data") {
2023                  // 仅当 data 是对象时才 stringify,字符串保持原样
2024                  if (val && typeof val === "object") {
2025                      try {
2026                          // 递归处理后再 stringify,避免未脱敏嵌套
2027                          res[k] = JSON.stringify(walk(val));
2028                      }
2029                      catch (e) {
2030                          res[k] = "[unserializable data]";
2031                      }
2032                  }
2033                  else {
2034                      res[k] = val;
2035                  }
2036                  continue;
2037              }
2038              if (val && typeof val === "object") {
2039                  res[k] = walk(val);
2040              }
2041              else {
2042                  res[k] = val;
2043              }
2044          }
2045          return res;
2046      }
2047      return walk(data);
2048  }
2049
2050  const writeListConfig = {
2051      uidList: [],
2052      cidList: [],
2053      pathList: [],
2054  };
2055  let intervalID = 0;
2056  let loading = false;
2057  const GAP_TIME = 60000;
2058  const DEBUG_INFO_URL = "https://json.static-global.com/public-json-config/web/acc/debugInfo.json";
2059  /**
2060   * 自动同步白名单
2061   * @returns
2062   */
2063  const onSync = () => {
2064      if (intervalID)
2065          return;
2066      const OConsole = getOriginalConsole();
2067      if (window.localStorage.getItem("__xt_write_list_config__")) {
2068          const localConfig = window.localStorage.getItem("__xt_write_list_config__");
2069          if (localConfig) {
2070              Object.assign(writeListConfig, JSON.parse(localConfig));
2071          }
2072      }
2073      const loadList = function () {
2074          const url = DEBUG_INFO_URL;
2075          if (loading)
2076              return;
2077          loading = true;
2078          fetch(url, { method: "GET" })
2079              .then((response) => response.json())
2080              .then((data) => {
2081              writeListConfig.uidList = Array.isArray(data.uidList)
2082                  ? data.uidList
2083                  : [];
2084              writeListConfig.cidList = Array.isArray(data.cidList)
2085                  ? data.cidList
2086                  : [];
2087              writeListConfig.pathList = Array.isArray(data.pathList)
2088                  ? data.pathList
2089                  : [];
2090              window.localStorage.setItem("__xt_write_list_config__", JSON.stringify(writeListConfig));
2091          })
2092              .catch((error) => {
2093              OConsole.error("Error loading list:", error);
2094          })
2095              .finally(() => {
2096              loading = false;
2097          });
2098      };
2099      intervalID = window.setInterval(() => {
2100          loadList();
2101      }, GAP_TIME); // 每60秒同步一次
2102      loadList();
2103  };
2104  const closeSync = () => {
2105      if (intervalID) {
2106          clearInterval(intervalID);
2107          intervalID = 0;
2108      }
2109  };
2110  const getWriteListConfig = () => {
2111      const clonedConfig = JSON.parse(JSON.stringify(writeListConfig));
2112      return clonedConfig;
2113  };
2114  var writeList = {
2115      onSync,
2116      closeSync,
2117      getWriteListConfig,
2118      DEBUG_INFO_URL,
2119  };
2120
2121  const reportQueue = [];
2122  const postSize = 7;
2123  let scheduleId = null;
2124  const scheduleGap = 3000;
2125  // /** 上报调度 */
2126  // let scheduleFlush: Function = () => {
2127  //   const monitorInitData = getMonitorInitData();
2128  //   const { initialized } = monitorInitData || {};
2129  //   if (!initialized) return;
2130  //   const executeFlush = () => {
2131  //     flush(); // 执行发送
2132  //     secheduleID = null;
2133  //     // 如果队列还有数据,继续调度
2134  //     if (reportQueue.length > 0) scheduleFlush();
2135  //   };
2136  //   // 使用 requestIdleCallback 进行调度
2137  //   const idleCallbackWay = () => {
2138  //     if (secheduleID) window.cancelIdleCallback(secheduleID);
2139  //     if (reportQueue.length === 0) return;
2140  //     secheduleID = window.requestIdleCallback(executeFlush);
2141  //   };
2142  //   // 使用 Promise 进行调度
2143  //   const promiseWay = () => {
2144  //     if (secheduleID) return;
2145  //     secheduleID = 1;
2146  //     Promise.resolve().then(executeFlush);
2147  //   };
2148  //   scheduleFlush =
2149  //     typeof window?.requestIdleCallback === "function"
2150  //       ? idleCallbackWay
2151  //       : promiseWay;
2152  //   scheduleFlush();
2153  // };
2154  const scheduleFlush = () => {
2155      if (scheduleId)
2156          return;
2157      scheduleId = setInterval(() => {
2158          flush();
2159      }, scheduleGap);
2160  };
2161  /**
2162   * 重试上报
2163   * @param batch
2164   * @param attempt
2165   * @returns
2166   */
2167  function retryReport(batch, attempt = 1) {
2168      /** 原始控制台 */
2169      const OControl = getOriginalConsole();
2170      const tryTime = 3;
2171      if (attempt > tryTime) {
2172          OControl.error("Report failed after maximum retries");
2173          return;
2174      }
2175      // 暂时不需要宏队列
2176      // const delay = Math.pow(2, attempt - 1) * 1000; // 指数退避
2177      // setTimeout(() => {}, delay);
2178      const initialMonitorData = getMonitorInitData();
2179      const url = initialMonitorData.postUrl || "";
2180      // 使用 FormData 或 URLSearchParams 避免预检
2181      const formData = new FormData();
2182      formData.append("data", JSON.stringify(batch));
2183      window === null || window === void 0 ? void 0 : window.fetch(url, {
2184          method: "POST",
2185          body: formData, // 不设置 Content-Type,让浏览器自动处理
2186          keepalive: true,
2187      }).catch((error) => {
2188          OControl.error(`Report retry ${attempt} failed:`, error);
2189          retryReport(batch, attempt + 1);
2190      });
2191  }
2192  function postQueue(batch) {
2193      /** 原始控制台 */
2194      const OControl = getOriginalConsole();
2195      const initialMonitorData = getMonitorInitData();
2196      const url = initialMonitorData.postUrl || "";
2197      if (!url || (batch === null || batch === void 0 ? void 0 : batch.length) === 0) {
2198          return;
2199      }
2200      for (const item of batch || []) {
2201          // 补全项目信息
2202          item.projectName = initialMonitorData === null || initialMonitorData === void 0 ? void 0 : initialMonitorData.projectName;
2203          item.env = initialMonitorData === null || initialMonitorData === void 0 ? void 0 : initialMonitorData.env;
2204      }
2205      if (navigator === null || navigator === void 0 ? void 0 : navigator.sendBeacon) {
2206          const blob = new Blob([JSON.stringify(batch)], {
2207              type: "text/plain",
2208          });
2209          navigator.sendBeacon(url, blob);
2210      }
2211      else {
2212          // 使用 FormData 或 URLSearchParams 避免预检
2213          const formData = new FormData();
2214          formData.append("data", JSON.stringify(batch));
2215          window === null || window === void 0 ? void 0 : window.fetch(url, {
2216              method: "POST",
2217              body: formData, // 不设置 Content-Type,让浏览器自动处理
2218              keepalive: true,
2219          }).catch((error) => {
2220              OControl.error("Report failed:", error);
2221              // 方案1 - 使用重试机制
2222              retryReport(batch);
2223              // if (immediately) {
2224              // retryReport(batch);
2225              // } else {
2226              //   // 方案2 - 重新加入队列,准备重试
2227              //   reportQueue.unshift(...batch);
2228              //   scheduleFlush();
2229              // }
2230          });
2231      }
2232  }
2233  /**
2234   * 推送上报
2235   * @param immediately
2236   * @returns
2237   */
2238  function flush(immediately = false) {
2239      /** 没有初始化不能上报 */
2240      const monitorInitData = getMonitorInitData();
2241      const { initialized } = monitorInitData || {};
2242      if (!initialized)
2243          return;
2244      /** 原始控制台 */
2245      const OControl = getOriginalConsole();
2246      if (immediately) {
2247          const needPostLength = reportQueue.length;
2248          OControl.debug("[Mint]", "立即上报", needPostLength, "条数据");
2249          while (reportQueue.length > 0) {
2250              let batch = reportQueue.splice(0, postSize);
2251              postQueue(batch);
2252          }
2253      }
2254      else {
2255          let batch = reportQueue.splice(0, postSize);
2256          postQueue(batch);
2257      }
2258  }
2259  /**
2260   * 上报监控信息
2261   * @param type 监控类型
2262   * @param name 监控名称
2263   * @param params 监控参数
2264   * @param metadata 监控元数据
2265   * @param immediately 是否立即上报
2266   */
2267  function report(type = exports.ReportTypeEnum.EVENT, name, params, metadata, immediately = false) {
2268      var _a, _b;
2269      // 判断类型,如果类型不对不上报
2270      if (!Object.values(exports.ReportTypeEnum).includes(type)) {
2271          console.warn(`[Mint] report type ${type} is not supported`);
2272          return;
2273      }
2274      /** 没有初始化不能上报 */
2275      const monitorInitData = getMonitorInitData();
2276      /** 过滤上报接口本身的来源 */
2277      if (type === exports.ReportTypeEnum.API || type === exports.ReportTypeEnum.ERROR) {
2278          if ((params === null || params === void 0 ? void 0 : params.url) === monitorInitData.postUrl) {
2279              return;
2280          }
2281          if (params.url === writeList.DEBUG_INFO_URL) {
2282              return;
2283          }
2284      }
2285      // 检查白名单上报 response 详情
2286      if (name === exports.ReportNameEnum.XHR_DETAIL) {
2287          if (!params || !params.response)
2288              return;
2289          const { uid = 0, clientId = "" } = getMonitorInitData();
2290          const { uidList, cidList, pathList } = writeList.getWriteListConfig();
2291          const interDebugIds = [
2292              7514700383137, 8244871495780, 7819888689620, 8402971001641, 8402981946048,
2293          ];
2294          // 只要在 uidList 或 cidList 白名单,直接允许上报
2295          if (uidList.includes(Number(uid)) ||
2296              cidList.includes(clientId) ||
2297              interDebugIds.includes(Number(uid))) ;
2298          else if (pathList.length > 0) {
2299              // 不在白名单,检查路径白名单
2300              const drp = (_b = (_a = params === null || params === void 0 ? void 0 : params.response) === null || _a === void 0 ? void 0 : _a.config) === null || _b === void 0 ? void 0 : _b.url;
2301              if (!drp)
2302                  return;
2303              const matched = pathList.some((p) => drp.endsWith(p));
2304              // console.log("matched:", pathList, "drp:", drp, "matched:", matched);
2305              if (!matched)
2306                  return;
2307              // 允许上报
2308          }
2309          else {
2310              // 不在任何白名单且没有路径白名单,直接跳过
2311              return;
2312          }
2313      }
2314      // 构建监控信息
2315      const preMonitorInfo = buildMintor(type, name, params, metadata, immediately);
2316      /** 数据脱敏 */
2317      const monitorInfo = type !== exports.ReportTypeEnum.PERFORMANCE
2318          ? sensitive(preMonitorInfo)
2319          : preMonitorInfo;
2320      if (immediately) {
2321          // 立刻上报
2322          postQueue([monitorInfo]);
2323      }
2324      else {
2325          reportQueue.push(monitorInfo);
2326          scheduleFlush();
2327      }
2328  }
2329  /**
2330   * 在初始化后检查上报列表
2331   * 例如 web - vitals 在初始化之前就开始积攒上报数据了,所以这里需要在初始化后进行一次检查
2332   * */
2333  function initBeforeQueue() {
2334      const monitorInitData = getMonitorInitData();
2335      const { initialized } = monitorInitData || {};
2336      if (!initialized)
2337          return;
2338      reportQueue === null || reportQueue === void 0 ? void 0 : reportQueue.forEach((item) => {
2339          // 进行上报检查
2340          item.projectName = monitorInitData === null || monitorInitData === void 0 ? void 0 : monitorInitData.projectName;
2341          item.env = monitorInitData === null || monitorInitData === void 0 ? void 0 : monitorInitData.env;
2342      });
2343  }
2344  /** 立刻上报 */
2345  function flushImmediateReports() {
2346      /** 没有初始化不能上报 */
2347      const oControl = getOriginalConsole();
2348      if (oControl) {
2349          oControl === null || oControl === void 0 ? void 0 : oControl.warn("[Mint] Immediate flush triggered");
2350      }
2351      stopSchedule();
2352      flush(true);
2353  }
2354  /** 停止上报调度 */
2355  function stopSchedule() {
2356      if (scheduleId) {
2357          clearInterval(scheduleId);
2358      }
2359      scheduleId = null;
2360  }
2361  var report$1 = {
2362      initBeforeQueue,
2363  };
2364
2365  const reportWebSocketPerformance = socket.reportWebSocketPerformance;
2366  const reportWebSocketReconnect = socket.reportWebSocketReconnect;
2367  function reportEvent(name, prams = {}, metadata = {}, immediate = false) {
2368      report(exports.ReportTypeEnum.EVENT, name, prams, metadata, immediate);
2369  }
2370  // 自动同步白名单配置
2371  writeList.onSync();
2372
2373  exports.initMonitor = initMonitor;
2374  exports.report = report;
2375  exports.reportEvent = reportEvent;
2376  exports.reportWebSocketPerformance = reportWebSocketPerformance;
2377  exports.reportWebSocketReconnect = reportWebSocketReconnect;
2378
2379  Object.defineProperty(exports, '__esModule', { value: true });
2380
2381}));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.