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.esm.js CHANGED
@@ -274,13 +274,22 @@ class Sender {
274
274
  * 策略:优先使用 sendBeacon(更可靠),不支持或失败时降级为 fetch
275
275
  */
276
276
  doSend(data) {
277
+ // 检查配置是否已初始化
278
+ if (!config.isInitialized()) {
279
+ // 配置未初始化,数据放回缓冲区等待下次发送
280
+ this.buffer.unshift(...data);
281
+ this.scheduleFlush();
282
+ return;
283
+ }
277
284
  const cfg = config.get();
278
285
  const dsn = cfg.dsn;
279
- // dsn 未配置,跳过发送
286
+ // dsn 未配置,将数据放回缓冲区等待下次发送
280
287
  if (!dsn) {
281
288
  if (cfg.debug) {
282
- console.warn('[Monitor] dsn not configured, skip sending');
289
+ console.warn('[Monitor] dsn not configured, buffering data for later');
283
290
  }
291
+ this.buffer.unshift(...data);
292
+ this.scheduleFlush();
284
293
  return;
285
294
  }
286
295
  const payload = JSON.stringify(data);
@@ -401,25 +410,83 @@ class Reporter {
401
410
  }
402
411
  }
403
412
  /**
404
- * 发送早期缓存的数据
413
+ * 发送早期缓存的数据(根据最新配置过滤)
405
414
  */
406
415
  flushEarlyBuffer() {
416
+ const cfg = config.get();
417
+ let skippedCount = 0;
418
+ // 全局开关检查:如果 enabled 为 false,清空缓存不上报
419
+ if (cfg.enabled === false) {
420
+ const totalCount = this.earlyBuffer.length;
421
+ this.earlyBuffer = [];
422
+ if (cfg.debug) {
423
+ console.log(`[Monitor] SDK disabled, discarded ${totalCount} early buffered items`);
424
+ }
425
+ return;
426
+ }
407
427
  while (this.earlyBuffer.length > 0) {
408
428
  const item = this.earlyBuffer.shift();
409
429
  if (!item)
410
430
  continue;
431
+ // 根据最新配置过滤数据
411
432
  switch (item.type) {
412
433
  case 'error':
434
+ // 检查错误监控是否启用
435
+ if (cfg.error?.enabled === false) {
436
+ skippedCount++;
437
+ continue;
438
+ }
439
+ // 根据错误类型检查具体开关
440
+ const errorType = item.data?.type;
441
+ if (errorType === 'js_error' && cfg.error?.jsError === false) {
442
+ skippedCount++;
443
+ continue;
444
+ }
445
+ if (errorType === 'promise_error' && cfg.error?.promiseError === false) {
446
+ skippedCount++;
447
+ continue;
448
+ }
449
+ if (errorType === 'resource_error' && cfg.error?.resourceError === false) {
450
+ skippedCount++;
451
+ continue;
452
+ }
453
+ if (errorType === 'http_error' && cfg.error?.httpError === false) {
454
+ skippedCount++;
455
+ continue;
456
+ }
413
457
  this.reportError(item.data);
414
458
  break;
415
459
  case 'performance':
460
+ // 检查性能监控是否启用
461
+ if (cfg.performance?.enabled === false) {
462
+ skippedCount++;
463
+ continue;
464
+ }
416
465
  this.reportPerformance(item.data);
417
466
  break;
418
467
  case 'behavior':
468
+ // 检查行为监控是否启用
469
+ if (cfg.behavior?.enabled === false) {
470
+ skippedCount++;
471
+ continue;
472
+ }
473
+ // 根据行为类型检查具体开关
474
+ const action = item.data?.action;
475
+ if (action === 'pv' && cfg.behavior?.pv === false) {
476
+ skippedCount++;
477
+ continue;
478
+ }
479
+ if (action === 'route' && cfg.behavior?.route === false) {
480
+ skippedCount++;
481
+ continue;
482
+ }
419
483
  this.reportBehavior(item.data);
420
484
  break;
421
485
  }
422
486
  }
487
+ if (skippedCount > 0 && cfg.debug) {
488
+ console.log(`[Monitor] Filtered out ${skippedCount} early buffered items based on config`);
489
+ }
423
490
  }
424
491
  /**
425
492
  * 缓存早期数据
@@ -547,15 +614,16 @@ const reporter = new Reporter();
547
614
  * 安装 JS 错误监听
548
615
  */
549
616
  function installJsErrorHandler() {
550
- const cfg = config.get();
551
- if (!cfg.error?.enabled || !cfg.error?.jsError) {
552
- return;
553
- }
554
617
  window.addEventListener('error', (event) => {
555
618
  // 过滤资源加载错误(由 resourceError 处理)
556
619
  if (event.target !== window) {
557
620
  return;
558
621
  }
622
+ // 检查配置(在事件触发时检查,而不是安装时)
623
+ const cfg = config.isInitialized() ? config.get() : null;
624
+ if (cfg?.error?.enabled === false || cfg?.error?.jsError === false) {
625
+ return;
626
+ }
559
627
  const errorData = {
560
628
  type: 'js_error',
561
629
  message: event.message || 'Unknown error',
@@ -576,9 +644,7 @@ function installJsErrorHandler() {
576
644
  });
577
645
  reporter.reportError(errorData);
578
646
  }, true);
579
- if (cfg.debug) {
580
- console.log('[Monitor] JS error handler installed');
581
- }
647
+ console.log('[Monitor] JS error handler installed');
582
648
  }
583
649
 
584
650
  /**
@@ -588,11 +654,12 @@ function installJsErrorHandler() {
588
654
  * 安装 Promise 错误监听
589
655
  */
590
656
  function installPromiseErrorHandler() {
591
- const cfg = config.get();
592
- if (!cfg.error?.enabled || !cfg.error?.promiseError) {
593
- return;
594
- }
595
657
  window.addEventListener('unhandledrejection', (event) => {
658
+ // 检查配置(在事件触发时检查,而不是安装时)
659
+ const cfg = config.isInitialized() ? config.get() : null;
660
+ if (cfg?.error?.enabled === false || cfg?.error?.promiseError === false) {
661
+ return;
662
+ }
596
663
  let message = 'Unhandled Promise rejection';
597
664
  let stack;
598
665
  const reason = event.reason;
@@ -621,9 +688,7 @@ function installPromiseErrorHandler() {
621
688
  });
622
689
  reporter.reportError(errorData);
623
690
  });
624
- if (cfg.debug) {
625
- console.log('[Monitor] Promise error handler installed');
626
- }
691
+ console.log('[Monitor] Promise error handler installed');
627
692
  }
