@journium/js 1.1.1 → 1.2.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/JourniumAnalytics.d.ts.map +1 -1
- package/dist/JourniumClient.d.ts +9 -0
- package/dist/JourniumClient.d.ts.map +1 -1
- package/dist/PageviewTracker.d.ts +3 -2
- package/dist/PageviewTracker.d.ts.map +1 -1
- package/dist/index.cjs +120 -99
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +12 -2
- package/dist/index.mjs +120 -99
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +120 -99
- package/dist/index.umd.js.map +1 -1
- package/dist/journium.js +120 -99
- package/dist/journium.js.map +1 -1
- package/dist/journium.min.js +1 -1
- package/dist/journium.min.js.map +1 -1
- package/package.json +2 -2
package/dist/journium.js
CHANGED
|
@@ -701,6 +701,9 @@
|
|
|
701
701
|
this.queue = [];
|
|
702
702
|
this.stagedEvents = [];
|
|
703
703
|
this.flushTimer = null;
|
|
704
|
+
this.remoteOptionsRefreshTimer = null;
|
|
705
|
+
this.isRefreshing = false;
|
|
706
|
+
this.lastRemoteOptions = null;
|
|
704
707
|
this.initializationComplete = false;
|
|
705
708
|
this.initializationFailed = false;
|
|
706
709
|
this.optionsChangeCallbacks = new Set();
|
|
@@ -754,61 +757,24 @@
|
|
|
754
757
|
}
|
|
755
758
|
}
|
|
756
759
|
async initializeAsync() {
|
|
757
|
-
var _a;
|
|
758
760
|
try {
|
|
759
761
|
Logger.log('Journium: Starting initialization - fetching fresh remote config...');
|
|
760
|
-
// Step 1: Try to fetch fresh remote config with timeout and retry
|
|
761
762
|
const remoteOptions = await this.fetchRemoteOptionsWithRetry();
|
|
762
|
-
if (remoteOptions) {
|
|
763
|
-
|
|
764
|
-
this.
|
|
765
|
-
|
|
766
|
-
if (this.config.options) {
|
|
767
|
-
this.effectiveOptions = mergeOptions(this.config.options, remoteOptions);
|
|
768
|
-
Logger.log('Journium: Using fresh remote config merged with local options:', this.effectiveOptions);
|
|
769
|
-
}
|
|
770
|
-
else {
|
|
771
|
-
this.effectiveOptions = remoteOptions;
|
|
772
|
-
Logger.log('Journium: Using fresh remote config:', this.effectiveOptions);
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
else {
|
|
776
|
-
// Step 4: Fallback to cached config if fresh fetch failed
|
|
777
|
-
/* const cachedRemoteOptions = this.loadCachedOptions();
|
|
778
|
-
|
|
779
|
-
if (cachedRemoteOptions) {
|
|
780
|
-
if (this.config.options) {
|
|
781
|
-
this.effectiveOptions = mergeOptions(this.config.options, cachedRemoteOptions);
|
|
782
|
-
Logger.log('Journium: Fresh config failed, using cached remote config merged with local options:', this.effectiveOptions);
|
|
783
|
-
} else {
|
|
784
|
-
this.effectiveOptions = cachedRemoteOptions;
|
|
785
|
-
Logger.log('Journium: Fresh config failed, using cached remote config:', this.effectiveOptions);
|
|
786
|
-
}
|
|
787
|
-
} else {
|
|
788
|
-
// Step 5: No remote config and no cached config - initialization fails
|
|
789
|
-
Logger.error('Journium: Initialization failed - no remote config available and no cached config found');
|
|
790
|
-
this.initializationFailed = true;
|
|
791
|
-
this.initializationComplete = false;
|
|
792
|
-
return;
|
|
793
|
-
} */
|
|
794
|
-
}
|
|
795
|
-
// Step 6: Update identity manager session timeout if provided
|
|
796
|
-
if (this.effectiveOptions.sessionTimeout) {
|
|
797
|
-
this.identityManager.updateSessionTimeout(this.effectiveOptions.sessionTimeout);
|
|
763
|
+
if (!remoteOptions) {
|
|
764
|
+
Logger.error('Journium: Initialization failed - no remote config available');
|
|
765
|
+
this.initializationFailed = true;
|
|
766
|
+
return;
|
|
798
767
|
}
|
|
799
|
-
|
|
800
|
-
Logger.
|
|
801
|
-
// Step 8: Mark initialization as complete
|
|
768
|
+
this.applyRemoteOptions(remoteOptions);
|
|
769
|
+
Logger.log('Journium: Effective options after init:', this.effectiveOptions);
|
|
802
770
|
this.initializationComplete = true;
|
|
803
771
|
this.initializationFailed = false;
|
|
804
|
-
// Step 9: Process any staged events
|
|
805
772
|
this.processStagedEvents();
|
|
806
|
-
// Step 10: Start flush timer
|
|
807
773
|
if (this.effectiveOptions.flushInterval && this.effectiveOptions.flushInterval > 0) {
|
|
808
774
|
this.startFlushTimer();
|
|
809
775
|
}
|
|
810
|
-
|
|
811
|
-
|
|
776
|
+
this.startRemoteOptionsRefreshTimer();
|
|
777
|
+
Logger.log('Journium: Initialization complete');
|
|
812
778
|
this.notifyOptionsChange();
|
|
813
779
|
}
|
|
814
780
|
catch (error) {
|
|
@@ -879,35 +845,21 @@
|
|
|
879
845
|
processStagedEvents() {
|
|
880
846
|
if (this.stagedEvents.length === 0)
|
|
881
847
|
return;
|
|
848
|
+
if (this.ingestionPaused) {
|
|
849
|
+
Logger.warn(`Journium: Ingestion is paused — discarding ${this.stagedEvents.length} staged events`);
|
|
850
|
+
this.stagedEvents = [];
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
882
853
|
Logger.log(`Journium: Processing ${this.stagedEvents.length} staged events`);
|
|
883
|
-
// Move staged events to main queue, adding identity properties now
|
|
884
|
-
const identity = this.identityManager.getIdentity();
|
|
885
|
-
const userAgentInfo = this.identityManager.getUserAgentInfo();
|
|
886
854
|
for (const stagedEvent of this.stagedEvents) {
|
|
887
|
-
|
|
888
|
-
const eventWithIdentity = {
|
|
855
|
+
this.queue.push({
|
|
889
856
|
...stagedEvent,
|
|
890
|
-
properties:
|
|
891
|
-
|
|
892
|
-
distinct_id: identity === null || identity === void 0 ? void 0 : identity.distinct_id,
|
|
893
|
-
$session_id: identity === null || identity === void 0 ? void 0 : identity.$session_id,
|
|
894
|
-
$is_identified: (identity === null || identity === void 0 ? void 0 : identity.$user_state) === 'identified',
|
|
895
|
-
$current_url: typeof window !== 'undefined' ? window.location.href : '',
|
|
896
|
-
$pathname: typeof window !== 'undefined' ? window.location.pathname : '',
|
|
897
|
-
...userAgentInfo,
|
|
898
|
-
$lib_version: '0.1.0', // TODO: Get from package.json
|
|
899
|
-
$platform: 'web',
|
|
900
|
-
...stagedEvent.properties, // Original properties override system properties
|
|
901
|
-
},
|
|
902
|
-
};
|
|
903
|
-
this.queue.push(eventWithIdentity);
|
|
857
|
+
properties: this.buildIdentityProperties(stagedEvent.properties),
|
|
858
|
+
});
|
|
904
859
|
}
|
|
905
|
-
// Clear staged events
|
|
906
860
|
this.stagedEvents = [];
|
|
907
861
|
Logger.log('Journium: Staged events processed and moved to main queue');
|
|
908
|
-
// Check if we should flush immediately
|
|
909
862
|
if (this.queue.length >= this.effectiveOptions.flushAt) {
|
|
910
|
-
// console.log('1 Journium: Flushing events...'+JSON.stringify(this.effectiveOptions));
|
|
911
863
|
this.flush();
|
|
912
864
|
}
|
|
913
865
|
}
|
|
@@ -915,12 +867,88 @@
|
|
|
915
867
|
if (this.flushTimer) {
|
|
916
868
|
clearInterval(this.flushTimer);
|
|
917
869
|
}
|
|
918
|
-
// Use universal setInterval (works in both browser and Node.js)
|
|
919
870
|
this.flushTimer = setInterval(() => {
|
|
920
|
-
// console.log('2 Journium: Flushing events...'+JSON.stringify(this.effectiveOptions));
|
|
921
871
|
this.flush();
|
|
922
872
|
}, this.effectiveOptions.flushInterval);
|
|
923
873
|
}
|
|
874
|
+
startRemoteOptionsRefreshTimer() {
|
|
875
|
+
// Clear any existing timer to prevent duplicate intervals
|
|
876
|
+
if (this.remoteOptionsRefreshTimer) {
|
|
877
|
+
clearInterval(this.remoteOptionsRefreshTimer);
|
|
878
|
+
this.remoteOptionsRefreshTimer = null;
|
|
879
|
+
}
|
|
880
|
+
this.remoteOptionsRefreshTimer = setInterval(() => {
|
|
881
|
+
this.refreshRemoteOptions();
|
|
882
|
+
}, JourniumClient.REMOTE_OPTIONS_REFRESH_INTERVAL);
|
|
883
|
+
Logger.log(`Journium: Scheduling remote options refresh every ${JourniumClient.REMOTE_OPTIONS_REFRESH_INTERVAL}ms`);
|
|
884
|
+
}
|
|
885
|
+
async refreshRemoteOptions() {
|
|
886
|
+
if (this.isRefreshing) {
|
|
887
|
+
Logger.log('Journium: Remote options refresh already in progress, skipping');
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
this.isRefreshing = true;
|
|
891
|
+
Logger.log('Journium: Periodic remote options refresh triggered');
|
|
892
|
+
try {
|
|
893
|
+
const remoteOptions = await this.fetchRemoteOptionsWithRetry();
|
|
894
|
+
if (!remoteOptions) {
|
|
895
|
+
Logger.warn('Journium: Periodic remote options refresh failed, keeping current options');
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
const prevRemoteSnapshot = JSON.stringify(this.lastRemoteOptions);
|
|
899
|
+
const prevFlushInterval = this.effectiveOptions.flushInterval;
|
|
900
|
+
this.applyRemoteOptions(remoteOptions);
|
|
901
|
+
if (prevRemoteSnapshot === JSON.stringify(this.lastRemoteOptions)) {
|
|
902
|
+
Logger.log('Journium: Remote options unchanged after refresh, no update needed');
|
|
903
|
+
return;
|
|
904
|
+
}
|
|
905
|
+
Logger.log('Journium: Remote options updated after refresh:', this.effectiveOptions);
|
|
906
|
+
if (this.effectiveOptions.flushInterval !== prevFlushInterval) {
|
|
907
|
+
if (this.effectiveOptions.flushInterval && this.effectiveOptions.flushInterval > 0) {
|
|
908
|
+
this.startFlushTimer();
|
|
909
|
+
}
|
|
910
|
+
else if (this.flushTimer) {
|
|
911
|
+
clearInterval(this.flushTimer);
|
|
912
|
+
this.flushTimer = null;
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
this.notifyOptionsChange();
|
|
916
|
+
}
|
|
917
|
+
catch (error) {
|
|
918
|
+
Logger.error('Journium: Periodic remote options refresh encountered an error:', error);
|
|
919
|
+
}
|
|
920
|
+
finally {
|
|
921
|
+
this.isRefreshing = false;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
applyRemoteOptions(remoteOptions) {
|
|
925
|
+
var _a;
|
|
926
|
+
this.lastRemoteOptions = remoteOptions;
|
|
927
|
+
this.effectiveOptions = this.config.options
|
|
928
|
+
? mergeOptions(this.config.options, remoteOptions)
|
|
929
|
+
: remoteOptions;
|
|
930
|
+
this.saveCachedOptions(remoteOptions);
|
|
931
|
+
if (this.effectiveOptions.sessionTimeout) {
|
|
932
|
+
this.identityManager.updateSessionTimeout(this.effectiveOptions.sessionTimeout);
|
|
933
|
+
}
|
|
934
|
+
Logger.setDebug((_a = this.effectiveOptions.debug) !== null && _a !== void 0 ? _a : false);
|
|
935
|
+
}
|
|
936
|
+
buildIdentityProperties(userProperties = {}) {
|
|
937
|
+
const identity = this.identityManager.getIdentity();
|
|
938
|
+
const userAgentInfo = this.identityManager.getUserAgentInfo();
|
|
939
|
+
return {
|
|
940
|
+
$device_id: identity === null || identity === void 0 ? void 0 : identity.$device_id,
|
|
941
|
+
distinct_id: identity === null || identity === void 0 ? void 0 : identity.distinct_id,
|
|
942
|
+
$session_id: identity === null || identity === void 0 ? void 0 : identity.$session_id,
|
|
943
|
+
$is_identified: (identity === null || identity === void 0 ? void 0 : identity.$user_state) === 'identified',
|
|
944
|
+
$current_url: typeof window !== 'undefined' ? window.location.href : '',
|
|
945
|
+
$pathname: typeof window !== 'undefined' ? window.location.pathname : '',
|
|
946
|
+
...userAgentInfo,
|
|
947
|
+
$lib_version: '0.1.0', // TODO: Get from package.json
|
|
948
|
+
$platform: 'web',
|
|
949
|
+
...userProperties,
|
|
950
|
+
};
|
|
951
|
+
}
|
|
924
952
|
async sendEvents(events) {
|
|
925
953
|
if (!events.length)
|
|
926
954
|
return;
|
|
@@ -980,9 +1008,7 @@
|
|
|
980
1008
|
event,
|
|
981
1009
|
properties: { ...properties }, // Only user properties for now
|
|
982
1010
|
};
|
|
983
|
-
// Stage events during initialization, add to queue after initialization
|
|
984
1011
|
if (!this.initializationComplete) {
|
|
985
|
-
// If initialization failed, reject events
|
|
986
1012
|
if (this.initializationFailed) {
|
|
987
1013
|
Logger.warn('Journium: track() call rejected - initialization failed');
|
|
988
1014
|
return;
|
|
@@ -991,34 +1017,17 @@
|
|
|
991
1017
|
Logger.log('Journium: Event staged during initialization', journiumEvent);
|
|
992
1018
|
return;
|
|
993
1019
|
}
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
Logger.warn('Journium: track() call rejected - initialization failed');
|
|
1020
|
+
if (this.ingestionPaused) {
|
|
1021
|
+
Logger.warn('Journium: Ingestion is paused — event dropped:', journiumEvent.event);
|
|
997
1022
|
return;
|
|
998
1023
|
}
|
|
999
|
-
// Add identity properties for immediate events (after initialization)
|
|
1000
|
-
const identity = this.identityManager.getIdentity();
|
|
1001
|
-
const userAgentInfo = this.identityManager.getUserAgentInfo();
|
|
1002
1024
|
const eventWithIdentity = {
|
|
1003
1025
|
...journiumEvent,
|
|
1004
|
-
properties:
|
|
1005
|
-
$device_id: identity === null || identity === void 0 ? void 0 : identity.$device_id,
|
|
1006
|
-
distinct_id: identity === null || identity === void 0 ? void 0 : identity.distinct_id,
|
|
1007
|
-
$session_id: identity === null || identity === void 0 ? void 0 : identity.$session_id,
|
|
1008
|
-
$is_identified: (identity === null || identity === void 0 ? void 0 : identity.$user_state) === 'identified',
|
|
1009
|
-
$current_url: typeof window !== 'undefined' ? window.location.href : '',
|
|
1010
|
-
$pathname: typeof window !== 'undefined' ? window.location.pathname : '',
|
|
1011
|
-
...userAgentInfo,
|
|
1012
|
-
$lib_version: '0.1.0', // TODO: Get from package.json
|
|
1013
|
-
$platform: 'web',
|
|
1014
|
-
...properties, // User-provided properties override system properties
|
|
1015
|
-
},
|
|
1026
|
+
properties: this.buildIdentityProperties(properties),
|
|
1016
1027
|
};
|
|
1017
1028
|
this.queue.push(eventWithIdentity);
|
|
1018
1029
|
Logger.log('Journium: Event tracked', eventWithIdentity);
|
|
1019
|
-
// Only flush if we have effective options (after initialization)
|
|
1020
1030
|
if (this.effectiveOptions.flushAt && this.queue.length >= this.effectiveOptions.flushAt) {
|
|
1021
|
-
// console.log('3 Journium: Flushing events...'+JSON.stringify(this.effectiveOptions));
|
|
1022
1031
|
this.flush();
|
|
1023
1032
|
}
|
|
1024
1033
|
}
|
|
@@ -1045,12 +1054,20 @@
|
|
|
1045
1054
|
clearInterval(this.flushTimer);
|
|
1046
1055
|
this.flushTimer = null;
|
|
1047
1056
|
}
|
|
1057
|
+
if (this.remoteOptionsRefreshTimer) {
|
|
1058
|
+
clearInterval(this.remoteOptionsRefreshTimer);
|
|
1059
|
+
this.remoteOptionsRefreshTimer = null;
|
|
1060
|
+
}
|
|
1048
1061
|
this.flush();
|
|
1049
1062
|
}
|
|
1050
1063
|
getEffectiveOptions() {
|
|
1051
1064
|
return this.effectiveOptions;
|
|
1052
1065
|
}
|
|
1066
|
+
get ingestionPaused() {
|
|
1067
|
+
return this.effectiveOptions['ingestionPaused'] === true;
|
|
1068
|
+
}
|
|
1053
1069
|
}
|
|
1070
|
+
JourniumClient.REMOTE_OPTIONS_REFRESH_INTERVAL = 15 * 60 * 1000; // 15 minutes
|
|
1054
1071
|
|
|
1055
1072
|
class PageviewTracker {
|
|
1056
1073
|
constructor(client) {
|
|
@@ -1077,10 +1094,13 @@
|
|
|
1077
1094
|
}
|
|
1078
1095
|
/**
|
|
1079
1096
|
* Start automatic autocapture for pageviews
|
|
1080
|
-
* @
|
|
1097
|
+
* @param captureInitialPageview - whether to fire a $pageview immediately on start (default: true).
|
|
1098
|
+
* Pass false when restarting after a remote options update to avoid a spurious pageview.
|
|
1081
1099
|
*/
|
|
1082
|
-
startAutoPageviewTracking() {
|
|
1083
|
-
|
|
1100
|
+
startAutoPageviewTracking(captureInitialPageview = true) {
|
|
1101
|
+
if (captureInitialPageview) {
|
|
1102
|
+
this.capturePageview();
|
|
1103
|
+
}
|
|
1084
1104
|
if (typeof window !== 'undefined') {
|
|
1085
1105
|
// Store original methods for cleanup
|
|
1086
1106
|
this.originalPushState = window.history.pushState;
|
|
@@ -1599,21 +1619,22 @@
|
|
|
1599
1619
|
* Handle effective options change (e.g., when remote options are fetched)
|
|
1600
1620
|
*/
|
|
1601
1621
|
handleOptionsChange(effectiveOptions) {
|
|
1602
|
-
//
|
|
1622
|
+
// If autocapture was never started before, this is the initial options application
|
|
1623
|
+
// (async init completed) — treat it like a page load and capture a pageview.
|
|
1624
|
+
// If it was already started, this is a periodic remote options update — only
|
|
1625
|
+
// re-register listeners without emitting a spurious pageview.
|
|
1626
|
+
const isFirstStart = !this.autocaptureStarted;
|
|
1603
1627
|
if (this.autocaptureStarted) {
|
|
1604
1628
|
this.pageviewTracker.stopAutocapture();
|
|
1605
1629
|
this.autocaptureTracker.stop();
|
|
1606
1630
|
this.autocaptureStarted = false;
|
|
1607
1631
|
}
|
|
1608
|
-
// Evaluate if autocapture should be enabled with new options
|
|
1609
1632
|
const autoTrackPageviews = effectiveOptions.autoTrackPageviews !== false;
|
|
1610
1633
|
const autocaptureEnabled = effectiveOptions.autocapture !== false;
|
|
1611
|
-
// Update autocapture tracker options
|
|
1612
1634
|
const autocaptureOptions = this.resolveAutocaptureOptions(effectiveOptions.autocapture);
|
|
1613
1635
|
this.autocaptureTracker.updateOptions(autocaptureOptions);
|
|
1614
|
-
// Start autocapture based on new options (even if it wasn't started before)
|
|
1615
1636
|
if (autoTrackPageviews) {
|
|
1616
|
-
this.pageviewTracker.startAutoPageviewTracking();
|
|
1637
|
+
this.pageviewTracker.startAutoPageviewTracking(isFirstStart);
|
|
1617
1638
|
}
|
|
1618
1639
|
if (autocaptureEnabled) {
|
|
1619
1640
|
this.autocaptureTracker.start();
|