sobey-monitor-sdk 1.1.3 → 1.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.js CHANGED
@@ -278,13 +278,22 @@ class Sender {
278
278
  * 策略:优先使用 sendBeacon(更可靠),不支持或失败时降级为 fetch
279
279
  */
280
280
  doSend(data) {
281
+ // 检查配置是否已初始化
282
+ if (!config.isInitialized()) {
283
+ // 配置未初始化,数据放回缓冲区等待下次发送
284
+ this.buffer.unshift(...data);
285
+ this.scheduleFlush();
286
+ return;
287
+ }
281
288
  const cfg = config.get();
282
289
  const dsn = cfg.dsn;
283
- // dsn 未配置,跳过发送
290
+ // dsn 未配置,将数据放回缓冲区等待下次发送
284
291
  if (!dsn) {
285
292
  if (cfg.debug) {
286
- console.warn('[Monitor] dsn not configured, skip sending');
293
+ console.warn('[Monitor] dsn not configured, buffering data for later');
287
294
  }
295
+ this.buffer.unshift(...data);
296
+ this.scheduleFlush();
288
297
  return;
289
298
  }
290
299
  const payload = JSON.stringify(data);
@@ -405,25 +414,83 @@ class Reporter {
405
414
  }
406
415
  }
407
416
  /**
408
- * 发送早期缓存的数据
417
+ * 发送早期缓存的数据(根据最新配置过滤)
409
418
  */
410
419
  flushEarlyBuffer() {
420
+ const cfg = config.get();
421
+ let skippedCount = 0;
422
+ // 全局开关检查:如果 enabled 为 false,清空缓存不上报
423
+ if (cfg.enabled === false) {
424
+ const totalCount = this.earlyBuffer.length;
425
+ this.earlyBuffer = [];
426
+ if (cfg.debug) {
427
+ console.log(`[Monitor] SDK disabled, discarded ${totalCount} early buffered items`);
428
+ }
429
+ return;
430
+ }
411
431
  while (this.earlyBuffer.length > 0) {
412
432
  const item = this.earlyBuffer.shift();
413
433
  if (!item)
414
434
  continue;
435
+ // 根据最新配置过滤数据
415
436
  switch (item.type) {
416
437
  case 'error':
438
+ // 检查错误监控是否启用
439
+ if (cfg.error?.enabled === false) {
440
+ skippedCount++;
441
+ continue;
442
+ }
443
+ // 根据错误类型检查具体开关
444
+ const errorType = item.data?.type;
445
+ if (errorType === 'js_error' && cfg.error?.jsError === false) {
446
+ skippedCount++;
447
+ continue;
448
+ }
449
+ if (errorType === 'promise_error' && cfg.error?.promiseError === false) {
450
+ skippedCount++;
451
+ continue;
452
+ }
453
+ if (errorType === 'resource_error' && cfg.error?.resourceError === false) {
454
+ skippedCount++;
455
+ continue;
456
+ }
457
+ if (errorType === 'http_error' && cfg.error?.httpError === false) {
458
+ skippedCount++;
459
+ continue;
460
+ }
417
461
  this.reportError(item.data);
418
462
  break;
419
463
  case 'performance':
464
+ // 检查性能监控是否启用
465
+ if (cfg.performance?.enabled === false) {
466
+ skippedCount++;
467
+ continue;
468
+ }
420
469
  this.reportPerformance(item.data);
421
470
  break;
422
471
  case 'behavior':
472
+ // 检查行为监控是否启用
473
+ if (cfg.behavior?.enabled === false) {
474
+ skippedCount++;
475
+ continue;
476
+ }
477
+ // 根据行为类型检查具体开关
478
+ const action = item.data?.action;
479
+ if (action === 'pv' && cfg.behavior?.pv === false) {
480
+ skippedCount++;
481
+ continue;
482
+ }
483
+ if (action === 'route' && cfg.behavior?.route === false) {
484
+ skippedCount++;
485
+ continue;
486
+ }
423
487
  this.reportBehavior(item.data);
424
488
  break;
425
489
  }
426
490
  }
491
+ if (skippedCount > 0 && cfg.debug) {
492
+ console.log(`[Monitor] Filtered out ${skippedCount} early buffered items based on config`);
493
+ }
427
494
  }
428
495
  /**
429
496
  * 缓存早期数据
@@ -551,15 +618,16 @@ const reporter = new Reporter();
551
618
  * 安装 JS 错误监听
552
619
  */
553
620
  function installJsErrorHandler() {
554
- const cfg = config.get();
555
- if (!cfg.error?.enabled || !cfg.error?.jsError) {
556
- return;
557
- }
558
621
  window.addEventListener('error', (event) => {
559
622
  // 过滤资源加载错误(由 resourceError 处理)
560
623
  if (event.target !== window) {
561
624
  return;
562
625
  }
626
+ // 检查配置(在事件触发时检查,而不是安装时)
627
+ const cfg = config.isInitialized() ? config.get() : null;
628
+ if (cfg?.error?.enabled === false || cfg?.error?.jsError === false) {
629
+ return;
630
+ }
563
631
  const errorData = {
564
632
  type: 'js_error',
565
633
  message: event.message || 'Unknown error',
@@ -580,9 +648,7 @@ function installJsErrorHandler() {
580
648
  });
581
649
  reporter.reportError(errorData);
582
650
  }, true);
583
- if (cfg.debug) {
584
- console.log('[Monitor] JS error handler installed');
585
- }
651
+ console.log('[Monitor] JS error handler installed');
586
652
  }
587
653
 
588
654
  /**
@@ -592,11 +658,12 @@ function installJsErrorHandler() {
592
658
  * 安装 Promise 错误监听
593
659
  */
594
660
  function installPromiseErrorHandler() {
595
- const cfg = config.get();
596
- if (!cfg.error?.enabled || !cfg.error?.promiseError) {
597
- return;
598
- }
599
661
  window.addEventListener('unhandledrejection', (event) => {
662
+ // 检查配置(在事件触发时检查,而不是安装时)
663
+ const cfg = config.isInitialized() ? config.get() : null;
664
+ if (cfg?.error?.enabled === false || cfg?.error?.promiseError === false) {
665
+ return;
666
+ }
600
667
  let message = 'Unhandled Promise rejection';
601
668
  let stack;
602
669
  const reason = event.reason;
@@ -625,9 +692,7 @@ function installPromiseErrorHandler() {
625
692
  });
626
693
  reporter.reportError(errorData);
627
694
  });
628
- if (cfg.debug) {
629
- console.log('[Monitor] Promise error handler installed');
630
- }
695
+ console.log('[Monitor] Promise error handler installed');
631
696
  }
