@journium/js 1.0.5 → 1.0.7

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.umd.js CHANGED
@@ -671,14 +671,47 @@
671
671
  }
672
672
  }
673
673
 
674
+ class Logger {
675
+ static setDebug(enabled) {
676
+ this.isDebugEnabled = enabled;
677
+ }
678
+ static isDebug() {
679
+ return this.isDebugEnabled;
680
+ }
681
+ static log(...args) {
682
+ if (this.isDebugEnabled) {
683
+ console.log(...args);
684
+ }
685
+ }
686
+ static warn(...args) {
687
+ if (this.isDebugEnabled) {
688
+ console.warn(...args);
689
+ }
690
+ }
691
+ static error(...args) {
692
+ if (this.isDebugEnabled) {
693
+ console.error(...args);
694
+ }
695
+ }
696
+ static info(...args) {
697
+ if (this.isDebugEnabled) {
698
+ console.info(...args);
699
+ }
700
+ }
701
+ }
702
+ Logger.isDebugEnabled = false;
703
+
674
704
  class JourniumClient {
675
705
  constructor(config) {
706
+ var _a;
676
707
  this.queue = [];
677
708
  this.flushTimer = null;
678
709
  this.initialized = false;
710
+ this.optionsChangeCallbacks = new Set();
679
711
  // Validate required configuration
680
712
  if (!config.publishableKey) {
681
- console.error('Journium: publishableKey is required but not provided. SDK will not function.');
713
+ Logger.setDebug(true);
714
+ Logger.error('Journium: publishableKey is required but not provided. SDK will not function.');
682
715
  return;
683
716
  }
684
717
  // Set default apiHost if not provided
@@ -700,6 +733,8 @@
700
733
  if (this.config.options) {
701
734
  this.effectiveOptions = mergeOptions(defaultOptions, this.config.options);
702
735
  }
736
+ // Initialize Logger with debug setting
737
+ Logger.setDebug((_a = this.effectiveOptions.debug) !== null && _a !== void 0 ? _a : false);
703
738
  // Initialize identity manager
704
739
  this.identityManager = new BrowserIdentityManager(this.effectiveOptions.sessionTimeout, this.config.publishableKey);
705
740
  // Initialize synchronously with cached config, fetch fresh config in background
@@ -707,7 +742,6 @@
707
742
  this.fetchRemoteOptionsAsync();
708
743
  }
709
744
  loadCachedOptions() {
710
- var _a;
711
745
  if (typeof window === 'undefined' || !window.localStorage) {
712
746
  return null;
713
747
  }
@@ -716,14 +750,11 @@
716
750
  return cached ? JSON.parse(cached) : null;
717
751
  }
718
752
  catch (error) {
719
- if ((_a = this.effectiveOptions) === null || _a === void 0 ? void 0 : _a.debug) {
720
- console.warn('Journium: Failed to load cached config:', error);
721
- }
753
+ Logger.warn('Journium: Failed to load cached config:', error);
722
754
  return null;
723
755
  }
724
756
  }
725
757
  saveCachedOptions(options) {
726
- var _a;
727
758
  if (typeof window === 'undefined' || !window.localStorage) {
728
759
  return;
729
760
  }
@@ -731,30 +762,34 @@
731
762
  window.localStorage.setItem(this.optionsStorageKey, JSON.stringify(options));
732
763
  }
733
764
  catch (error) {
734
- if ((_a = this.effectiveOptions) === null || _a === void 0 ? void 0 : _a.debug) {
735
- console.warn('Journium: Failed to save config to cache:', error);
736
- }
765
+ Logger.warn('Journium: Failed to save config to cache:', error);
737
766
  }
738
767
  }