628
693
 
629
694
  /**
@@ -633,16 +698,17 @@ function installPromiseErrorHandler() {
633
698
  * 安装资源错误监听
634
699
  */
635
700
  function installResourceErrorHandler() {
636
- const cfg = config.get();
637
- if (!cfg.error?.enabled || !cfg.error?.resourceError) {
638
- return;
639
- }
640
701
  window.addEventListener('error', (event) => {
641
702
  const target = event.target;
642
703
  // 只处理资源加载错误(target 不是 window)
643
704
  if (!target || target === window || !(target instanceof HTMLElement)) {
644
705
  return;
645
706
  }
707
+ // 检查配置(在事件触发时检查,而不是安装时)
708
+ const cfg = config.isInitialized() ? config.get() : null;
709
+ if (cfg?.error?.enabled === false || cfg?.error?.resourceError === false) {
710
+ return;
711
+ }
646
712
  const tagName = target.tagName.toLowerCase();
647
713
  // 只监控特定标签的资源
648
714
  if (!['img', 'script', 'link', 'video', 'audio', 'source'].includes(tagName)) {
@@ -671,9 +737,7 @@ function installResourceErrorHandler() {
671
737
  });
672
738
  reporter.reportError(errorData);
673
739
  }, true); // 使用捕获阶段
674
- if (cfg.debug) {
675
- console.log('[Monitor] Resource error handler installed');
676
- }
740
+ console.log('[Monitor] Resource error handler installed');
677
741
  }