632
697
 
633
698
  /**
@@ -637,16 +702,17 @@ function installPromiseErrorHandler() {
637
702
  * 安装资源错误监听
638
703
  */
639
704
  function installResourceErrorHandler() {
640
- const cfg = config.get();
641
- if (!cfg.error?.enabled || !cfg.error?.resourceError) {
642
- return;
643
- }
644
705
  window.addEventListener('error', (event) => {
645
706
  const target = event.target;
646
707
  // 只处理资源加载错误(target 不是 window)
647
708
  if (!target || target === window || !(target instanceof HTMLElement)) {
648
709
  return;
649
710
  }
711
+ // 检查配置(在事件触发时检查,而不是安装时)
712
+ const cfg = config.isInitialized() ? config.get() : null;
713
+ if (cfg?.error?.enabled === false || cfg?.error?.resourceError === false) {
714
+ return;
715
+ }
650
716
  const tagName = target.tagName.toLowerCase();
651
717
  // 只监控特定标签的资源
652
718
  if (!['img', 'script', 'link', 'video', 'audio', 'source'].includes(tagName)) {
@@ -675,9 +741,7 @@ function installResourceErrorHandler() {
675
741
  });
676
742
  reporter.reportError(errorData);
677
743
  }, true); // 使用捕获阶段
678
- if (cfg.debug) {
679
- console.log('[Monitor] Resource error handler installed');
680
- }
744
+ console.log('[Monitor] Resource error handler installed');
681
745
  }
