@tracelog/lib 2.0.3 → 2.1.0

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.
@@ -265,12 +265,6 @@ var init_event_types = __esm({
265
265
  }
266
266
  });
267
267
 
268
- // src/types/log.types.ts
269
- var init_log_types = __esm({
270
- "src/types/log.types.ts"() {
271
- }
272
- });
273
-
274
268
  // src/types/mode.types.ts
275
269
  var Mode;
276
270
  var init_mode_types = __esm({
@@ -385,7 +379,6 @@ var init_types = __esm({
385
379
  init_emitter_types();
386
380
  init_error_types();
387
381
  init_event_types();
388
- init_log_types();
389
382
  init_mode_types();
390
383
  init_queue_types();
391
384
  init_scroll_types();
@@ -398,10 +391,22 @@ var init_types = __esm({
398
391
  }
399
392
  });
400
393
 
394
+ // src/constants/app.constants.ts
395
+ var LOG_STYLE_ACTIVE, LOG_STYLE_DISABLED, LOG_STYLE_CRITICAL;
396
+ var init_app_constants = __esm({
397
+ "src/constants/app.constants.ts"() {
398
+ LOG_STYLE_ACTIVE = "background: #ff9800; color: white; font-weight: bold; padding: 2px 8px; border-radius: 3px;";
399
+ LOG_STYLE_DISABLED = "background: #9e9e9e; color: white; font-weight: bold; padding: 2px 8px; border-radius: 3px;";
400
+ LOG_STYLE_CRITICAL = "background: #d32f2f; color: white; font-weight: bold; padding: 2px 8px; border-radius: 3px;";
401
+ }
402
+ });
403
+
401
404
  // src/utils/logging.utils.ts
402
- var formatLogMsg, log, sanitizeLogData;
405
+ var formatLogMsg, isQaModeActive, log, shouldShowLog, getEffectiveStyle, outputLog, sanitizeLogData;
403
406
  var init_logging_utils = __esm({
404
407
  "src/utils/logging.utils.ts"() {
408
+ init_storage_constants();
409
+ init_app_constants();
405
410
  formatLogMsg = (msg, error) => {
406
411
  if (error) {
407
412
  if (process.env.NODE_ENV !== "development" && error instanceof Error) {
@@ -425,27 +430,59 @@ var init_logging_utils = __esm({
425
430
  }
426
431
  return `[TraceLog] ${msg}`;
427
432
  };
433
+ isQaModeActive = () => {
434
+ if (typeof window === "undefined" || typeof sessionStorage === "undefined") {
435
+ return false;
436
+ }
437
+ try {
438
+ return sessionStorage.getItem(QA_MODE_KEY) === "true";
439
+ } catch {
440
+ return false;
441
+ }
442
+ };
428
443
  log = (type, msg, extra) => {
429
- const { error, data, showToClient = false, style } = extra ?? {};
444
+ const { error, data, showToClient = false, style, visibility } = extra ?? {};
430
445
  const formattedMsg = error ? formatLogMsg(msg, error) : `[TraceLog] ${msg}`;
431
446
  const method = type === "error" ? "error" : type === "warn" ? "warn" : "log";
432
447
  const isProduction = process.env.NODE_ENV !== "development";
433
- if (isProduction) {
434
- if (type === "debug") {
435
- return;
436
- }
437
- if (type === "info" && !showToClient) {
438
- return;
439
- }
448
+ if (!isProduction) {
449
+ outputLog(method, formattedMsg, style, data);
450
+ return;
440
451
  }
452
+ const shouldShow = shouldShowLog(visibility, showToClient);
453
+ if (!shouldShow) {
454
+ return;
455
+ }
456
+ const effectiveStyle = getEffectiveStyle(visibility, style);
457
+ const sanitizedData = data !== void 0 ? sanitizeLogData(data) : void 0;
458
+ outputLog(method, formattedMsg, effectiveStyle, sanitizedData);
459
+ };
460
+ shouldShowLog = (visibility, showToClient) => {
461
+ if (visibility === "critical") {
462
+ return true;
463
+ }
464
+ if (visibility === "qa" || showToClient) {
465
+ return isQaModeActive();
466
+ }
467
+ return false;
468
+ };
469
+ getEffectiveStyle = (visibility, providedStyle) => {
470
+ if (providedStyle !== void 0 && providedStyle !== "") {
471
+ return providedStyle;
472
+ }
473
+ if (visibility === "critical") {
474
+ return LOG_STYLE_CRITICAL;
475
+ }
476
+ return "";
477
+ };
478
+ outputLog = (method, formattedMsg, style, data) => {
441
479
  const hasStyle = style !== void 0 && style !== "";
442
480
  const styledMsg = hasStyle ? `%c${formattedMsg}` : formattedMsg;
443
481
  if (data !== void 0) {
444
- const sanitizedData = isProduction ? sanitizeLogData(data) : data;
445
482
  if (hasStyle) {
446
- console[method](styledMsg, style, sanitizedData);
483
+ console[method](styledMsg, style, data);
447
484
  } else {
448
- console[method](styledMsg, sanitizedData);
485
+ console[method](styledMsg, data);
449
486
  }
450
487
  } else {
451
488
  if (hasStyle) {
@@ -480,7 +517,7 @@ var init_logging_utils = __esm({
480
517
  });
481
518
 
482
519
  // src/utils/browser/device-detector.utils.ts
483
- var coarsePointerQuery, noHoverQuery, initMediaQueries, getDeviceType;
520
+ var coarsePointerQuery, noHoverQuery, initMediaQueries, UNKNOWN, detectOS, detectBrowser, getDeviceType, getDeviceInfo;
484
521
  var init_device_detector_utils = __esm({
485
522
  "src/utils/browser/device-detector.utils.ts"() {
486
523
  init_device_types();
@@ -491,11 +528,53 @@ var init_device_detector_utils = __esm({
491
528
  noHoverQuery = window.matchMedia("(hover: none)");
492
529
  }
493
530
  };
531
+ UNKNOWN = "Unknown";
532
+ detectOS = (nav) => {
533
+ const platform = nav.userAgentData?.platform;
534
+ if (platform != null && platform !== "") {
535
+ if (/windows/i.test(platform)) return "Windows";
536
+ if (/macos/i.test(platform)) return "macOS";
537
+ if (/android/i.test(platform)) return "Android";
538
+ if (/linux/i.test(platform)) return "Linux";
539
+ if (/chromeos/i.test(platform)) return "ChromeOS";
540
+ if (/ios/i.test(platform)) return "iOS";
541
+ }
542
+ const ua = navigator.userAgent;
543
+ if (/Windows/i.test(ua)) return "Windows";
544
+ if (/iPhone|iPad|iPod/i.test(ua)) return "iOS";
545
+ if (/Mac OS X|Macintosh/i.test(ua)) return "macOS";
546
+ if (/Android/i.test(ua)) return "Android";
547
+ if (/CrOS/i.test(ua)) return "ChromeOS";
548
+ if (/Linux/i.test(ua)) return "Linux";
549
+ return UNKNOWN;
550
+ };
551
+ detectBrowser = (nav) => {
552
+ const brands = nav.userAgentData?.brands;
553
+ if (brands != null && brands.length > 0) {
554
+ const validBrands = brands.filter((b) => !/not.?a.?brand|chromium/i.test(b.brand));
555
+ const firstBrand = validBrands[0];
556
+ if (firstBrand != null) {
557
+ const brand = firstBrand.brand;
558
+ if (/google chrome/i.test(brand)) return "Chrome";
559
+ if (/microsoft edge/i.test(brand)) return "Edge";
560
+ if (/opera/i.test(brand)) return "Opera";
561
+ return brand;
562
+ }
563
+ }
564
+ const ua = navigator.userAgent;
565
+ if (/Edg\//i.test(ua)) return "Edge";
566
+ if (/OPR\//i.test(ua)) return "Opera";
567
+ if (/Chrome/i.test(ua)) return "Chrome";
568
+ if (/Firefox/i.test(ua)) return "Firefox";
569
+ if (/Safari/i.test(ua) && !/Chrome/i.test(ua)) return "Safari";
570
+ return UNKNOWN;
571
+ };
494
572
  getDeviceType = () => {
495
573
  try {
496
574
  const nav = navigator;
497
- if (nav.userAgentData && typeof nav.userAgentData.mobile === "boolean") {
498
- if (nav.userAgentData.platform && /ipad|tablet/i.test(nav.userAgentData.platform)) {
575
+ if (nav.userAgentData != null && typeof nav.userAgentData.mobile === "boolean") {
576
+ const uaPlatform = nav.userAgentData.platform;
577
+ if (uaPlatform != null && uaPlatform !== "" && /ipad|tablet/i.test(uaPlatform)) {
499
578
  return "tablet" /* Tablet */;
500
579
  }
501
580
  const result = nav.userAgentData.mobile ? "mobile" /* Mobile */ : "desktop" /* Desktop */;
@@ -517,19 +596,27 @@ var init_device_detector_utils = __esm({
517
596
  }
518
597
  return "desktop" /* Desktop */;
519
598
  } catch (error) {
520
- log("warn", "Device detection failed, defaulting to desktop", { error });
599
+ log("debug", "Device detection failed, defaulting to desktop", { error });
521
600
  return "desktop" /* Desktop */;
522
601
  }
523
602
  };
524
- }
525
- });
526
-
527
- // src/constants/app.constants.ts
528
- var LOG_STYLE_ACTIVE, LOG_STYLE_DISABLED;
529
- var init_app_constants = __esm({
530
- "src/constants/app.constants.ts"() {
531
- LOG_STYLE_ACTIVE = "background: #ff9800; color: white; font-weight: bold; padding: 2px 8px; border-radius: 3px;";
532
- LOG_STYLE_DISABLED = "background: #9e9e9e; color: white; font-weight: bold; padding: 2px 8px; border-radius: 3px;";
603
+ getDeviceInfo = () => {
604
+ try {
605
+ const nav = navigator;
606
+ return {
607
+ type: getDeviceType(),
608
+ os: detectOS(nav),
609
+ browser: detectBrowser(nav)
610
+ };
611
+ } catch (error) {
612
+ log("debug", "Device info detection failed, using defaults", { error });
613
+ return {
614
+ type: "desktop" /* Desktop */,
615
+ os: UNKNOWN,
616
+ browser: UNKNOWN
617
+ };
618
+ }
619
+ };
533
620
  }
534
621
  });
535
622
 
@@ -631,7 +718,7 @@ var init_performance_constants = __esm({
631
718
  var version;
632
719
  var init_package = __esm({
633
720
  "package.json"() {
634
- version = "2.0.2";
721
+ version = "2.0.3";
635
722
  }
636
723
  });
637
724
 
@@ -656,19 +743,33 @@ var init_constants = __esm({
656
743
  }
657
744
  });
658
745
 
659
- // src/utils/browser/qa-mode.utils.ts
660
- var qa_mode_utils_exports = {};
661
- __export(qa_mode_utils_exports, {
746
+ // src/utils/browser/mode.utils.ts
747
+ var mode_utils_exports = {};
748
+ __export(mode_utils_exports, {
662
749
  detectQaMode: () => detectQaMode,
750
+ isQaModeActive: () => isQaModeActive2,
663
751
  setQaMode: () => setQaMode
664
752
  });
665
- var detectQaMode, setQaMode;
666
- var init_qa_mode_utils = __esm({
667
- "src/utils/browser/qa-mode.utils.ts"() {
753
+ var isBrowserEnvironment, cleanUrlParameter, detectQaMode, setQaMode, isQaModeActive2;
754
+ var init_mode_utils = __esm({
755
+ "src/utils/browser/mode.utils.ts"() {
668
756
  init_constants();
669
757
  init_logging_utils();
758
+ isBrowserEnvironment = () => {
759
+ return typeof window !== "undefined" && typeof sessionStorage !== "undefined";
760
+ };
761
+ cleanUrlParameter = () => {
762
+ try {
763
+ const params = new URLSearchParams(window.location.search);
764
+ params.delete(QA_MODE_URL_PARAM);
765
+ const search = params.toString();
766
+ const url = window.location.pathname + (search ? "?" + search : "") + window.location.hash;
767
+ window.history.replaceState({}, "", url);
768
+ } catch {
769
+ }
770
+ };
670
771
  detectQaMode = () => {
671
- if (typeof window === "undefined" || typeof document === "undefined") {
772
+ if (!isBrowserEnvironment()) {
672
773
  return false;
673
774
  }
674
775
  try {
@@ -680,25 +781,19 @@ var init_qa_mode_utils = __esm({
680
781
  newState = true;
681
782
  sessionStorage.setItem(QA_MODE_KEY, "true");
682
783
  log("info", "QA Mode ACTIVE", {
683
- showToClient: true,
784
+ visibility: "qa",
684
785
  style: LOG_STYLE_ACTIVE
685
786
  });
686
787
  } else if (urlParam === QA_MODE_DISABLE_VALUE) {
687
788
  newState = false;
688
789
  sessionStorage.setItem(QA_MODE_KEY, "false");
689
790
  log("info", "QA Mode DISABLED", {
690
- showToClient: true,
791
+ visibility: "qa",
691
792
  style: LOG_STYLE_DISABLED
692
793
  });
693
794
  }
694
795
  if (urlParam === QA_MODE_ENABLE_VALUE || urlParam === QA_MODE_DISABLE_VALUE) {
695
- try {
696
- params.delete(QA_MODE_URL_PARAM);
697
- const search = params.toString();
698
- const url = window.location.pathname + (search ? "?" + search : "") + window.location.hash;
699
- window.history.replaceState({}, "", url);
700
- } catch {
701
- }
796
+ cleanUrlParameter();
702
797
  }
703
798
  return newState ?? storedState === "true";
704
799
  } catch {
@@ -706,25 +801,27 @@ var init_qa_mode_utils = __esm({
706
801
  }
707
802
  };
708
803
  setQaMode = (enabled) => {
709
- if (typeof window === "undefined" || typeof document === "undefined") {
804
+ if (!isBrowserEnvironment()) {
710
805
  return;
711
806
  }
712
807
  try {
713
- if (enabled) {
714
- sessionStorage.setItem(QA_MODE_KEY, "true");
715
- log("info", "QA Mode ENABLED", {
716
- showToClient: true,
717
- style: LOG_STYLE_ACTIVE
718
- });
719
- } else {
720
- sessionStorage.setItem(QA_MODE_KEY, "false");
721
- log("info", "QA Mode DISABLED", {
722
- showToClient: true,
723
- style: LOG_STYLE_DISABLED
724
- });
725
- }
808
+ sessionStorage.setItem(QA_MODE_KEY, enabled ? "true" : "false");
809
+ log("info", enabled ? "QA Mode ACTIVE" : "QA Mode DISABLED", {
810
+ visibility: "qa",
811
+ style: enabled ? LOG_STYLE_ACTIVE : LOG_STYLE_DISABLED
812
+ });
726
813
  } catch {
727
- log("warn", "Cannot set QA mode: sessionStorage unavailable");
814
+ log("debug", "Cannot set QA mode: sessionStorage unavailable");
815
+ }
816
+ };
817
+ isQaModeActive2 = () => {
818
+ if (!isBrowserEnvironment()) {
819
+ return false;
820
+ }
821
+ try {
822
+ return sessionStorage.getItem(QA_MODE_KEY) === "true";
823
+ } catch {
824
+ return false;
728
825
  }
729
826
  };
730
827
  }
@@ -755,7 +852,7 @@ var init_utm_params_utils = __esm({
755
852
  var init_browser = __esm({
756
853
  "src/utils/browser/index.ts"() {
757
854
  init_device_detector_utils();
758
- init_qa_mode_utils();
855
+ init_mode_utils();
759
856
  init_utm_params_utils();
760
857
  }
761
858
  });
@@ -885,7 +982,7 @@ var init_url_utils = __esm({
885
982
  };
886
983
  normalizeUrl = (url, sensitiveQueryParams = []) => {
887
984
  if (!url || typeof url !== "string") {
888
- log("warn", "Invalid URL provided to normalizeUrl", { data: { url: String(url) } });
985
+ log("warn", "Invalid URL provided to normalizeUrl", { data: { type: typeof url } });
889
986
  return url || "";
890
987
  }
891
988
  try {
@@ -908,8 +1005,7 @@ var init_url_utils = __esm({
908
1005
  const result = urlObject.toString();
909
1006
  return result;
910
1007
  } catch (error) {
911
- const urlPreview = url && typeof url === "string" ? url.slice(0, 100) : String(url);
912
- log("warn", "URL normalization failed, returning original", { error, data: { url: urlPreview } });
1008
+ log("warn", "URL normalization failed, returning original", { error, data: { urlLength: url?.length } });
913
1009
  return url;
914
1010
  }
915
1011
  };
@@ -949,7 +1045,7 @@ var init_sanitize_utils = __esm({
949
1045
  log("warn", "XSS patterns detected and removed", {
950
1046
  data: {
951
1047
  patternMatches: xssPatternMatches,
952
- originalValue: value.slice(0, 100)
1048
+ valueLength: value.length
953
1049
  }
954
1050
  });
955
1051
  }
@@ -1465,7 +1561,6 @@ var init_event_validations_utils = __esm({
1465
1561
  const nameValidation = isValidEventName(eventName);
1466
1562
  if (!nameValidation.valid) {
1467
1563
  log("error", "Event name validation failed", {
1468
- showToClient: true,
1469
1564
  data: { eventName, error: nameValidation.error }
1470
1565
  });
1471
1566
  return nameValidation;
@@ -1476,7 +1571,6 @@ var init_event_validations_utils = __esm({
1476
1571
  const metadataValidation = isValidMetadata(eventName, metadata, "customEvent");
1477
1572
  if (!metadataValidation.valid) {
1478
1573
  log("error", "Event metadata validation failed", {
1479
- showToClient: true,
1480
1574
  data: {
1481
1575
  eventName,
1482
1576
  error: metadataValidation.error
@@ -1642,7 +1736,10 @@ function transformEvent(event2, transformer, context) {
1642
1736
  log("warn", `beforeSend transformer returned invalid data, using original [${context}]`);
1643
1737
  return event2;
1644
1738
  } catch (error) {
1645
- log("error", `beforeSend transformer threw error, using original event [${context}]`, { error });
1739
+ log("error", `beforeSend transformer threw error, using original event [${context}]`, {
1740
+ error,
1741
+ visibility: "critical"
1742
+ });
1646
1743
  return event2;
1647
1744
  }
1648
1745
  }
@@ -1668,7 +1765,8 @@ function transformBatch(batch, transformer, context) {
1668
1765
  } catch (error) {
1669
1766
  log("error", `beforeBatch transformer threw error, using original batch [${context}]`, {
1670
1767
  error,
1671
- data: { eventCount: batch.events.length }
1768
+ data: { eventCount: batch.events.length },
1769
+ visibility: "critical"
1672
1770
  });
1673
1771
  return batch;
1674
1772
  }
@@ -2171,7 +2269,7 @@ var init_sender_manager = __esm({
2171
2269
  return true;
2172
2270
  }
2173
2271
  if (this.apiUrl?.includes("localhost:9999" /* Fail */)) {
2174
- log("warn", `Fail mode: simulating network failure${this.integrationId ? ` [${this.integrationId}]` : ""}`, {
2272
+ log("debug", `Fail mode: simulating network failure${this.integrationId ? ` [${this.integrationId}]` : ""}`, {
2175
2273
  data: { events: transformedBody.events.length }
2176
2274
  });
2177
2275
  return false;
@@ -2398,7 +2496,7 @@ var init_sender_manager = __esm({
2398
2496
  return JSON.parse(persistedDataString);
2399
2497
  }
2400
2498
  } catch (error) {
2401
- log("warn", `Failed to parse persisted data${this.integrationId ? ` [${this.integrationId}]` : ""}`, { error });
2499
+ log("debug", `Failed to parse persisted data${this.integrationId ? ` [${this.integrationId}]` : ""}`, { error });
2402
2500
  this.clearPersistedEvents();
2403
2501
  }
2404
2502
  return null;
@@ -2477,7 +2575,7 @@ var init_sender_manager = __esm({
2477
2575
  this.storeManager.setItem(storageKey, JSON.stringify(persistedData));
2478
2576
  return !!this.storeManager.getItem(storageKey);
2479
2577
  } catch (error) {
2480
- log("warn", `Failed to persist events${this.integrationId ? ` [${this.integrationId}]` : ""}`, { error });
2578
+ log("debug", `Failed to persist events${this.integrationId ? ` [${this.integrationId}]` : ""}`, { error });
2481
2579
  return false;
2482
2580
  }
2483
2581
  }
@@ -2486,7 +2584,9 @@ var init_sender_manager = __esm({
2486
2584
  const key = this.getQueueStorageKey();
2487
2585
  this.storeManager.removeItem(key);
2488
2586
  } catch (error) {
2489
- log("warn", `Failed to clear persisted events${this.integrationId ? ` [${this.integrationId}]` : ""}`, { error });
2587
+ log("debug", `Failed to clear persisted events${this.integrationId ? ` [${this.integrationId}]` : ""}`, {
2588
+ error
2589
+ });
2490
2590
  }
2491
2591
  }
2492
2592
  shouldSkipSend() {
@@ -2561,7 +2661,7 @@ var init_time_manager = __esm({
2561
2661
  } else {
2562
2662
  this.bootTime = 0;
2563
2663
  this.bootTimestamp = Date.now();
2564
- log("warn", "performance.now() not available, falling back to Date.now()");
2664
+ log("debug", "performance.now() not available, falling back to Date.now()");
2565
2665
  }
2566
2666
  }
2567
2667
  /**
@@ -2796,7 +2896,7 @@ var init_event_manager = __esm({
2796
2896
  }
2797
2897
  },
2798
2898
  onFailure: () => {
2799
- log("warn", "Failed to recover persisted events");
2899
+ log("debug", "Failed to recover persisted events");
2800
2900
  }
2801
2901
  })
2802
2902
  );
@@ -2870,7 +2970,8 @@ var init_event_manager = __esm({
2870
2970
  custom_event,
2871
2971
  web_vitals,
2872
2972
  error_data,
2873
- viewport_data
2973
+ viewport_data,
2974
+ page_view
2874
2975
  }) {
2875
2976
  if (!type) {
2876
2977
  log("error", "Event type is required - event will be ignored");
@@ -2880,7 +2981,7 @@ var init_event_manager = __esm({
2880
2981
  if (!currentSessionId) {
2881
2982
  if (this.pendingEventsBuffer.length >= MAX_PENDING_EVENTS_BUFFER) {
2882
2983
  this.pendingEventsBuffer.shift();
2883
- log("warn", "Pending events buffer full - dropping oldest event", {
2984
+ log("debug", "Pending events buffer full - dropping oldest event", {
2884
2985
  data: { maxBufferSize: MAX_PENDING_EVENTS_BUFFER }
2885
2986
  });
2886
2987
  }
@@ -2893,7 +2994,8 @@ var init_event_manager = __esm({
2893
2994
  custom_event,
2894
2995
  web_vitals,
2895
2996
  error_data,
2896
- viewport_data
2997
+ viewport_data,
2998
+ page_view
2897
2999
  });
2898
3000
  return;
2899
3001
  }
@@ -2954,7 +3056,8 @@ var init_event_manager = __esm({
2954
3056
  custom_event,
2955
3057
  web_vitals,
2956
3058
  error_data,
2957
- viewport_data
3059
+ viewport_data,
3060
+ page_view
2958
3061
  });
2959
3062
  if (!payload) {
2960
3063
  return;
@@ -2969,7 +3072,7 @@ var init_event_manager = __esm({
2969
3072
  return;
2970
3073
  }
2971
3074
  if (this.get("hasStartSession")) {
2972
- log("warn", "Duplicate session_start detected", {
3075
+ log("debug", "Duplicate session_start detected", {
2973
3076
  data: { sessionId: currentSessionId2 }
2974
3077
  });
2975
3078
  return;
@@ -2979,16 +3082,33 @@ var init_event_manager = __esm({
2979
3082
  if (this.isDuplicateEvent(payload)) {
2980
3083
  return;
2981
3084
  }
2982
- if (this.get("mode") === "qa" /* QA */ && eventType === "custom" /* CUSTOM */ && custom_event) {
2983
- log("info", `Custom Event: ${custom_event.name}`, {
2984
- showToClient: true,
2985
- data: {
2986
- name: custom_event.name,
2987
- ...custom_event.metadata && { metadata: custom_event.metadata }
2988
- }
2989
- });
2990
- this.emitEvent(payload);
2991
- return;
3085
+ if (this.get("mode") === "qa" /* QA */) {
3086
+ if (eventType === "custom" /* CUSTOM */ && custom_event) {
3087
+ log("info", `Custom Event: ${custom_event.name}`, {
3088
+ visibility: "qa",
3089
+ data: {
3090
+ name: custom_event.name,
3091
+ ...custom_event.metadata && { metadata: custom_event.metadata }
3092
+ }
3093
+ });
3094
+ this.emitEvent(payload);
3095
+ return;
3096
+ }
3097
+ if (eventType === "viewport_visible" /* VIEWPORT_VISIBLE */ && viewport_data) {
3098
+ const displayName = viewport_data.name || viewport_data.id || viewport_data.selector;
3099
+ log("info", `Viewport Visible: ${displayName}`, {
3100
+ visibility: "qa",
3101
+ data: {
3102
+ selector: viewport_data.selector,
3103
+ ...viewport_data.name && { name: viewport_data.name },
3104
+ ...viewport_data.id && { id: viewport_data.id },
3105
+ visibilityRatio: viewport_data.visibilityRatio,
3106
+ dwellTime: viewport_data.dwellTime
3107
+ }
3108
+ });
3109
+ this.emitEvent(payload);
3110
+ return;
3111
+ }
2992
3112
  }
2993
3113
  this.addToQueue(payload);
2994
3114
  if (!isCriticalEvent) {
@@ -3240,7 +3360,7 @@ var init_event_manager = __esm({
3240
3360
  }
3241
3361
  const currentSessionId = this.get("sessionId");
3242
3362
  if (!currentSessionId) {
3243
- log("warn", "Cannot flush pending events: session not initialized - keeping in buffer", {
3363
+ log("debug", "Cannot flush pending events: session not initialized - keeping in buffer", {
3244
3364
  data: { bufferedEventCount: this.pendingEventsBuffer.length }
3245
3365
  });
3246
3366
  return;
@@ -3282,7 +3402,7 @@ var init_event_manager = __esm({
3282
3402
  this.emitEventsQueue(body);
3283
3403
  } else {
3284
3404
  this.clearSendInterval();
3285
- log("warn", "Sync flush complete failure, events kept in queue for retry", {
3405
+ log("debug", "Sync flush complete failure, events kept in queue for retry", {
3286
3406
  data: { eventCount: eventIds.length }
3287
3407
  });
3288
3408
  }
@@ -3303,7 +3423,7 @@ var init_event_manager = __esm({
3303
3423
  this.clearSendInterval();
3304
3424
  this.emitEventsQueue(body);
3305
3425
  } else {
3306
- log("warn", "Async flush complete failure, events kept in queue for retry", {
3426
+ log("debug", "Async flush complete failure, events kept in queue for retry", {
3307
3427
  data: { eventCount: eventsToSend.length }
3308
3428
  });
3309
3429
  }
@@ -3337,12 +3457,12 @@ var init_event_manager = __esm({
3337
3457
  this.emitEventsQueue(body);
3338
3458
  const failedCount = results.filter((result) => !this.isSuccessfulResult(result)).length;
3339
3459
  if (failedCount > 0) {
3340
- log("warn", "Periodic send completed with some failures, removed from queue and persisted per-integration", {
3460
+ log("debug", "Periodic send completed with some failures, removed from queue and persisted per-integration", {
3341
3461
  data: { eventCount: eventsToSend.length, failedCount }
3342
3462
  });
3343
3463
  }
3344
3464
  } else {
3345
- log("warn", "Periodic send complete failure, events kept in queue for retry", {
3465
+ log("debug", "Periodic send complete failure, events kept in queue for retry", {
3346
3466
  data: { eventCount: eventsToSend.length }
3347
3467
  });
3348
3468
  }
@@ -3406,6 +3526,7 @@ var init_event_manager = __esm({
3406
3526
  ...data.web_vitals && { web_vitals: data.web_vitals },
3407
3527
  ...data.error_data && { error_data: data.error_data },
3408
3528
  ...data.viewport_data && { viewport_data: data.viewport_data },
3529
+ ...data.page_view && { page_view: data.page_view },
3409
3530
  ...isSessionStart && getUTMParameters() && { utm: getUTMParameters() }
3410
3531
  };
3411
3532
  const collectApiUrls = this.get("collectApiUrls");
@@ -3439,7 +3560,7 @@ var init_event_manager = __esm({
3439
3560
  if (this.recentEventFingerprints.size > MAX_FINGERPRINTS_HARD_LIMIT) {
3440
3561
  this.recentEventFingerprints.clear();
3441
3562
  this.recentEventFingerprints.set(fingerprint, now);
3442
- log("warn", "Event fingerprint cache exceeded hard limit, cleared", {
3563
+ log("debug", "Event fingerprint cache exceeded hard limit, cleared", {
3443
3564
  data: { hardLimit: MAX_FINGERPRINTS_HARD_LIMIT }
3444
3565
  });
3445
3566
  }
@@ -3877,7 +3998,7 @@ var init_session_manager = __esm({
3877
3998
  }
3878
3999
  initCrossTabSync() {
3879
4000
  if (typeof BroadcastChannel === "undefined") {
3880
- log("warn", "BroadcastChannel not supported");
4001
+ log("debug", "BroadcastChannel not supported");
3881
4002
  return;
3882
4003
  }
3883
4004
  const projectId = this.getProjectId();
@@ -4025,7 +4146,7 @@ var init_session_manager = __esm({
4025
4146
  */
4026
4147
  startTracking() {
4027
4148
  if (this.isTracking) {
4028
- log("warn", "Session tracking already active");
4149
+ log("debug", "Session tracking already active");
4029
4150
  return;
4030
4151
  }
4031
4152
  const recoveredSessionId = this.recoverSession();
@@ -4248,7 +4369,7 @@ var init_session_handler = __esm({
4248
4369
  return;
4249
4370
  }
4250
4371
  if (this.destroyed) {
4251
- log("warn", "Cannot start tracking on destroyed handler");
4372
+ log("debug", "Cannot start tracking on destroyed handler");
4252
4373
  return;
4253
4374
  }
4254
4375
  const config = this.get("config");
@@ -4484,7 +4605,7 @@ var init_click_handler = __esm({
4484
4605
  const target = mouseEvent.target;
4485
4606
  const clickedElement = typeof HTMLElement !== "undefined" && target instanceof HTMLElement ? target : typeof HTMLElement !== "undefined" && target instanceof Node && target.parentElement instanceof HTMLElement ? target.parentElement : null;
4486
4607
  if (!clickedElement) {
4487
- log("warn", "Click target not found or not an element");
4608
+ log("debug", "Click target not found or not an element");
4488
4609
  return;
4489
4610
  }
4490
4611
  if (this.shouldIgnoreElement(clickedElement)) {
@@ -4646,7 +4767,7 @@ var init_click_handler = __esm({
4646
4767
  return parent;
4647
4768
  }
4648
4769
  } catch (error) {
4649
- log("warn", "Invalid selector in element search", { error, data: { selector } });
4770
+ log("debug", "Invalid selector in element search", { error, data: { selector } });
4650
4771
  continue;
4651
4772
  }
4652
4773
  }
@@ -5028,7 +5149,7 @@ var init_scroll_handler = __esm({
5028
5149
  return;
5029
5150
  }
5030
5151
  this.limitWarningLogged = true;
5031
- log("warn", "Max scroll events per session reached", {
5152
+ log("debug", "Max scroll events per session reached", {
5032
5153
  data: { limit: this.maxEventsPerSession }
5033
5154
  });
5034
5155
  }
@@ -5113,7 +5234,7 @@ var init_scroll_handler = __esm({
5113
5234
  } else {
5114
5235
  const element = document.querySelector(selector);
5115
5236
  if (!(element instanceof HTMLElement)) {
5116
- log("warn", `Selector "${selector}" did not match an HTMLElement`);
5237
+ log("debug", `Selector "${selector}" did not match an HTMLElement`);
5117
5238
  return;
5118
5239
  }
5119
5240
  targetElement = element;
@@ -5166,15 +5287,15 @@ var init_viewport_handler = __esm({
5166
5287
  const threshold = this.config.threshold ?? 0.5;
5167
5288
  const minDwellTime = this.config.minDwellTime ?? 1e3;
5168
5289
  if (threshold < 0 || threshold > 1) {
5169
- log("warn", "ViewportHandler: Invalid threshold, must be between 0 and 1");
5290
+ log("debug", "ViewportHandler: Invalid threshold, must be between 0 and 1");
5170
5291
  return;
5171
5292
  }
5172
5293
  if (minDwellTime < 0) {
5173
- log("warn", "ViewportHandler: Invalid minDwellTime, must be non-negative");
5294
+ log("debug", "ViewportHandler: Invalid minDwellTime, must be non-negative");
5174
5295
  return;
5175
5296
  }
5176
5297
  if (typeof IntersectionObserver === "undefined") {
5177
- log("warn", "ViewportHandler: IntersectionObserver not supported in this browser");
5298
+ log("debug", "ViewportHandler: IntersectionObserver not supported in this browser");
5178
5299
  return;
5179
5300
  }
5180
5301
  this.observer = new IntersectionObserver(this.handleIntersection, {
@@ -5218,7 +5339,7 @@ var init_viewport_handler = __esm({
5218
5339
  const elements = document.querySelectorAll(elementConfig.selector);
5219
5340
  for (const element of Array.from(elements)) {
5220
5341
  if (totalTracked >= maxTrackedElements) {
5221
- log("warn", "ViewportHandler: Maximum tracked elements reached", {
5342
+ log("debug", "ViewportHandler: Maximum tracked elements reached", {
5222
5343
  data: {
5223
5344
  limit: maxTrackedElements,
5224
5345
  selector: elementConfig.selector,
@@ -5246,7 +5367,7 @@ var init_viewport_handler = __esm({
5246
5367
  totalTracked++;
5247
5368
  }
5248
5369
  } catch (error) {
5249
- log("warn", `ViewportHandler: Invalid selector "${elementConfig.selector}"`, { error });
5370
+ log("debug", `ViewportHandler: Invalid selector "${elementConfig.selector}"`, { error });
5250
5371
  }
5251
5372
  }
5252
5373
  log("debug", "ViewportHandler: Elements tracked", {
@@ -5326,7 +5447,7 @@ var init_viewport_handler = __esm({
5326
5447
  return;
5327
5448
  }
5328
5449
  if (!document.body) {
5329
- log("warn", "ViewportHandler: document.body not available, skipping MutationObserver setup");
5450
+ log("debug", "ViewportHandler: document.body not available, skipping MutationObserver setup");
5330
5451
  return;
5331
5452
  }
5332
5453
  this.mutationObserver = new MutationObserver((mutations) => {
@@ -5401,10 +5522,10 @@ var init_storage_manager = __esm({
5401
5522
  this.storage = this.initializeStorage("localStorage");
5402
5523
  this.sessionStorageRef = this.initializeStorage("sessionStorage");
5403
5524
  if (!this.storage) {
5404
- log("warn", "localStorage not available, using memory fallback");
5525
+ log("debug", "localStorage not available, using memory fallback");
5405
5526
  }
5406
5527
  if (!this.sessionStorageRef) {
5407
- log("warn", "sessionStorage not available, using memory fallback");
5528
+ log("debug", "sessionStorage not available, using memory fallback");
5408
5529
  }
5409
5530
  }
5410
5531
  /**
@@ -5790,7 +5911,7 @@ var init_performance_handler = __esm({
5790
5911
  try {
5791
5912
  obs.disconnect();
5792
5913
  } catch (error) {
5793
- log("warn", "Failed to disconnect performance observer", { error, data: { observerIndex: index } });
5914
+ log("debug", "Failed to disconnect performance observer", { error, data: { observerIndex: index } });
5794
5915
  }
5795
5916
  });
5796
5917
  this.observers.length = 0;
@@ -5875,7 +5996,7 @@ var init_performance_handler = __esm({
5875
5996
  onTTFB(report("TTFB"), { reportAllChanges: false });
5876
5997
  onINP(report("INP"), { reportAllChanges: false });
5877
5998
  } catch (error) {
5878
- log("warn", "Failed to load web-vitals library, using fallback", { error });
5999
+ log("debug", "Failed to load web-vitals library, using fallback", { error });
5879
6000
  this.observeWebVitalsFallback();
5880
6001
  }
5881
6002
  }
@@ -5890,7 +6011,7 @@ var init_performance_handler = __esm({
5890
6011
  this.sendVital({ type: "TTFB", value: Number(ttfb.toFixed(PRECISION_TWO_DECIMALS)) });
5891
6012
  }
5892
6013
  } catch (error) {
5893
- log("warn", "Failed to report TTFB", { error });
6014
+ log("debug", "Failed to report TTFB", { error });
5894
6015
  }
5895
6016
  }
5896
6017
  observeLongTasks() {
@@ -5940,7 +6061,7 @@ var init_performance_handler = __esm({
5940
6061
  }
5941
6062
  trackWebVital(type, value) {
5942
6063
  if (!Number.isFinite(value)) {
5943
- log("warn", "Invalid web vital value", { data: { type, value } });
6064
+ log("debug", "Invalid web vital value", { data: { type, value } });
5944
6065
  return;
5945
6066
  }
5946
6067
  this.eventManager.track({
@@ -5983,7 +6104,7 @@ var init_performance_handler = __esm({
5983
6104
  const baseId = `${timestamp.toFixed(2)}_${window.location.pathname}`;
5984
6105
  return counter > 1 ? `${baseId}_${counter}` : baseId;
5985
6106
  } catch (error) {
5986
- log("warn", "Failed to get navigation ID", { error });
6107
+ log("debug", "Failed to get navigation ID", { error });
5987
6108
  return null;
5988
6109
  }
5989
6110
  }
@@ -6001,7 +6122,7 @@ var init_performance_handler = __esm({
6001
6122
  try {
6002
6123
  cb(list, observer);
6003
6124
  } catch (callbackError) {
6004
- log("warn", "Observer callback failed", {
6125
+ log("debug", "Observer callback failed", {
6005
6126
  error: callbackError,
6006
6127
  data: { type }
6007
6128
  });
@@ -6019,7 +6140,7 @@ var init_performance_handler = __esm({
6019
6140
  }
6020
6141
  return true;
6021
6142
  } catch (error) {
6022
- log("warn", "Failed to create performance observer", {
6143
+ log("debug", "Failed to create performance observer", {
6023
6144
  error,
6024
6145
  data: { type }
6025
6146
  });
@@ -6028,7 +6149,7 @@ var init_performance_handler = __esm({
6028
6149
  }
6029
6150
  shouldSendVital(type, value) {
6030
6151
  if (typeof value !== "number" || !Number.isFinite(value)) {
6031
- log("warn", "Invalid web vital value", { data: { type, value } });
6152
+ log("debug", "Invalid web vital value", { data: { type, value } });
6032
6153
  return false;
6033
6154
  }
6034
6155
  const threshold = this.vitalThresholds[type];
@@ -6100,7 +6221,7 @@ var init_error_handler = __esm({
6100
6221
  this.errorBurstCounter++;
6101
6222
  if (this.errorBurstCounter > ERROR_BURST_THRESHOLD) {
6102
6223
  this.burstBackoffUntil = now + ERROR_BURST_BACKOFF_MS;
6103
- log("warn", "Error burst detected - entering cooldown", {
6224
+ log("debug", "Error burst detected - entering cooldown", {
6104
6225
  data: {
6105
6226
  errorsInWindow: this.errorBurstCounter,
6106
6227
  cooldownMs: ERROR_BURST_BACKOFF_MS
@@ -6355,13 +6476,13 @@ var init_app = __esm({
6355
6476
  this.set("userId", userId);
6356
6477
  const collectApiUrls = getCollectApiUrls(config);
6357
6478
  this.set("collectApiUrls", collectApiUrls);
6358
- const device = getDeviceType();
6479
+ const device = getDeviceInfo();
6359
6480
  this.set("device", device);
6360
6481
  const pageUrl = normalizeUrl(window.location.href, config.sensitiveQueryParams);
6361
6482
  this.set("pageUrl", pageUrl);
6362
- const mode = detectQaMode() ? "qa" /* QA */ : void 0;
6363
- if (mode) {
6364
- this.set("mode", mode);
6483
+ const isQaMode = detectQaMode();
6484
+ if (isQaMode) {
6485
+ this.set("mode", "qa" /* QA */);
6365
6486
  }
6366
6487
  }
6367
6488
  /**
@@ -6507,7 +6628,7 @@ var init_test_bridge = __esm({
6507
6628
  "src/test-bridge.ts"() {
6508
6629
  init_app();
6509
6630
  init_api();
6510
- init_qa_mode_utils();
6631
+ init_mode_utils();
6511
6632
  TestBridge = class extends App {
6512
6633
  constructor() {
6513
6634
  super();
@@ -6984,7 +7105,7 @@ var init_api = __esm({
6984
7105
  }
6985
7106
  }).catch(() => {
6986
7107
  });
6987
- void Promise.resolve().then(() => (init_qa_mode_utils(), qa_mode_utils_exports)).then((module) => {
7108
+ void Promise.resolve().then(() => (init_mode_utils(), mode_utils_exports)).then((module) => {
6988
7109
  if (typeof module.detectQaMode === "function") {
6989
7110
  module.detectQaMode();
6990
7111
  }