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