739
768
  initializeSync() {
740
769
  // Step 1: Load cached remote options from localStorage (synchronous)
741
770
  const cachedRemoteOptions = this.loadCachedOptions();
742
- // Step 2: If no local options provided, use cached remote options
743
- if (!this.config.options && cachedRemoteOptions) {
744
- this.effectiveOptions = cachedRemoteOptions;
745
- if (this.effectiveOptions.debug) {
746
- console.log('Journium: Using cached remote options:', cachedRemoteOptions);
771
+ // Step 2: Merge cached remote options with local options (if cached options exist)
772
+ // Local options take precedence over cached remote options
773
+ if (cachedRemoteOptions) {
774
+ if (this.config.options) {
775
+ // Merge: local options override cached remote options
776
+ this.effectiveOptions = mergeOptions(cachedRemoteOptions, this.config.options);
777
+ Logger.log('Journium: Using cached remote options merged with local options:', this.effectiveOptions);
778
+ }
779
+ else {
780
+ // No local options, use cached remote options as-is
781
+ this.effectiveOptions = cachedRemoteOptions;
782
+ Logger.log('Journium: Using cached remote options:', cachedRemoteOptions);
747
783
  }
748
784
  }
785
+ // If no cached options, effectiveOptions already has defaults merged with local options from constructor
749
786
  // Step 3: Mark as initialized immediately - no need to wait for remote fetch
750
787
  this.initialized = true;
751
788
  // Step 4: Start flush timer immediately
752
789
  if (this.effectiveOptions.flushInterval && this.effectiveOptions.flushInterval > 0) {
753
790
  this.startFlushTimer();
754
791
  }
755
- if (this.effectiveOptions.debug) {
756
- console.log('Journium: Client initialized with effective options:', this.effectiveOptions);
757
- }
792
+ Logger.log('Journium: Client initialized with effective options:', this.effectiveOptions);
758
793
  }
759
794
  async fetchRemoteOptionsAsync() {
760
795
  // Fetch fresh config in background
@@ -763,10 +798,9 @@
763
798
  }
764
799
  }
765
800
  async fetchAndCacheRemoteOptions() {
801
+ var _a;
766
802
  try {
767
- if (this.effectiveOptions.debug) {
768
- console.log('Journium: Fetching remote configuration in background...');
769
- }
803
+ Logger.log('Journium: Fetching remote configuration in background...');
770
804
  const remoteOptionsResponse = await fetchRemoteOptions(this.config.apiHost, this.config.publishableKey);
771
805
  if (remoteOptionsResponse && remoteOptionsResponse.success) {
772
806
  // Save remote config to cache for next session
@@ -784,18 +818,38 @@
784
818
  if (this.effectiveOptions.sessionTimeout) {
785
819
  this.identityManager.updateSessionTimeout(this.effectiveOptions.sessionTimeout);
786
820
  }
787
- if (this.effectiveOptions.debug) {
788
- console.log('Journium: Background remote options applied:', remoteOptionsResponse.config);
789
- console.log('Journium: New effective options:', this.effectiveOptions);
790
- }
821
+ Logger.log('Journium: Background remote options applied:', remoteOptionsResponse.config);
822
+ Logger.log('Journium: New effective options:', this.effectiveOptions);
823
+ // Update Logger debug setting with new options
824
+ Logger.setDebug((_a = this.effectiveOptions.debug) !== null && _a !== void 0 ? _a : false);
825
+ // Notify all registered callbacks about the options change
826
+ this.notifyOptionsChange();
791
827
  }
792
828
  }
793
829
  catch (error) {
794
- if (this.effectiveOptions.debug) {
795
- console.warn('Journium: Background remote options fetch failed:', error);
796
- }
830
+ Logger.warn('Journium: Background remote options fetch failed:', error);
797
831
  }
798
832
  }
833
+ /**
834
+ * Register a callback to be notified when effective options change (e.g., when remote options are fetched)
835
+ */
836
+ onOptionsChange(callback) {
837
+ this.optionsChangeCallbacks.add(callback);
838
+ // Return unsubscribe function
839
+ return () => {
840
+ this.optionsChangeCallbacks.delete(callback);
841
+ };
842
+ }
843
+ notifyOptionsChange() {
844
+ this.optionsChangeCallbacks.forEach(callback => {
845
+ try {
846
+ callback(this.effectiveOptions);
847
+ }
848
+ catch (error) {
849
+ Logger.warn('Journium: Error in options change callback:', error);
850
+ }
851
+ });
852
+ }
799
853
  startFlushTimer() {
800
854
  if (this.flushTimer) {
801
855
  clearInterval(this.flushTimer);
@@ -822,24 +876,17 @@
822
876
  if (!response.ok) {
823
877
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
824
878
  }
825
- if (this.effectiveOptions.debug) {
826
- console.log('Journium: Successfully sent events', events);
827
- }
879
+ Logger.log('Journium: Successfully sent events', events);
828
880
  }
829
881
  catch (error) {
830
- if (this.effectiveOptions.debug) {
831
- console.error('Journium: Failed to send events', error);
832
- }
882
+ Logger.error('Journium: Failed to send events', error);
833
883
  throw error;
834
884
  }
835
885
  }
836
886
  identify(distinctId, attributes = {}) {
837
- var _a;
838
887
  // Don't identify if SDK is not properly configured
839
888
  if (!this.config || !this.config.publishableKey || !this.initialized) {
840
- if ((_a = this.effectiveOptions) === null || _a === void 0 ? void 0 : _a.debug) {
841
- console.warn('Journium: identify() call rejected - SDK not ready');
842
- }
889
+ Logger.warn('Journium: identify() call rejected - SDK not ready');
843
890
  return;
844
891
  }
845
892
  // Call identify on identity manager to get previous distinct ID
@@ -850,32 +897,22 @@
850
897
  $anon_distinct_id: previousDistinctId,
851
898
  };
852
899
  this.track('$identify', identifyProperties);
853
- if (this.effectiveOptions.debug) {
854
- console.log('Journium: User identified', { distinctId, attributes, previousDistinctId });
855
- }
900
+ Logger.log('Journium: User identified', { distinctId, attributes, previousDistinctId });
856
901
  }