682
746
 
683
747
  /**
@@ -692,23 +756,16 @@ const originalFetch = window.fetch;
692
756
  * 安装 HTTP 错误拦截
693
757
  */
694
758
  function installHttpErrorHandler() {
695
- const cfg = config.get();
696
- if (!cfg.error?.enabled || !cfg.error?.httpError) {
697
- return;
698
- }
699
759
  interceptXHR();
700
760
  interceptFetch();
701
- if (cfg.debug) {
702
- console.log('[Monitor] HTTP error handler installed');
703
- }
761
+ console.log('[Monitor] HTTP error handler installed');
704
762
  }
705
- /**
706
- * 拦截 XMLHttpRequest
707
- */
708
763
  /**
709
764
  * 检查是否是 SDK 自身的请求
710
765
  */
711
766
  function isSdkRequest(url) {
767
+ if (!config.isInitialized())
768
+ return false;
712
769
  const cfg = config.get();
713
770
  if (!cfg.dsn)
714
771
  return false;
@@ -878,10 +935,6 @@ function reportHttpError(httpInfo) {
878
935
  reporter.reportError(errorData);
879
936
  }
880
937
 
881
- /**
882
- * 白屏检测插件
883
- * 使用 DOM 采样检测页面是否白屏
884
- */
885
938
  // 采样点 - 页面关键区域
886
939
  const SAMPLE_POINTS = [
887
940
  { x: 0.5, y: 0.1 }, // 顶部中间
@@ -896,10 +949,6 @@ const INVALID_ELEMENTS = ['html', 'body', 'head', 'meta', 'link', 'style', 'scri
896
949
  * 安装白屏检测
897
950
  */
898
951
  function installWhiteScreenDetector() {
899
- const cfg = config.get();
900
- if (!cfg.error?.enabled) {
901
- return;
902
- }
903
952
  // 在页面加载完成后检测
904
953
  if (document.readyState === 'complete') {
905
954
  scheduleDetection();
@@ -909,9 +958,7 @@ function installWhiteScreenDetector() {
909
958
  scheduleDetection();
910
959
  });
911
960
  }
912
- if (cfg.debug) {
913
- console.log('[Monitor] White screen detector installed');
914
- }
961
+ console.log('[Monitor] White screen detector installed');
915
962
  }
916
963
  /**
917
964
  * 调度检测(延迟执行,给页面渲染时间)
@@ -983,10 +1030,6 @@ function installErrorHandlers() {
983
1030
  * 安装 Web Vitals 采集
984
1031
  */
985
1032
  function installWebVitals() {
986
- const cfg = config.get();
987
- if (!cfg.performance?.enabled || !cfg.performance?.webVitals) {
988
- return;
989
- }
990
1033
  // 页面加载完成后采集
991
1034
  if (document.readyState === 'complete') {
992
1035
  collectMetrics();
@@ -997,14 +1040,17 @@ function installWebVitals() {
997
1040
  setTimeout(collectMetrics, 3000);
998
1041
  });
999
1042
  }
1000
- if (cfg.debug) {
1001
- console.log('[Monitor] Web Vitals collector installed');
1002
- }
1043
+ console.log('[Monitor] Web Vitals collector installed');
1003
1044
  }
1004
1045
  /**
1005
1046
  * 采集性能指标
1006
1047
  */
1007
1048
  function collectMetrics() {
1049
+ // 检查配置(在采集时检查,而不是安装时)
1050
+ const cfg = config.isInitialized() ? config.get() : null;
1051
+ if (cfg?.performance?.enabled === false || cfg?.performance?.webVitals === false) {
1052
+ return;
1053
+ }
1008
1054
  const metrics = {};
1009
1055
  // 使用 Performance API
1010
1056
  if (!window.performance) {
@@ -1113,22 +1159,13 @@ function installPerformanceMonitor() {
1113
1159
  installWebVitals();
1114
1160
  }
1115
1161
 
1116
- /**
1117
- * PV (Page View) 统计插件
1118
- */
1119
1162
  /**
1120
1163
  * 安装 PV 统计
1121
1164
  */
1122
1165
  function installPVTracker() {
1123
- const cfg = config.get();
1124
- if (!cfg.behavior?.enabled || !cfg.behavior?.pv) {
1125
- return;
1126
- }
1127
- // 页面加载时上报
1166
+ // 页面加载时上报(reporter 会缓存直到 SDK 就绪)
1128
1167
  reportPV();
1129
- if (cfg.debug) {
1130
- console.log('[Monitor] PV tracker installed');
1131
- }
1168
+ console.log('[Monitor] PV tracker installed');
1132
1169
  }
1133
1170
  /**
1134
1171
  * 上报 PV
@@ -1151,11 +1188,12 @@ function reportPV() {
1151
1188
  * 安装点击追踪
1152
1189
  */
1153
1190
  function installClickTracker() {
1154
- const cfg = config.get();
1155
- if (!cfg.behavior?.enabled || !cfg.behavior?.click) {
1156
- return;
1157
- }
1158
1191
  document.addEventListener('click', (event) => {
1192
+ // 检查配置(在事件触发时检查,而不是安装时)
1193
+ const cfg = config.isInitialized() ? config.get() : null;
1194
+ if (cfg?.behavior?.enabled === false || cfg?.behavior?.click === false) {
1195
+ return;
1196
+ }
1159
1197
  const target = event.target;
1160
1198
  if (!target)
1161
1199
  return;
@@ -1173,9 +1211,7 @@ function installClickTracker() {
1173
1211
  // data: clickData,
1174
1212
  // });
1175
1213
  }, true);
1176
- if (cfg.debug) {
1177
- console.log('[Monitor] Click tracker installed');
1178
- }
1214
+ console.log('[Monitor] Click tracker installed');
1179
1215
  }
1180
1216
  /**
1181
1217
  * 提取点击数据
@@ -1254,10 +1290,6 @@ const originalReplaceState = history.replaceState;
1254
1290
  * 安装路由监控
1255
1291
  */
1256
1292
  function installRouteTracker() {
1257
- const cfg = config.get();
1258
- if (!cfg.behavior?.enabled || !cfg.behavior?.route) {
1259
- return;
1260
- }
1261
1293
  // 拦截 pushState
1262
1294
  history.pushState = function (...args) {
1263
1295
  const result = originalPushState.apply(this, args);
@@ -1278,14 +1310,17 @@ function installRouteTracker() {
1278
1310
  window.addEventListener('hashchange', () => {
1279
1311
  handleRouteChange('hashchange');
1280
1312
  });
1281
- if (cfg.debug) {
1282
- console.log('[Monitor] Route tracker installed');
1283
- }
1313
+ console.log('[Monitor] Route tracker installed');
1284
1314
  }
1285
1315
  /**
1286
1316
  * 处理路由变化
1287
1317
  */
1288
1318
  function handleRouteChange(trigger) {
1319
+ // 检查配置(在事件触发时检查,而不是安装时)
1320
+ const cfg = config.isInitialized() ? config.get() : null;
1321
+ if (cfg?.behavior?.enabled === false || cfg?.behavior?.route === false) {
1322
+ return;
1323
+ }
1289
1324
  const routeData = {
1290
1325
  url: getPageUrl(),
1291
1326
  title: getPageTitle(),
@@ -1320,16 +1355,16 @@ const originalConsole = {
1320
1355
  * 安装控制台追踪
1321
1356
  */
1322
1357
  function installConsoleTracker() {
1323
- const cfg = config.get();
1324
- // 默认启用控制台追踪(跟随 behavior.enabled)
1325
- if (!cfg.behavior?.enabled) {
1326
- return;
1327
- }
1328
1358
  const levels = ['log', 'info', 'warn', 'error'];
1329
1359
  levels.forEach((level) => {
1330
1360
  console[level] = function (...args) {
1331
1361
  // 调用原始方法
1332
1362
  originalConsole[level].apply(console, args);
1363
+ // 检查配置(在调用时检查,而不是安装时)
1364
+ const cfg = config.isInitialized() ? config.get() : null;
1365
+ if (cfg?.behavior?.enabled === false) {
1366
+ return;
1367
+ }
1333
1368
  // 添加到面包屑(只记录 warn 和 error)
1334
1369
  if (level === 'warn' || level === 'error') {
1335
1370
  const message = formatConsoleArgs(args);
@@ -1344,9 +1379,7 @@ function installConsoleTracker() {
1344
1379
  }
1345
1380
  };
1346
1381
  });
1347
- if (cfg.debug) {
1348
- originalConsole.log('[Monitor] Console tracker installed');
1349
- }
1382
+ originalConsole.log('[Monitor] Console tracker installed');
1350
1383
  }
1351
1384
  /**
1352
1385
  * 格式化控制台参数
@@ -1378,24 +1411,22 @@ function formatConsoleArgs(args) {
1378
1411
  * 安装输入追踪
1379
1412
  */
1380
1413
  function installInputTracker() {
1381
- const cfg = config.get();
1382
- // 默认启用输入追踪(跟随 behavior.enabled)
1383
- if (!cfg.behavior?.enabled) {
1384
- return;
1385
- }
1386
1414
  // 监听 input 事件(使用 change 事件减少数据量)
1387
1415
  document.addEventListener('change', handleInputChange, true);
1388
1416
  // 监听焦点事件
1389
1417
  document.addEventListener('focus', handleFocus, true);
1390
1418
  document.addEventListener('blur', handleBlur, true);
1391
- if (cfg.debug) {
1392
- console.log('[Monitor] Input tracker installed');
1393
- }
1419
+ console.log('[Monitor] Input tracker installed');
1394
1420
  }
1395
1421
  /**
1396
1422
  * 处理输入变化
1397
1423
  */
1398
1424
  function handleInputChange(event) {
1425
+ // 检查配置(在事件触发时检查,而不是安装时)
1426
+ const cfg = config.isInitialized() ? config.get() : null;
1427
+ if (cfg?.behavior?.enabled === false) {
1428
+ return;
1429
+ }
1399
1430
  const target = event.target;
1400
1431
  if (!target || !isFormElement(target))
1401
1432
  return;
@@ -1410,6 +1441,11 @@ function handleInputChange(event) {
1410
1441
  * 处理焦点获取
1411
1442
  */
1412
1443
  function handleFocus(event) {
1444
+ // 检查配置
1445
+ const cfg = config.isInitialized() ? config.get() : null;
1446
+ if (cfg?.behavior?.enabled === false) {
1447
+ return;
1448
+ }
1413
1449
  const target = event.target;
1414
1450
  if (!target || !isFormElement(target))
1415
1451
  return;
@@ -1423,6 +1459,11 @@ function handleFocus(event) {
1423
1459
  * 处理焦点失去
1424
1460
  */
1425
1461
  function handleBlur(event) {
1462
+ // 检查配置
1463
+ const cfg = config.isInitialized() ? config.get() : null;
1464
+ if (cfg?.behavior?.enabled === false) {
1465
+ return;
1466
+ }
1426
1467
  const target = event.target;
1427
1468
  if (!target || !isFormElement(target))
1428
1469
  return;