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