857
902
  reset() {
858
- var _a;
859
903
  // Don't reset if SDK is not properly configured
860
904
  if (!this.config || !this.config.publishableKey || !this.initialized) {
861
- if ((_a = this.effectiveOptions) === null || _a === void 0 ? void 0 : _a.debug) {
862
- console.warn('Journium: reset() call rejected - SDK not ready');
863
- }
905
+ Logger.warn('Journium: reset() call rejected - SDK not ready');
864
906
  return;
865
907
  }
866
908
  // Reset identity in identity manager
867
909
  this.identityManager.reset();
868
- if (this.effectiveOptions.debug) {
869
- console.log('Journium: User identity reset');
870
- }
910
+ Logger.log('Journium: User identity reset');
871
911
  }
872
912
  track(event, properties = {}) {
873
- var _a;
874
913
  // Don't track if SDK is not properly configured
875
914
  if (!this.config || !this.config.publishableKey || !this.initialized) {
876
- if ((_a = this.effectiveOptions) === null || _a === void 0 ? void 0 : _a.debug) {
877
- console.warn('Journium: track() call rejected - SDK not ready');
878
- }
915
+ Logger.warn('Journium: track() call rejected - SDK not ready');
879
916
  return;
880
917
  }
881
918
  const identity = this.identityManager.getIdentity();
@@ -901,9 +938,7 @@
901
938
  properties: eventProperties,
902
939
  };
903
940
  this.queue.push(journiumEvent);
904
- if (this.effectiveOptions.debug) {
905
- console.log('Journium: Event tracked', journiumEvent);
906
- }
941
+ Logger.log('Journium: Event tracked', journiumEvent);
907
942
  if (this.queue.length >= this.effectiveOptions.flushAt) {
908
943
  this.flush();
909
944
  }
@@ -1026,6 +1061,31 @@
1026
1061
  ...options,
1027
1062
  };
1028
1063
  }
