@journium/react 1.0.6 → 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
@@ -703,6 +703,7 @@ class JourniumClient {
703
703
  this.queue = [];
704
704
  this.flushTimer = null;
705
705
  this.initialized = false;
706
+ this.optionsChangeCallbacks = new Set();
706
707
  // Validate required configuration
707
708
  if (!config.publishableKey) {
708
709
  Logger.setDebug(true);
@@ -763,11 +764,21 @@ class JourniumClient {
763
764
  initializeSync() {
764
765
  // Step 1: Load cached remote options from localStorage (synchronous)
765
766
  const cachedRemoteOptions = this.loadCachedOptions();
766
- // Step 2: If no local options provided, use cached remote options
767
- if (!this.config.options && cachedRemoteOptions) {
768
- this.effectiveOptions = cachedRemoteOptions;
769
- Logger.log('Journium: Using cached remote options:', cachedRemoteOptions);
767
+ // Step 2: Merge cached remote options with local options (if cached options exist)
768
+ // Local options take precedence over cached remote options
769
+ if (cachedRemoteOptions) {
770
+ if (this.config.options) {
771
+ // Merge: local options override cached remote options
772
+ this.effectiveOptions = mergeOptions(cachedRemoteOptions, this.config.options);
773
+ Logger.log('Journium: Using cached remote options merged with local options:', this.effectiveOptions);
774
+ }
775
+ else {
776
+ // No local options, use cached remote options as-is
777
+ this.effectiveOptions = cachedRemoteOptions;
778
+ Logger.log('Journium: Using cached remote options:', cachedRemoteOptions);
779
+ }
770
780
  }
781
+ // If no cached options, effectiveOptions already has defaults merged with local options from constructor
771
782
  // Step 3: Mark as initialized immediately - no need to wait for remote fetch
772
783
  this.initialized = true;
773
784
  // Step 4: Start flush timer immediately
@@ -807,12 +818,34 @@ class JourniumClient {
807
818
  Logger.log('Journium: New effective options:', this.effectiveOptions);
808
819
  // Update Logger debug setting with new options
809
820
  Logger.setDebug((_a = this.effectiveOptions.debug) !== null && _a !== void 0 ? _a : false);
821
+ // Notify all registered callbacks about the options change
822
+ this.notifyOptionsChange();
810
823
  }
811
824
  }
812
825
  catch (error) {
813
826
  Logger.warn('Journium: Background remote options fetch failed:', error);
814
827
  }
815
828
  }
829
+ /**
830
+ * Register a callback to be notified when effective options change (e.g., when remote options are fetched)
831
+ */
832
+ onOptionsChange(callback) {
833
+ this.optionsChangeCallbacks.add(callback);
834
+ // Return unsubscribe function
835
+ return () => {
836
+ this.optionsChangeCallbacks.delete(callback);
837
+ };
838
+ }
839
+ notifyOptionsChange() {
840
+ this.optionsChangeCallbacks.forEach(callback => {
841
+ try {
842
+ callback(this.effectiveOptions);
843
+ }
844
+ catch (error) {
845
+ Logger.warn('Journium: Error in options change callback:', error);
846
+ }
847
+ });
848
+ }
816
849
  startFlushTimer() {
817
850
  if (this.flushTimer) {
818
851
  clearInterval(this.flushTimer);
@@ -1024,6 +1057,31 @@ class AutocaptureTracker {
1024
1057
  ...options,
1025
1058
  };
1026
1059
  }
1060
+ /**
1061
+ * Update autocapture options and restart if currently active
1062
+ */
1063
+ updateOptions(options) {
1064
+ const wasActive = this.isActive;
1065
+ // Stop if currently active
1066
+ if (wasActive) {
1067
+ this.stop();
1068
+ }
1069
+ // Update options
1070
+ this.options = {
1071
+ captureClicks: true,
1072
+ captureFormSubmits: true,
1073
+ captureFormChanges: true,
1074
+ captureTextSelection: false,
1075
+ ignoreClasses: ['journium-ignore'],
1076
+ ignoreElements: ['script', 'style', 'noscript'],
1077
+ captureContentText: true,
1078
+ ...options,
1079
+ };
1080
+ // Restart if it was active before
1081
+ if (wasActive) {
1082
+ this.start();
1083
+ }
1084
+ }
1027
1085
  start() {
1028
1086
  if (!isBrowser() || this.isActive) {
1029
1087
  return;
@@ -1353,14 +1411,19 @@ class AutocaptureTracker {
1353
1411
 
1354
1412
  class JourniumAnalytics {
1355
1413
  constructor(config) {
1356
- var _a, _b;
1414
+ this.autocaptureStarted = false;
1357
1415
  this.config = config;
1358
1416
  this.client = new JourniumClient(config);
1359
1417
  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;
1418
+ // Initialize autocapture tracker with effective options (may include cached remote options)
1419
+ // This ensures we use the correct initial state even if cached remote options exist
1420
+ const initialEffectiveOptions = this.client.getEffectiveOptions();
1421
+ const initialAutocaptureOptions = this.resolveAutocaptureOptions(initialEffectiveOptions.autocapture);
1422
+ this.autocaptureTracker = new AutocaptureTracker(this.client, initialAutocaptureOptions);
1423
+ // Listen for options changes (e.g., when fresh remote options are fetched)
1424
+ this.unsubscribeOptionsChange = this.client.onOptionsChange((effectiveOptions) => {
1425
+ this.handleOptionsChange(effectiveOptions);
1426
+ });
1364
1427
  }
1365
1428
  resolveAutocaptureOptions(autocapture) {
1366
1429
  if (autocapture === false) {
@@ -1389,19 +1452,51 @@ class JourniumAnalytics {
1389
1452
  this.pageviewTracker.capturePageview(properties);
1390
1453
  }
1391
1454
  startAutocapture() {
1392
- // Check if automatic pageview tracking is enabled (defaults to true)
1455
+ // Always check effective options (which may include remote options)
1393
1456
  const effectiveOptions = this.client.getEffectiveOptions();
1394
1457
  const autoTrackPageviews = effectiveOptions.autoTrackPageviews !== false;
1458
+ const autocaptureEnabled = effectiveOptions.autocapture !== false;
1459
+ // Update autocapture tracker options if they've changed
1460
+ const autocaptureOptions = this.resolveAutocaptureOptions(effectiveOptions.autocapture);
1461
+ this.autocaptureTracker.updateOptions(autocaptureOptions);
1395
1462
  if (autoTrackPageviews) {
1396
1463
  this.pageviewTracker.startAutocapture();
1397
1464
  }
1398
- if (this.autocaptureEnabled) {
1465
+ if (autocaptureEnabled) {
1399
1466
  this.autocaptureTracker.start();
1400
1467
  }
1468
+ this.autocaptureStarted = true;
1401
1469
  }
1402
1470
  stopAutocapture() {
1403
1471
  this.pageviewTracker.stopAutocapture();
1404
1472
  this.autocaptureTracker.stop();
1473
+ this.autocaptureStarted = false;
1474
+ }
1475
+ /**
1476
+ * Handle effective options change (e.g., when remote options are fetched)
1477
+ */
1478
+ handleOptionsChange(effectiveOptions) {
1479
+ // If autocapture was already started, re-evaluate with new options
1480
+ if (this.autocaptureStarted) {
1481
+ // Stop current autocapture
1482
+ this.pageviewTracker.stopAutocapture();
1483
+ this.autocaptureTracker.stop();
1484
+ this.autocaptureStarted = false;
1485
+ // Re-evaluate if autocapture should be enabled with new options
1486
+ const autoTrackPageviews = effectiveOptions.autoTrackPageviews !== false;
1487
+ const autocaptureEnabled = effectiveOptions.autocapture !== false;
1488
+ // Update autocapture tracker options
1489
+ const autocaptureOptions = this.resolveAutocaptureOptions(effectiveOptions.autocapture);
1490
+ this.autocaptureTracker.updateOptions(autocaptureOptions);
1491
+ // Restart only if still enabled
1492
+ if (autoTrackPageviews) {
1493
+ this.pageviewTracker.startAutocapture();
1494
+ }
1495
+ if (autocaptureEnabled) {
1496
+ this.autocaptureTracker.start();
1497
+ }
1498
+ this.autocaptureStarted = autoTrackPageviews || autocaptureEnabled;
1499
+ }
1405
1500
  }
1406
1501
  async flush() {
1407
1502
  return this.client.flush();
@@ -1409,9 +1504,18 @@ class JourniumAnalytics {
1409
1504
  getEffectiveOptions() {
1410
1505
  return this.client.getEffectiveOptions();
1411
1506
  }
1507
+ /**
1508
+ * Register a callback to be notified when effective options change
1509
+ */
1510
+ onOptionsChange(callback) {
1511
+ return this.client.onOptionsChange(callback);
1512
+ }
1412
1513
  destroy() {
1413
1514
  this.pageviewTracker.stopAutocapture();
1414
1515
  this.autocaptureTracker.stop();
1516
+ if (this.unsubscribeOptionsChange) {
1517
+ this.unsubscribeOptionsChange();
1518
+ }
1415
1519
  this.client.destroy();
1416
1520
  }
1417
1521
  }
@@ -1425,15 +1529,25 @@ const JourniumProvider = ({ children, config, }) => {
1425
1529
  const [effectiveOptions, setEffectiveOptions] = useState(null);
1426
1530
  useEffect(() => {
1427
1531
  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;
1532
+ // Get initial effective options (may include cached remote options)
1533
+ const initialEffective = analyticsInstance.getEffectiveOptions();
1534
+ setEffectiveOptions(initialEffective);
1535
+ // Check if autocapture should be enabled based on initial effective options
1536
+ const autocaptureEnabled = initialEffective.autocapture !== false;
1432
1537
  if (autocaptureEnabled) {
1433
1538
  analyticsInstance.startAutocapture();
1434
1539
  }
1435
1540
  setAnalytics(analyticsInstance);
1541
+ // Listen for options changes (when remote options are fetched)
1542
+ // Note: JourniumAnalytics already handles restarting autocapture when options change
1543
+ // We just need to update the effectiveOptions state for consumers
1544
+ const unsubscribe = analyticsInstance.onOptionsChange((newOptions) => {
1545
+ setEffectiveOptions(newOptions);
1546
+ });
1436
1547
  return () => {
1548
+ if (unsubscribe) {
1549
+ unsubscribe();
1550
+ }
1437
1551
  analyticsInstance.destroy();
1438
1552
  setAnalytics(null);
1439
1553
  setEffectiveOptions(null);