@journium/react 1.0.7 → 1.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.
- package/dist/context.d.ts.map +1 -1
- package/dist/index.cjs +268 -128
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +268 -128
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -3
- package/readme.md +30 -326
package/dist/index.mjs
CHANGED
|
@@ -699,15 +699,23 @@ Logger.isDebugEnabled = false;
|
|
|
699
699
|
|
|
700
700
|
class JourniumClient {
|
|
701
701
|
constructor(config) {
|
|
702
|
-
var _a;
|
|
702
|
+
var _a, _b, _c, _d;
|
|
703
703
|
this.queue = [];
|
|
704
|
+
this.stagedEvents = [];
|
|
704
705
|
this.flushTimer = null;
|
|
705
|
-
this.
|
|
706
|
+
this.initializationComplete = false;
|
|
707
|
+
this.initializationFailed = false;
|
|
708
|
+
this.disabled = false;
|
|
706
709
|
this.optionsChangeCallbacks = new Set();
|
|
707
|
-
// Validate required configuration
|
|
708
|
-
if (!config.publishableKey) {
|
|
710
|
+
// Validate required configuration - put in disabled state if invalid
|
|
711
|
+
if (!config.publishableKey || config.publishableKey.trim() === '') {
|
|
712
|
+
this.disabled = true;
|
|
709
713
|
Logger.setDebug(true);
|
|
710
|
-
Logger.error('Journium: publishableKey is required but not provided. SDK will not function.');
|
|
714
|
+
Logger.error('Journium: publishableKey is required but not provided or is empty. SDK will not function.');
|
|
715
|
+
// Create minimal config to prevent crashes
|
|
716
|
+
this.config = { publishableKey: '', apiHost: 'https://events.journium.app' };
|
|
717
|
+
this.effectiveOptions = { debug: true };
|
|
718
|
+
this.optionsStorageKey = 'jrnm_invalid_options';
|
|
711
719
|
return;
|
|
712
720
|
}
|
|
713
721
|
// Set default apiHost if not provided
|
|
@@ -717,25 +725,15 @@ class JourniumClient {
|
|
|
717
725
|
};
|
|
718
726
|
// Generate storage key for options caching
|
|
719
727
|
this.optionsStorageKey = `jrnm_${config.publishableKey}_options`;
|
|
720
|
-
//
|
|
721
|
-
const
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
// Initialize
|
|
728
|
-
this.
|
|
729
|
-
if (this.config.options) {
|
|
730
|
-
this.effectiveOptions = mergeOptions(defaultOptions, this.config.options);
|
|
731
|
-
}
|
|
732
|
-
// Initialize Logger with debug setting
|
|
733
|
-
Logger.setDebug((_a = this.effectiveOptions.debug) !== null && _a !== void 0 ? _a : false);
|
|
734
|
-
// Initialize identity manager
|
|
735
|
-
this.identityManager = new BrowserIdentityManager(this.effectiveOptions.sessionTimeout, this.config.publishableKey);
|
|
736
|
-
// Initialize synchronously with cached config, fetch fresh config in background
|
|
737
|
-
this.initializeSync();
|
|
738
|
-
this.fetchRemoteOptionsAsync();
|
|
728
|
+
// Initialize with minimal defaults for identity manager
|
|
729
|
+
const fallbackSessionTimeout = 30 * 60 * 1000; // 30 minutes
|
|
730
|
+
this.effectiveOptions = {}; // Will be set after remote config
|
|
731
|
+
// Initialize Logger with local debug setting or false
|
|
732
|
+
Logger.setDebug((_b = (_a = this.config.options) === null || _a === void 0 ? void 0 : _a.debug) !== null && _b !== void 0 ? _b : false);
|
|
733
|
+
// Initialize identity manager with fallback timeout
|
|
734
|
+
this.identityManager = new BrowserIdentityManager((_d = (_c = this.config.options) === null || _c === void 0 ? void 0 : _c.sessionTimeout) !== null && _d !== void 0 ? _d : fallbackSessionTimeout, this.config.publishableKey);
|
|
735
|
+
// Initialize asynchronously - wait for remote config first
|
|
736
|
+
this.initializeAsync();
|
|
739
737
|
}
|
|
740
738
|
loadCachedOptions() {
|
|
741
739
|
if (typeof window === 'undefined' || !window.localStorage) {
|
|
@@ -761,70 +759,105 @@ class JourniumClient {
|
|
|
761
759
|
Logger.warn('Journium: Failed to save config to cache:', error);
|
|
762
760
|
}
|
|
763
761
|
}
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
if (
|
|
771
|
-
//
|
|
772
|
-
this.
|
|
773
|
-
|
|
762
|
+
async initializeAsync() {
|
|
763
|
+
var _a;
|
|
764
|
+
try {
|
|
765
|
+
Logger.log('Journium: Starting initialization - fetching fresh remote config...');
|
|
766
|
+
// Step 1: Try to fetch fresh remote config with timeout and retry
|
|
767
|
+
const remoteOptions = await this.fetchRemoteOptionsWithRetry();
|
|
768
|
+
if (remoteOptions) {
|
|
769
|
+
// Step 2: Cache the fresh remote config
|
|
770
|
+
this.saveCachedOptions(remoteOptions);
|
|
771
|
+
// Step 3: Merge local options over remote config (local overrides remote)
|
|
772
|
+
if (this.config.options) {
|
|
773
|
+
this.effectiveOptions = mergeOptions(this.config.options, remoteOptions);
|
|
774
|
+
Logger.log('Journium: Using fresh remote config merged with local options:', this.effectiveOptions);
|
|
775
|
+
}
|
|
776
|
+
else {
|
|
777
|
+
this.effectiveOptions = remoteOptions;
|
|
778
|
+
Logger.log('Journium: Using fresh remote config:', this.effectiveOptions);
|
|
779
|
+
}
|
|
774
780
|
}
|
|
775
781
|
else {
|
|
776
|
-
//
|
|
777
|
-
|
|
778
|
-
|
|
782
|
+
// Step 4: Fallback to cached config if fresh fetch failed
|
|
783
|
+
const cachedRemoteOptions = this.loadCachedOptions();
|
|
784
|
+
if (cachedRemoteOptions) {
|
|
785
|
+
if (this.config.options) {
|
|
786
|
+
this.effectiveOptions = mergeOptions(this.config.options, cachedRemoteOptions);
|
|
787
|
+
Logger.log('Journium: Fresh config failed, using cached remote config merged with local options:', this.effectiveOptions);
|
|
788
|
+
}
|
|
789
|
+
else {
|
|
790
|
+
this.effectiveOptions = cachedRemoteOptions;
|
|
791
|
+
Logger.log('Journium: Fresh config failed, using cached remote config:', this.effectiveOptions);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
else {
|
|
795
|
+
// Step 5: No remote config and no cached config - initialization fails
|
|
796
|
+
Logger.error('Journium: Initialization failed - no remote config available and no cached config found');
|
|
797
|
+
this.initializationFailed = true;
|
|
798
|
+
this.initializationComplete = false;
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
779
801
|
}
|
|
802
|
+
// Step 6: Update identity manager session timeout if provided
|
|
803
|
+
if (this.effectiveOptions.sessionTimeout) {
|
|
804
|
+
this.identityManager.updateSessionTimeout(this.effectiveOptions.sessionTimeout);
|
|
805
|
+
}
|
|
806
|
+
// Step 7: Update Logger debug setting
|
|
807
|
+
Logger.setDebug((_a = this.effectiveOptions.debug) !== null && _a !== void 0 ? _a : false);
|
|
808
|
+
// Step 8: Mark initialization as complete
|
|
809
|
+
this.initializationComplete = true;
|
|
810
|
+
this.initializationFailed = false;
|
|
811
|
+
// Step 9: Process any staged events
|
|
812
|
+
this.processStagedEvents();
|
|
813
|
+
// Step 10: Start flush timer
|
|
814
|
+
if (this.effectiveOptions.flushInterval && this.effectiveOptions.flushInterval > 0) {
|
|
815
|
+
this.startFlushTimer();
|
|
816
|
+
}
|
|
817
|
+
Logger.log('Journium: Initialization complete with options:', this.effectiveOptions);
|
|
818
|
+
// Step 11: Notify callbacks about options
|
|
819
|
+
this.notifyOptionsChange();
|
|
780
820
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
if (this.effectiveOptions.flushInterval && this.effectiveOptions.flushInterval > 0) {
|
|
786
|
-
this.startFlushTimer();
|
|
787
|
-
}
|
|
788
|
-
Logger.log('Journium: Client initialized with effective options:', this.effectiveOptions);
|
|
789
|
-
}
|
|
790
|
-
async fetchRemoteOptionsAsync() {
|
|
791
|
-
// Fetch fresh config in background
|
|
792
|
-
if (this.config.publishableKey) {
|
|
793
|
-
await this.fetchAndCacheRemoteOptions();
|
|
821
|
+
catch (error) {
|
|
822
|
+
Logger.error('Journium: Initialization failed:', error);
|
|
823
|
+
this.initializationFailed = true;
|
|
824
|
+
this.initializationComplete = false;
|
|
794
825
|
}
|
|
795
826
|
}
|
|
796
|
-
async
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
//
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
827
|
+
async fetchRemoteOptionsWithRetry() {
|
|
828
|
+
const maxRetries = 2;
|
|
829
|
+
const timeoutMs = 15000; // 15 seconds
|
|
830
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
831
|
+
try {
|
|
832
|
+
Logger.log(`Journium: Fetching remote config (attempt ${attempt}/${maxRetries})...`);
|
|
833
|
+
// Create timeout promise
|
|
834
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
835
|
+
setTimeout(() => reject(new Error('Timeout')), timeoutMs);
|
|
836
|
+
});
|
|
837
|
+
// Race fetch against timeout
|
|
838
|
+
const fetchPromise = fetchRemoteOptions(this.config.apiHost, this.config.publishableKey);
|
|
839
|
+
const remoteOptionsResponse = await Promise.race([fetchPromise, timeoutPromise]);
|
|
840
|
+
if (remoteOptionsResponse && remoteOptionsResponse.success) {
|
|
841
|
+
Logger.log('Journium: Successfully fetched fresh remote config:', remoteOptionsResponse.config);
|
|
842
|
+
return remoteOptionsResponse.config;
|
|
808
843
|
}
|
|
809
844
|
else {
|
|
810
|
-
|
|
811
|
-
this.effectiveOptions = mergeOptions(remoteOptionsResponse.config, this.config.options);
|
|
845
|
+
throw new Error('Remote config fetch unsuccessful');
|
|
812
846
|
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
847
|
+
}
|
|
848
|
+
catch (error) {
|
|
849
|
+
Logger.warn(`Journium: Remote config fetch attempt ${attempt} failed:`, error);
|
|
850
|
+
if (attempt === maxRetries) {
|
|
851
|
+
Logger.warn('Journium: All remote config fetch attempts failed, falling back to cached config');
|
|
852
|
+
return null;
|
|
853
|
+
}
|
|
854
|
+
// Wait 1 second before retry (except on last attempt)
|
|
855
|
+
if (attempt < maxRetries) {
|
|
856
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
816
857
|
}
|
|
817
|
-
Logger.log('Journium: Background remote options applied:', remoteOptionsResponse.config);
|
|
818
|
-
Logger.log('Journium: New effective options:', this.effectiveOptions);
|
|
819
|
-
// Update Logger debug setting with new options
|
|
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();
|
|
823
858
|
}
|
|
824
859
|
}
|
|
825
|
-
|
|
826
|
-
Logger.warn('Journium: Background remote options fetch failed:', error);
|
|
827
|
-
}
|
|
860
|
+
return null;
|
|
828
861
|
}
|
|
829
862
|
/**
|
|
830
863
|
* Register a callback to be notified when effective options change (e.g., when remote options are fetched)
|
|
@@ -846,12 +879,48 @@ class JourniumClient {
|
|
|
846
879
|
}
|
|
847
880
|
});
|
|
848
881
|
}
|
|
882
|
+
processStagedEvents() {
|
|
883
|
+
if (this.stagedEvents.length === 0)
|
|
884
|
+
return;
|
|
885
|
+
Logger.log(`Journium: Processing ${this.stagedEvents.length} staged events`);
|
|
886
|
+
// Move staged events to main queue, adding identity properties now
|
|
887
|
+
const identity = this.identityManager.getIdentity();
|
|
888
|
+
const userAgentInfo = this.identityManager.getUserAgentInfo();
|
|
889
|
+
for (const stagedEvent of this.stagedEvents) {
|
|
890
|
+
// Add identity properties that weren't available during staging
|
|
891
|
+
const eventWithIdentity = {
|
|
892
|
+
...stagedEvent,
|
|
893
|
+
properties: {
|
|
894
|
+
$device_id: identity === null || identity === void 0 ? void 0 : identity.$device_id,
|
|
895
|
+
distinct_id: identity === null || identity === void 0 ? void 0 : identity.distinct_id,
|
|
896
|
+
$session_id: identity === null || identity === void 0 ? void 0 : identity.$session_id,
|
|
897
|
+
$is_identified: (identity === null || identity === void 0 ? void 0 : identity.$user_state) === 'identified',
|
|
898
|
+
$current_url: typeof window !== 'undefined' ? window.location.href : '',
|
|
899
|
+
$pathname: typeof window !== 'undefined' ? window.location.pathname : '',
|
|
900
|
+
...userAgentInfo,
|
|
901
|
+
$lib_version: '0.1.0', // TODO: Get from package.json
|
|
902
|
+
$platform: 'web',
|
|
903
|
+
...stagedEvent.properties, // Original properties override system properties
|
|
904
|
+
},
|
|
905
|
+
};
|
|
906
|
+
this.queue.push(eventWithIdentity);
|
|
907
|
+
}
|
|
908
|
+
// Clear staged events
|
|
909
|
+
this.stagedEvents = [];
|
|
910
|
+
Logger.log('Journium: Staged events processed and moved to main queue');
|
|
911
|
+
// Check if we should flush immediately
|
|
912
|
+
if (this.queue.length >= this.effectiveOptions.flushAt) {
|
|
913
|
+
// console.log('1 Journium: Flushing events...'+JSON.stringify(this.effectiveOptions));
|
|
914
|
+
this.flush();
|
|
915
|
+
}
|
|
916
|
+
}
|
|
849
917
|
startFlushTimer() {
|
|
850
918
|
if (this.flushTimer) {
|
|
851
919
|
clearInterval(this.flushTimer);
|
|
852
920
|
}
|
|
853
921
|
// Use universal setInterval (works in both browser and Node.js)
|
|
854
922
|
this.flushTimer = setInterval(() => {
|
|
923
|
+
// console.log('2 Journium: Flushing events...'+JSON.stringify(this.effectiveOptions));
|
|
855
924
|
this.flush();
|
|
856
925
|
}, this.effectiveOptions.flushInterval);
|
|
857
926
|
}
|
|
@@ -880,9 +949,14 @@ class JourniumClient {
|
|
|
880
949
|
}
|
|
881
950
|
}
|
|
882
951
|
identify(distinctId, attributes = {}) {
|
|
883
|
-
// Don't identify if SDK is not properly configured
|
|
884
|
-
if (
|
|
885
|
-
Logger.warn('Journium: identify() call rejected - SDK not ready');
|
|
952
|
+
// Don't identify if SDK is not properly configured or disabled
|
|
953
|
+
if (this.disabled || !this.config || !this.config.publishableKey) {
|
|
954
|
+
Logger.warn('Journium: identify() call rejected - SDK not ready or disabled');
|
|
955
|
+
return;
|
|
956
|
+
}
|
|
957
|
+
// Don't identify if initialization failed
|
|
958
|
+
if (this.initializationFailed) {
|
|
959
|
+
Logger.warn('Journium: identify() call rejected - initialization failed');
|
|
886
960
|
return;
|
|
887
961
|
}
|
|
888
962
|
// Call identify on identity manager to get previous distinct ID
|
|
@@ -896,9 +970,14 @@ class JourniumClient {
|
|
|
896
970
|
Logger.log('Journium: User identified', { distinctId, attributes, previousDistinctId });
|
|
897
971
|
}
|
|
898
972
|
reset() {
|
|
899
|
-
// Don't reset if SDK is not properly configured
|
|
900
|
-
if (
|
|
901
|
-
Logger.warn('Journium: reset() call rejected - SDK not ready');
|
|
973
|
+
// Don't reset if SDK is not properly configured or disabled
|
|
974
|
+
if (this.disabled || !this.config || !this.config.publishableKey) {
|
|
975
|
+
Logger.warn('Journium: reset() call rejected - SDK not ready or disabled');
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
// Don't reset if initialization failed
|
|
979
|
+
if (this.initializationFailed) {
|
|
980
|
+
Logger.warn('Journium: reset() call rejected - initialization failed');
|
|
902
981
|
return;
|
|
903
982
|
}
|
|
904
983
|
// Reset identity in identity manager
|
|
@@ -906,36 +985,58 @@ class JourniumClient {
|
|
|
906
985
|
Logger.log('Journium: User identity reset');
|
|
907
986
|
}
|
|
908
987
|
track(event, properties = {}) {
|
|
909
|
-
// Don't track if SDK is not properly configured
|
|
910
|
-
if (
|
|
911
|
-
Logger.warn('Journium: track() call rejected - SDK not ready');
|
|
988
|
+
// Don't track if SDK is not properly configured or disabled
|
|
989
|
+
if (this.disabled || !this.config || !this.config.publishableKey) {
|
|
990
|
+
Logger.warn('Journium: track() call rejected - SDK not ready or disabled');
|
|
912
991
|
return;
|
|
913
992
|
}
|
|
914
|
-
|
|
915
|
-
const userAgentInfo = this.identityManager.getUserAgentInfo();
|
|
916
|
-
// Create standardized event properties
|
|
917
|
-
const eventProperties = {
|
|
918
|
-
$device_id: identity === null || identity === void 0 ? void 0 : identity.$device_id,
|
|
919
|
-
distinct_id: identity === null || identity === void 0 ? void 0 : identity.distinct_id,
|
|
920
|
-
$session_id: identity === null || identity === void 0 ? void 0 : identity.$session_id,
|
|
921
|
-
$is_identified: (identity === null || identity === void 0 ? void 0 : identity.$user_state) === 'identified',
|
|
922
|
-
$current_url: typeof window !== 'undefined' ? window.location.href : '',
|
|
923
|
-
$pathname: typeof window !== 'undefined' ? window.location.pathname : '',
|
|
924
|
-
...userAgentInfo,
|
|
925
|
-
$lib_version: '0.1.0', // TODO: Get from package.json
|
|
926
|
-
$platform: 'web',
|
|
927
|
-
...properties, // User-provided properties override defaults
|
|
928
|
-
};
|
|
993
|
+
// Create minimal event without identity properties (will be added later if staging)
|
|
929
994
|
const journiumEvent = {
|
|
930
995
|
uuid: generateUuidv7(),
|
|
931
996
|
ingestion_key: this.config.publishableKey,
|
|
932
997
|
client_timestamp: getCurrentTimestamp(),
|
|
933
998
|
event,
|
|
934
|
-
properties:
|
|
999
|
+
properties: { ...properties }, // Only user properties for now
|
|
935
1000
|
};
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
1001
|
+
// Stage events during initialization, add to queue after initialization
|
|
1002
|
+
if (!this.initializationComplete) {
|
|
1003
|
+
// If initialization failed, reject events
|
|
1004
|
+
if (this.initializationFailed) {
|
|
1005
|
+
Logger.warn('Journium: track() call rejected - initialization failed');
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
this.stagedEvents.push(journiumEvent);
|
|
1009
|
+
Logger.log('Journium: Event staged during initialization', journiumEvent);
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
// If initialization failed, reject events
|
|
1013
|
+
if (this.initializationFailed) {
|
|
1014
|
+
Logger.warn('Journium: track() call rejected - initialization failed');
|
|
1015
|
+
return;
|
|
1016
|
+
}
|
|
1017
|
+
// Add identity properties for immediate events (after initialization)
|
|
1018
|
+
const identity = this.identityManager.getIdentity();
|
|
1019
|
+
const userAgentInfo = this.identityManager.getUserAgentInfo();
|
|
1020
|
+
const eventWithIdentity = {
|
|
1021
|
+
...journiumEvent,
|
|
1022
|
+
properties: {
|
|
1023
|
+
$device_id: identity === null || identity === void 0 ? void 0 : identity.$device_id,
|
|
1024
|
+
distinct_id: identity === null || identity === void 0 ? void 0 : identity.distinct_id,
|
|
1025
|
+
$session_id: identity === null || identity === void 0 ? void 0 : identity.$session_id,
|
|
1026
|
+
$is_identified: (identity === null || identity === void 0 ? void 0 : identity.$user_state) === 'identified',
|
|
1027
|
+
$current_url: typeof window !== 'undefined' ? window.location.href : '',
|
|
1028
|
+
$pathname: typeof window !== 'undefined' ? window.location.pathname : '',
|
|
1029
|
+
...userAgentInfo,
|
|
1030
|
+
$lib_version: '0.1.0', // TODO: Get from package.json
|
|
1031
|
+
$platform: 'web',
|
|
1032
|
+
...properties, // User-provided properties override system properties
|
|
1033
|
+
},
|
|
1034
|
+
};
|
|
1035
|
+
this.queue.push(eventWithIdentity);
|
|
1036
|
+
Logger.log('Journium: Event tracked', eventWithIdentity);
|
|
1037
|
+
// Only flush if we have effective options (after initialization)
|
|
1038
|
+
if (this.effectiveOptions.flushAt && this.queue.length >= this.effectiveOptions.flushAt) {
|
|
1039
|
+
// console.log('3 Journium: Flushing events...'+JSON.stringify(this.effectiveOptions));
|
|
939
1040
|
this.flush();
|
|
940
1041
|
}
|
|
941
1042
|
}
|
|
@@ -944,6 +1045,11 @@ class JourniumClient {
|
|
|
944
1045
|
if (!this.config || !this.config.publishableKey) {
|
|
945
1046
|
return;
|
|
946
1047
|
}
|
|
1048
|
+
// Don't flush if initialization failed
|
|
1049
|
+
if (this.initializationFailed) {
|
|
1050
|
+
Logger.warn('Journium: flush() call rejected - initialization failed');
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
947
1053
|
if (this.queue.length === 0)
|
|
948
1054
|
return;
|
|
949
1055
|
const events = [...this.queue];
|
|
@@ -995,7 +1101,7 @@ class PageviewTracker {
|
|
|
995
1101
|
* Start automatic autocapture for pageviews
|
|
996
1102
|
* @returns void
|
|
997
1103
|
*/
|
|
998
|
-
|
|
1104
|
+
startAutoPageviewTracking() {
|
|
999
1105
|
this.capturePageview();
|
|
1000
1106
|
if (typeof window !== 'undefined') {
|
|
1001
1107
|
// Store original methods for cleanup
|
|
@@ -1424,6 +1530,9 @@ class JourniumAnalytics {
|
|
|
1424
1530
|
this.unsubscribeOptionsChange = this.client.onOptionsChange((effectiveOptions) => {
|
|
1425
1531
|
this.handleOptionsChange(effectiveOptions);
|
|
1426
1532
|
});
|
|
1533
|
+
// Start automatic autocapture immediately if initial options support it
|
|
1534
|
+
// This handles cached remote options or local options with autocapture enabled
|
|
1535
|
+
this.startAutocaptureIfEnabled(initialEffectiveOptions);
|
|
1427
1536
|
}
|
|
1428
1537
|
resolveAutocaptureOptions(autocapture) {
|
|
1429
1538
|
if (autocapture === false) {
|
|
@@ -1454,13 +1563,18 @@ class JourniumAnalytics {
|
|
|
1454
1563
|
startAutocapture() {
|
|
1455
1564
|
// Always check effective options (which may include remote options)
|
|
1456
1565
|
const effectiveOptions = this.client.getEffectiveOptions();
|
|
1457
|
-
|
|
1458
|
-
const
|
|
1566
|
+
// Only enable if effectiveOptions are loaded and autoTrackPageviews is not explicitly false
|
|
1567
|
+
const autoTrackPageviews = effectiveOptions && Object.keys(effectiveOptions).length > 0
|
|
1568
|
+
? effectiveOptions.autoTrackPageviews !== false
|
|
1569
|
+
: false;
|
|
1570
|
+
const autocaptureEnabled = effectiveOptions && Object.keys(effectiveOptions).length > 0
|
|
1571
|
+
? effectiveOptions.autocapture !== false
|
|
1572
|
+
: false;
|
|
1459
1573
|
// Update autocapture tracker options if they've changed
|
|
1460
1574
|
const autocaptureOptions = this.resolveAutocaptureOptions(effectiveOptions.autocapture);
|
|
1461
1575
|
this.autocaptureTracker.updateOptions(autocaptureOptions);
|
|
1462
1576
|
if (autoTrackPageviews) {
|
|
1463
|
-
this.pageviewTracker.
|
|
1577
|
+
this.pageviewTracker.startAutoPageviewTracking();
|
|
1464
1578
|
}
|
|
1465
1579
|
if (autocaptureEnabled) {
|
|
1466
1580
|
this.autocaptureTracker.start();
|
|
@@ -1473,30 +1587,60 @@ class JourniumAnalytics {
|
|
|
1473
1587
|
this.autocaptureStarted = false;
|
|
1474
1588
|
}
|
|
1475
1589
|
/**
|
|
1476
|
-
*
|
|
1590
|
+
* Automatically start autocapture if enabled in options
|
|
1591
|
+
* Handles both initial options and empty options during remote-first initialization
|
|
1477
1592
|
*/
|
|
1478
|
-
|
|
1479
|
-
//
|
|
1593
|
+
startAutocaptureIfEnabled(effectiveOptions) {
|
|
1594
|
+
// Skip if autocapture was already started manually
|
|
1480
1595
|
if (this.autocaptureStarted) {
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1596
|
+
return;
|
|
1597
|
+
}
|
|
1598
|
+
// During remote-first initialization, effective options might be empty initially
|
|
1599
|
+
// Only auto-start if we have actual options loaded, not empty options
|
|
1600
|
+
const hasActualOptions = effectiveOptions && Object.keys(effectiveOptions).length > 0;
|
|
1601
|
+
if (hasActualOptions) {
|
|
1602
|
+
// Use same logic as manual startAutocapture() but only start automatically
|
|
1486
1603
|
const autoTrackPageviews = effectiveOptions.autoTrackPageviews !== false;
|
|
1487
1604
|
const autocaptureEnabled = effectiveOptions.autocapture !== false;
|
|
1488
1605
|
// Update autocapture tracker options
|
|
1489
1606
|
const autocaptureOptions = this.resolveAutocaptureOptions(effectiveOptions.autocapture);
|
|
1490
1607
|
this.autocaptureTracker.updateOptions(autocaptureOptions);
|
|
1491
|
-
// Restart only if still enabled
|
|
1492
1608
|
if (autoTrackPageviews) {
|
|
1493
|
-
this.pageviewTracker.
|
|
1609
|
+
this.pageviewTracker.startAutoPageviewTracking();
|
|
1494
1610
|
}
|
|
1495
1611
|
if (autocaptureEnabled) {
|
|
1496
1612
|
this.autocaptureTracker.start();
|
|
1497
1613
|
}
|
|
1498
|
-
|
|
1614
|
+
if (autoTrackPageviews || autocaptureEnabled) {
|
|
1615
|
+
this.autocaptureStarted = true;
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
// If options are empty (during initialization), wait for options change callback
|
|
1619
|
+
}
|
|
1620
|
+
/**
|
|
1621
|
+
* Handle effective options change (e.g., when remote options are fetched)
|
|
1622
|
+
*/
|
|
1623
|
+
handleOptionsChange(effectiveOptions) {
|
|
1624
|
+
// Stop current autocapture if it was already started
|
|
1625
|
+
if (this.autocaptureStarted) {
|
|
1626
|
+
this.pageviewTracker.stopAutocapture();
|
|
1627
|
+
this.autocaptureTracker.stop();
|
|
1628
|
+
this.autocaptureStarted = false;
|
|
1499
1629
|
}
|
|
1630
|
+
// Evaluate if autocapture should be enabled with new options
|
|
1631
|
+
const autoTrackPageviews = effectiveOptions.autoTrackPageviews !== false;
|
|
1632
|
+
const autocaptureEnabled = effectiveOptions.autocapture !== false;
|
|
1633
|
+
// Update autocapture tracker options
|
|
1634
|
+
const autocaptureOptions = this.resolveAutocaptureOptions(effectiveOptions.autocapture);
|
|
1635
|
+
this.autocaptureTracker.updateOptions(autocaptureOptions);
|
|
1636
|
+
// Start autocapture based on new options (even if it wasn't started before)
|
|
1637
|
+
if (autoTrackPageviews) {
|
|
1638
|
+
this.pageviewTracker.startAutoPageviewTracking();
|
|
1639
|
+
}
|
|
1640
|
+
if (autocaptureEnabled) {
|
|
1641
|
+
this.autocaptureTracker.start();
|
|
1642
|
+
}
|
|
1643
|
+
this.autocaptureStarted = autoTrackPageviews || autocaptureEnabled;
|
|
1500
1644
|
}
|
|
1501
1645
|
async flush() {
|
|
1502
1646
|
return this.client.flush();
|
|
@@ -1523,24 +1667,20 @@ const init = (config) => {
|
|
|
1523
1667
|
return new JourniumAnalytics(config);
|
|
1524
1668
|
};
|
|
1525
1669
|
|
|
1526
|
-
const JourniumContext = createContext(
|
|
1670
|
+
const JourniumContext = createContext(undefined);
|
|
1527
1671
|
const JourniumProvider = ({ children, config, }) => {
|
|
1528
1672
|
const [analytics, setAnalytics] = useState(null);
|
|
1529
1673
|
const [effectiveOptions, setEffectiveOptions] = useState(null);
|
|
1530
1674
|
useEffect(() => {
|
|
1531
1675
|
const analyticsInstance = new JourniumAnalytics(config);
|
|
1532
|
-
// Get initial effective options (may
|
|
1676
|
+
// Get initial effective options (may be empty during remote-first initialization)
|
|
1533
1677
|
const initialEffective = analyticsInstance.getEffectiveOptions();
|
|
1534
1678
|
setEffectiveOptions(initialEffective);
|
|
1535
|
-
//
|
|
1536
|
-
|
|
1537
|
-
if (autocaptureEnabled) {
|
|
1538
|
-
analyticsInstance.startAutocapture();
|
|
1539
|
-
}
|
|
1679
|
+
// Don't start autocapture immediately with potentially empty options
|
|
1680
|
+
// Let the analytics instance handle autocapture after initialization completes
|
|
1540
1681
|
setAnalytics(analyticsInstance);
|
|
1541
1682
|
// Listen for options changes (when remote options are fetched)
|
|
1542
|
-
//
|
|
1543
|
-
// We just need to update the effectiveOptions state for consumers
|
|
1683
|
+
// The JourniumAnalytics will automatically start autocapture when initialization completes
|
|
1544
1684
|
const unsubscribe = analyticsInstance.onOptionsChange((newOptions) => {
|
|
1545
1685
|
setEffectiveOptions(newOptions);
|
|
1546
1686
|
});
|