678
742
 
679
743
  /**
@@ -688,23 +752,16 @@ const originalFetch = window.fetch;
688
752
  * 安装 HTTP 错误拦截
689
753
  */
690
754
  function installHttpErrorHandler() {
691
- const cfg = config.get();
692
- if (!cfg.error?.enabled || !cfg.error?.httpError) {
693
- return;
694
- }
695
755
  interceptXHR();
696
756
  interceptFetch();
697
- if (cfg.debug) {
698
- console.log('[Monitor] HTTP error handler installed');
699
- }
757
+ console.log('[Monitor] HTTP error handler installed');
700
758
  }
701
- /**
702
- * 拦截 XMLHttpRequest
703
- */
704
759
  /**
705
760
  * 检查是否是 SDK 自身的请求
706
761
  */
707
762
  function isSdkRequest(url) {
763
+ if (!config.isInitialized())
764
+ return false;
708
765
  const cfg = config.get();
709
766
  if (!cfg.dsn)
710
767
  return false;
@@ -874,10 +931,6 @@ function reportHttpError(httpInfo) {
874
931
  reporter.reportError(errorData);
875
932
  }
876
933
 
877
- /**
878
- * 白屏检测插件
879
- * 使用 DOM 采样检测页面是否白屏
880
- */
881
934
  // 采样点 - 页面关键区域
882
935
  const SAMPLE_POINTS = [
883
936
  { x: 0.5, y: 0.1 }, // 顶部中间
@@ -892,10 +945,6 @@ const INVALID_ELEMENTS = ['html', 'body', 'head', 'meta', 'link', 'style', 'scri
892
945
  * 安装白屏检测
893
946
  */
894
947
  function installWhiteScreenDetector() {
895
- const cfg = config.get();
896
- if (!cfg.error?.enabled) {
897
- return;
898
- }
899
948
  // 在页面加载完成后检测
900
949
  if (document.readyState === 'complete') {
901
950
  scheduleDetection();
@@ -905,9 +954,7 @@ function installWhiteScreenDetector() {
905
954
  scheduleDetection();
906
955
  });
907
956
  }
908
- if (cfg.debug) {
909
- console.log('[Monitor] White screen detector installed');
910
- }
957
+ console.log('[Monitor] White screen detector installed');
911
958
  }
912
959
  /**
913
960
  * 调度检测(延迟执行,给页面渲染时间)
@@ -979,10 +1026,6 @@ function installErrorHandlers() {
979
1026
  * 安装 Web Vitals 采集
980
1027
  */
981
1028
  function installWebVitals() {
982
- const cfg = config.get();
983
- if (!cfg.performance?.enabled || !cfg.performance?.webVitals) {
984
- return;
985
- }
986
1029
  // 页面加载完成后采集
987
1030
  if (document.readyState === 'complete') {
988
1031
  collectMetrics();
@@ -993,14 +1036,17 @@ function installWebVitals() {
993
1036
  setTimeout(collectMetrics, 3000);
994
1037
  });
995
1038
  }
996
- if (cfg.debug) {
997
- console.log('[Monitor] Web Vitals collector installed');
998
- }
1039
+ console.log('[Monitor] Web Vitals collector installed');
999
1040
  }
1000
1041
  /**
1001
1042
  * 采集性能指标
1002
1043
  */
1003
1044
  function collectMetrics() {
1045
+ // 检查配置(在采集时检查,而不是安装时)
1046
+ const cfg = config.isInitialized() ? config.get() : null;
1047
+ if (cfg?.performance?.enabled === false || cfg?.performance?.webVitals === false) {
1048
+ return;
1049
+ }
1004
1050
  const metrics = {};
1005
1051
  // 使用 Performance API
1006
1052
  if (!window.performance) {
@@ -1109,22 +1155,13 @@ function installPerformanceMonitor() {
1109
1155
  installWebVitals();
1110
1156
  }
1111
1157
 
1112
- /**
1113
- * PV (Page View) 统计插件
1114
- */
1115
1158
  /**
1116
1159
  * 安装 PV 统计
1117
1160
  */
1118
1161
  function installPVTracker() {
1119
- const cfg = config.get();
1120
- if (!cfg.behavior?.enabled || !cfg.behavior?.pv) {
1121
- return;
1122
- }
1123
- // 页面加载时上报
1162
+ // 页面加载时上报(reporter 会缓存直到 SDK 就绪)
1124
1163
  reportPV();
1125
- if (cfg.debug) {
1126
- console.log('[Monitor] PV tracker installed');
1127
- }
1164
+ console.log('[Monitor] PV tracker installed');
1128
1165
  }
1129
1166
  /**
1130
1167
  * 上报 PV
@@ -1147,11 +1184,12 @@ function reportPV() {
1147
1184
  * 安装点击追踪
1148
1185
  */
1149
1186
  function installClickTracker() {
1150
- const cfg = config.get();
1151
- if (!cfg.behavior?.enabled || !cfg.behavior?.click) {
1152
- return;
1153
- }
1154
1187
  document.addEventListener('click', (event) => {
1188
+ // 检查配置(在事件触发时检查,而不是安装时)
1189
+ const cfg = config.isInitialized() ? config.get() : null;
1190
+ if (cfg?.behavior?.enabled === false || cfg?.behavior?.click === false) {
1191
+ return;
1192
+ }
1155
1193
  const target = event.target;
1156
1194
  if (!target)
1157
1195
  return;
@@ -1169,9 +1207,7 @@ function installClickTracker() {
1169
1207
  // data: clickData,
1170
1208
  // });
1171
1209
  }, true);
1172
- if (cfg.debug) {
1173
- console.log('[Monitor] Click tracker installed');
1174
- }
1210
+ console.log('[Monitor] Click tracker installed');
1175
1211
  }
1176
1212
  /**
1177
1213
  * 提取点击数据
@@ -1250,10 +1286,6 @@ const originalReplaceState = history.replaceState;
1250
1286
  * 安装路由监控
1251
1287
  */
1252
1288
  function installRouteTracker() {
1253
- const cfg = config.get();
1254
- if (!cfg.behavior?.enabled || !cfg.behavior?.route) {
1255
- return;
1256
- }
1257
1289
  // 拦截 pushState
1258
1290
  history.pushState = function (...args) {
1259
1291
  const result = originalPushState.apply(this, args);
@@ -1274,14 +1306,17 @@ function installRouteTracker() {
1274
1306
  window.addEventListener('hashchange', () => {
1275
1307
  handleRouteChange('hashchange');
1276
1308
  });
1277
- if (cfg.debug) {
1278
- console.log('[Monitor] Route tracker installed');
1279
- }
1309
+ console.log('[Monitor] Route tracker installed');
1280
1310
  }
1281
1311
  /**
1282
1312
  * 处理路由变化
1283
1313
  */
1284
1314
  function handleRouteChange(trigger) {
1315
+ // 检查配置(在事件触发时检查,而不是安装时)
1316
+ const cfg = config.isInitialized() ? config.get() : null;
1317
+ if (cfg?.behavior?.enabled === false || cfg?.behavior?.route === false) {
1318
+ return;
1319
+ }
1285
1320
  const routeData = {
1286
1321
  url: getPageUrl(),
1287
1322
  title: getPageTitle(),
@@ -1316,16 +1351,16 @@ const originalConsole = {
1316
1351
  * 安装控制台追踪
1317
1352
  */
1318
1353
  function installConsoleTracker() {
1319
- const cfg = config.get();
1320
- // 默认启用控制台追踪(跟随 behavior.enabled)
1321
- if (!cfg.behavior?.enabled) {
1322
- return;
1323
- }
1324
1354
  const levels = ['log', 'info', 'warn', 'error'];
1325
1355
  levels.forEach((level) => {
1326
1356
  console[level] = function (...args) {
1327
1357
  // 调用原始方法
1328
1358
  originalConsole[level].apply(console, args);
1359
+ // 检查配置(在调用时检查,而不是安装时)
1360
+ const cfg = config.isInitialized() ? config.get() : null;
1361
+ if (cfg?.behavior?.enabled === false) {
1362
+ return;
1363
+ }
1329
1364
  // 添加到面包屑(只记录 warn 和 error)
1330
1365
  if (level === 'warn' || level === 'error') {
1331
1366
  const message = formatConsoleArgs(args);
@@ -1340,9 +1375,7 @@ function installConsoleTracker() {
1340
1375
  }
1341
1376
  };
1342
1377
  });
1343
- if (cfg.debug) {
1344
- originalConsole.log('[Monitor] Console tracker installed');
1345
- }
1378
+ originalConsole.log('[Monitor] Console tracker installed');
1346
1379
  }
1347
1380
  /**
1348
1381
  * 格式化控制台参数
@@ -1374,24 +1407,22 @@ function formatConsoleArgs(args) {
1374
1407
  * 安装输入追踪
1375
1408
  */
1376
1409
  function installInputTracker() {
1377
- const cfg = config.get();
1378
- // 默认启用输入追踪(跟随 behavior.enabled)
1379
- if (!cfg.behavior?.enabled) {
1380
- return;
1381
- }
1382
1410
  // 监听 input 事件(使用 change 事件减少数据量)
1383
1411
  document.addEventListener('change', handleInputChange, true);
1384
1412
  // 监听焦点事件
1385
1413
  document.addEventListener('focus', handleFocus, true);
1386
1414
  document.addEventListener('blur', handleBlur, true);
1387
- if (cfg.debug) {
1388
- console.log('[Monitor] Input tracker installed');
1389
- }
1415
+ console.log('[Monitor] Input tracker installed');
1390
1416
  }
1391
1417
  /**
1392
1418
  * 处理输入变化
1393
1419
  */
1394
1420
  function handleInputChange(event) {
1421
+ // 检查配置(在事件触发时检查,而不是安装时)
1422
+ const cfg = config.isInitialized() ? config.get() : null;
1423
+ if (cfg?.behavior?.enabled === false) {
1424
+ return;
1425
+ }
1395
1426
  const target = event.target;
1396
1427
  if (!target || !isFormElement(target))
1397
1428
  return;
@@ -1406,6 +1437,11 @@ function handleInputChange(event) {
1406
1437
  * 处理焦点获取
1407
1438
  */
1408
1439
  function handleFocus(event) {
1440
+ // 检查配置
1441
+ const cfg = config.isInitialized() ? config.get() : null;
1442
+ if (cfg?.behavior?.enabled === false) {
1443
+ return;
1444
+ }
1409
1445
  const target = event.target;
1410
1446
  if (!target || !isFormElement(target))
1411
1447
  return;
@@ -1419,6 +1455,11 @@ function handleFocus(event) {
1419
1455
  * 处理焦点失去
1420
1456
  */
1421
1457
  function handleBlur(event) {
1458
+ // 检查配置
1459
+ const cfg = config.isInitialized() ? config.get() : null;
1460
+ if (cfg?.behavior?.enabled === false) {
1461
+ return;
1462
+ }
1422
1463
  const target = event.target;
1423
1464
  if (!target || !isFormElement(target))
1424
1465
  return;