1064
+ /**
1065
+ * Update autocapture options and restart if currently active
1066
+ */
1067
+ updateOptions(options) {
1068
+ const wasActive = this.isActive;
1069
+ // Stop if currently active
1070
+ if (wasActive) {
1071
+ this.stop();
1072
+ }
1073
+ // Update options
1074
+ this.options = {
1075
+ captureClicks: true,
1076
+ captureFormSubmits: true,
1077
+ captureFormChanges: true,
1078
+ captureTextSelection: false,
1079
+ ignoreClasses: ['journium-ignore'],
1080
+ ignoreElements: ['script', 'style', 'noscript'],
1081
+ captureContentText: true,
1082
+ ...options,
1083
+ };
1084
+ // Restart if it was active before
1085
+ if (wasActive) {
1086
+ this.start();
1087
+ }
1088
+ }
1029
1089
  start() {
1030
1090
  if (!isBrowser() || this.isActive) {
1031
1091
  return;
@@ -1355,14 +1415,19 @@
1355
1415
 
1356
1416
  class JourniumAnalytics {
1357
1417
  constructor(config) {
1358
- var _a, _b;
1418
+ this.autocaptureStarted = false;
1359
1419
  this.config = config;
1360
1420
  this.client = new JourniumClient(config);
1361
1421
  this.pageviewTracker = new PageviewTracker(this.client);
1362
- const autocaptureOptions = this.resolveAutocaptureOptions((_a = config.options) === null || _a === void 0 ? void 0 : _a.autocapture);
1363
- this.autocaptureTracker = new AutocaptureTracker(this.client, autocaptureOptions);
1364
- // Store resolved autocapture state for startAutocapture method
1365
- this.autocaptureEnabled = ((_b = config.options) === null || _b === void 0 ? void 0 : _b.autocapture) !== false;
1422
+ // Initialize autocapture tracker with effective options (may include cached remote options)
1423
+ // This ensures we use the correct initial state even if cached remote options exist
1424
+ const initialEffectiveOptions = this.client.getEffectiveOptions();
1425
+ const initialAutocaptureOptions = this.resolveAutocaptureOptions(initialEffectiveOptions.autocapture);
1426
+ this.autocaptureTracker = new AutocaptureTracker(this.client, initialAutocaptureOptions);
1427
+ // Listen for options changes (e.g., when fresh remote options are fetched)
1428
+ this.unsubscribeOptionsChange = this.client.onOptionsChange((effectiveOptions) => {
1429
+ this.handleOptionsChange(effectiveOptions);
1430
+ });
1366
1431
  }
1367
1432
  resolveAutocaptureOptions(autocapture) {
1368
1433
  if (autocapture === false) {
@@ -1391,19 +1456,51 @@
1391
1456
  this.pageviewTracker.capturePageview(properties);
1392
1457
  }
1393
1458
  startAutocapture() {
1394
- // Check if automatic pageview tracking is enabled (defaults to true)
1459
+ // Always check effective options (which may include remote options)
1395
1460
  const effectiveOptions = this.client.getEffectiveOptions();
1396
1461
  const autoTrackPageviews = effectiveOptions.autoTrackPageviews !== false;
1462
+ const autocaptureEnabled = effectiveOptions.autocapture !== false;
1463
+ // Update autocapture tracker options if they've changed
1464
+ const autocaptureOptions = this.resolveAutocaptureOptions(effectiveOptions.autocapture);
1465
+ this.autocaptureTracker.updateOptions(autocaptureOptions);
1397
1466
  if (autoTrackPageviews) {
1398
1467
  this.pageviewTracker.startAutocapture();
1399
1468
  }
1400
- if (this.autocaptureEnabled) {
1469
+ if (autocaptureEnabled) {
1401
1470
  this.autocaptureTracker.start();
1402
1471
  }
1472
+ this.autocaptureStarted = true;
1403
1473
  }
1404
1474
  stopAutocapture() {
1405
1475
  this.pageviewTracker.stopAutocapture();
1406
1476
  this.autocaptureTracker.stop();
1477
+ this.autocaptureStarted = false;
1478
+ }
1479
+ /**
1480
+ * Handle effective options change (e.g., when remote options are fetched)
1481
+ */
1482
+ handleOptionsChange(effectiveOptions) {
1483
+ // If autocapture was already started, re-evaluate with new options
1484
+ if (this.autocaptureStarted) {
1485
+ // Stop current autocapture
1486
+ this.pageviewTracker.stopAutocapture();
1487
+ this.autocaptureTracker.stop();
1488
+ this.autocaptureStarted = false;
1489
+ // Re-evaluate if autocapture should be enabled with new options
1490
+ const autoTrackPageviews = effectiveOptions.autoTrackPageviews !== false;
1491
+ const autocaptureEnabled = effectiveOptions.autocapture !== false;
1492
+ // Update autocapture tracker options
1493
+ const autocaptureOptions = this.resolveAutocaptureOptions(effectiveOptions.autocapture);
1494
+ this.autocaptureTracker.updateOptions(autocaptureOptions);
1495
+ // Restart only if still enabled
1496
+ if (autoTrackPageviews) {
1497
+ this.pageviewTracker.startAutocapture();
1498
+ }
1499
+ if (autocaptureEnabled) {
1500
+ this.autocaptureTracker.start();
1501
+ }
1502
+ this.autocaptureStarted = autoTrackPageviews || autocaptureEnabled;
1503
+ }
1407
1504
  }
1408
1505
  async flush() {
1409
1506
  return this.client.flush();
@@ -1411,9 +1508,18 @@
1411
1508
  getEffectiveOptions() {
1412
1509
  return this.client.getEffectiveOptions();
1413
1510
  }
1511
+ /**
1512
+ * Register a callback to be notified when effective options change
1513
+ */
1514
+ onOptionsChange(callback) {
1515
+ return this.client.onOptionsChange(callback);
1516
+ }
1414
1517
  destroy() {
1415
1518
  this.pageviewTracker.stopAutocapture();
1416
1519
  this.autocaptureTracker.stop();
1520
+ if (this.unsubscribeOptionsChange) {
1521
+ this.unsubscribeOptionsChange();
1522
+ }
1417
1523
  this.client.destroy();
1418
1524
  }
1419
1525
  }
@@ -1425,6 +1531,7 @@
1425
1531
  exports.BrowserIdentityManager = BrowserIdentityManager;
1426
1532
  exports.JourniumAnalytics = JourniumAnalytics;
1427
1533
  exports.JourniumClient = JourniumClient;
1534
+ exports.Logger = Logger;
1428
1535
  exports.PageviewTracker = PageviewTracker;
1429
1536
  exports.fetchRemoteOptions = fetchRemoteOptions;
1430
1537
  exports.generateId = generateId;