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