@journium/js 1.1.1 → 1.2.1
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 +136 -111
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +12 -2
- package/dist/index.mjs +136 -111
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +136 -111
- package/dist/index.umd.js.map +1 -1
- package/dist/journium.js +136 -111
- 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 +4 -4
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* uuidv7: A JavaScript implementation of UUID version 7
|
|
3
3
|
*
|
|
4
|
-
* Copyright 2021-
|
|
4
|
+
* Copyright 2021-2025 LiosK
|
|
5
5
|
*
|
|
6
6
|
* @license Apache-2.0
|
|
7
7
|
* @packageDocumentation
|
|
@@ -230,7 +230,10 @@ class V7Generator {
|
|
|
230
230
|
* number generator should be cryptographically strong and securely seeded.
|
|
231
231
|
*/
|
|
232
232
|
constructor(randomNumberGenerator) {
|
|
233
|
-
|
|
233
|
+
/**
|
|
234
|
+
* Biased by one to distinguish zero (uninitialized) and zero (UNIX epoch).
|
|
235
|
+
*/
|
|
236
|
+
this.timestamp_biased = 0;
|
|
234
237
|
this.counter = 0;
|
|
235
238
|
this.random = randomNumberGenerator !== null && randomNumberGenerator !== void 0 ? randomNumberGenerator : getDefaultRandom();
|
|
236
239
|
}
|
|
@@ -276,13 +279,13 @@ class V7Generator {
|
|
|
276
279
|
*
|
|
277
280
|
* @param rollbackAllowance - The amount of `unixTsMs` rollback that is
|
|
278
281
|
* considered significant. A suggested value is `10_000` (milliseconds).
|
|
279
|
-
* @throws RangeError if `unixTsMs` is not a 48-bit
|
|
282
|
+
* @throws RangeError if `unixTsMs` is not a 48-bit unsigned integer.
|
|
280
283
|
*/
|
|
281
284
|
generateOrResetCore(unixTsMs, rollbackAllowance) {
|
|
282
285
|
let value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
|
|
283
286
|
if (value === undefined) {
|
|
284
287
|
// reset state and resume
|
|
285
|
-
this.
|
|
288
|
+
this.timestamp_biased = 0;
|
|
286
289
|
value = this.generateOrAbortCore(unixTsMs, rollbackAllowance);
|
|
287
290
|
}
|
|
288
291
|
return value;
|
|
@@ -296,28 +299,29 @@ class V7Generator {
|
|
|
296
299
|
*
|
|
297
300
|
* @param rollbackAllowance - The amount of `unixTsMs` rollback that is
|
|
298
301
|
* considered significant. A suggested value is `10_000` (milliseconds).
|
|
299
|
-
* @throws RangeError if `unixTsMs` is not a 48-bit
|
|
302
|
+
* @throws RangeError if `unixTsMs` is not a 48-bit unsigned integer.
|
|
300
303
|
*/
|
|
301
304
|
generateOrAbortCore(unixTsMs, rollbackAllowance) {
|
|
302
305
|
const MAX_COUNTER = 4398046511103;
|
|
303
306
|
if (!Number.isInteger(unixTsMs) ||
|
|
304
|
-
unixTsMs <
|
|
307
|
+
unixTsMs < 0 ||
|
|
305
308
|
unixTsMs > 281474976710655) {
|
|
306
|
-
throw new RangeError("`unixTsMs` must be a 48-bit
|
|
309
|
+
throw new RangeError("`unixTsMs` must be a 48-bit unsigned integer");
|
|
307
310
|
}
|
|
308
311
|
else if (rollbackAllowance < 0 || rollbackAllowance > 281474976710655) {
|
|
309
312
|
throw new RangeError("`rollbackAllowance` out of reasonable range");
|
|
310
313
|
}
|
|
311
|
-
|
|
312
|
-
|
|
314
|
+
unixTsMs++;
|
|
315
|
+
if (unixTsMs > this.timestamp_biased) {
|
|
316
|
+
this.timestamp_biased = unixTsMs;
|
|
313
317
|
this.resetCounter();
|
|
314
318
|
}
|
|
315
|
-
else if (unixTsMs + rollbackAllowance >= this.
|
|
319
|
+
else if (unixTsMs + rollbackAllowance >= this.timestamp_biased) {
|
|
316
320
|
// go on with previous timestamp if new one is not much smaller
|
|
317
321
|
this.counter++;
|
|
318
322
|
if (this.counter > MAX_COUNTER) {
|
|
319
323
|
// increment timestamp at counter overflow
|
|
320
|
-
this.
|
|
324
|
+
this.timestamp_biased++;
|
|
321
325
|
this.resetCounter();
|
|
322
326
|
}
|
|
323
327
|
}
|
|
@@ -325,7 +329,7 @@ class V7Generator {
|
|
|
325
329
|
// abort if clock went backwards to unbearable extent
|
|
326
330
|
return undefined;
|
|
327
331
|
}
|
|
328
|
-
return UUID.fromFieldsV7(this.
|
|
332
|
+
return UUID.fromFieldsV7(this.timestamp_biased - 1, Math.trunc(this.counter / 2 ** 30), this.counter & (2 ** 30 - 1), this.random.nextUint32());
|
|
329
333
|
}
|
|
330
334
|
/** Initializes the counter at a 42-bit random integer. */
|
|
331
335
|
resetCounter() {
|
|
@@ -701,6 +705,9 @@ class JourniumClient {
|
|
|
701
705
|
this.queue = [];
|
|
702
706
|
this.stagedEvents = [];
|
|
703
707
|
this.flushTimer = null;
|
|
708
|
+
this.remoteOptionsRefreshTimer = null;
|
|
709
|
+
this.isRefreshing = false;
|
|
710
|
+
this.lastRemoteOptions = null;
|
|
704
711
|
this.initializationComplete = false;
|
|
705
712
|
this.initializationFailed = false;
|
|
706
713
|
this.optionsChangeCallbacks = new Set();
|
|
@@ -754,61 +761,24 @@ class JourniumClient {
|
|
|
754
761
|
}
|
|
755
762
|
}
|
|
756
763
|
async initializeAsync() {
|
|
757
|
-
var _a;
|
|
758
764
|
try {
|
|
759
765
|
Logger.log('Journium: Starting initialization - fetching fresh remote config...');
|
|
760
|
-
// Step 1: Try to fetch fresh remote config with timeout and retry
|
|
761
766
|
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);
|
|
767
|
+
if (!remoteOptions) {
|
|
768
|
+
Logger.error('Journium: Initialization failed - no remote config available');
|
|
769
|
+
this.initializationFailed = true;
|
|
770
|
+
return;
|
|
798
771
|
}
|
|
799
|
-
|
|
800
|
-
Logger.
|
|
801
|
-
// Step 8: Mark initialization as complete
|
|
772
|
+
this.applyRemoteOptions(remoteOptions);
|
|
773
|
+
Logger.log('Journium: Effective options after init:', this.effectiveOptions);
|
|
802
774
|
this.initializationComplete = true;
|
|
803
775
|
this.initializationFailed = false;
|
|
804
|
-
// Step 9: Process any staged events
|
|
805
776
|
this.processStagedEvents();
|
|
806
|
-
// Step 10: Start flush timer
|
|
807
777
|
if (this.effectiveOptions.flushInterval && this.effectiveOptions.flushInterval > 0) {
|
|
808
778
|
this.startFlushTimer();
|
|
809
779
|
}
|
|
810
|
-
|
|
811
|
-
|
|
780
|
+
this.startRemoteOptionsRefreshTimer();
|
|
781
|
+
Logger.log('Journium: Initialization complete');
|
|
812
782
|
this.notifyOptionsChange();
|
|
813
783
|
}
|
|
814
784
|
catch (error) {
|
|
@@ -879,35 +849,21 @@ class JourniumClient {
|
|
|
879
849
|
processStagedEvents() {
|
|
880
850
|
if (this.stagedEvents.length === 0)
|
|
881
851
|
return;
|
|
852
|
+
if (this.ingestionPaused) {
|
|
853
|
+
Logger.warn(`Journium: Ingestion is paused — discarding ${this.stagedEvents.length} staged events`);
|
|
854
|
+
this.stagedEvents = [];
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
882
857
|
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
858
|
for (const stagedEvent of this.stagedEvents) {
|
|
887
|
-
|
|
888
|
-
const eventWithIdentity = {
|
|
859
|
+
this.queue.push({
|
|
889
860
|
...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);
|
|
861
|
+
properties: this.buildIdentityProperties(stagedEvent.properties),
|
|
862
|
+
});
|
|
904
863
|
}
|
|
905
|
-
// Clear staged events
|
|
906
864
|
this.stagedEvents = [];
|
|
907
865
|
Logger.log('Journium: Staged events processed and moved to main queue');
|
|
908
|
-
// Check if we should flush immediately
|
|
909
866
|
if (this.queue.length >= this.effectiveOptions.flushAt) {
|
|
910
|
-
// console.log('1 Journium: Flushing events...'+JSON.stringify(this.effectiveOptions));
|
|
911
867
|
this.flush();
|
|
912
868
|
}
|
|
913
869
|
}
|
|
@@ -915,12 +871,88 @@ class JourniumClient {
|
|
|
915
871
|
if (this.flushTimer) {
|
|
916
872
|
clearInterval(this.flushTimer);
|
|
917
873
|
}
|
|
918
|
-
// Use universal setInterval (works in both browser and Node.js)
|
|
919
874
|
this.flushTimer = setInterval(() => {
|
|
920
|
-
// console.log('2 Journium: Flushing events...'+JSON.stringify(this.effectiveOptions));
|
|
921
875
|
this.flush();
|
|
922
876
|
}, this.effectiveOptions.flushInterval);
|
|
923
877
|
}
|
|
878
|
+
startRemoteOptionsRefreshTimer() {
|
|
879
|
+
// Clear any existing timer to prevent duplicate intervals
|
|
880
|
+
if (this.remoteOptionsRefreshTimer) {
|
|
881
|
+
clearInterval(this.remoteOptionsRefreshTimer);
|
|
882
|
+
this.remoteOptionsRefreshTimer = null;
|
|
883
|
+
}
|
|
884
|
+
this.remoteOptionsRefreshTimer = setInterval(() => {
|
|
885
|
+
this.refreshRemoteOptions();
|
|
886
|
+
}, JourniumClient.REMOTE_OPTIONS_REFRESH_INTERVAL);
|
|
887
|
+
Logger.log(`Journium: Scheduling remote options refresh every ${JourniumClient.REMOTE_OPTIONS_REFRESH_INTERVAL}ms`);
|
|
888
|
+
}
|
|
889
|
+
async refreshRemoteOptions() {
|
|
890
|
+
if (this.isRefreshing) {
|
|
891
|
+
Logger.log('Journium: Remote options refresh already in progress, skipping');
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
this.isRefreshing = true;
|
|
895
|
+
Logger.log('Journium: Periodic remote options refresh triggered');
|
|
896
|
+
try {
|
|
897
|
+
const remoteOptions = await this.fetchRemoteOptionsWithRetry();
|
|
898
|
+
if (!remoteOptions) {
|
|
899
|
+
Logger.warn('Journium: Periodic remote options refresh failed, keeping current options');
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
const prevRemoteSnapshot = JSON.stringify(this.lastRemoteOptions);
|
|
903
|
+
const prevFlushInterval = this.effectiveOptions.flushInterval;
|
|
904
|
+
this.applyRemoteOptions(remoteOptions);
|
|
905
|
+
if (prevRemoteSnapshot === JSON.stringify(this.lastRemoteOptions)) {
|
|
906
|
+
Logger.log('Journium: Remote options unchanged after refresh, no update needed');
|
|
907
|
+
return;
|
|
908
|
+
}
|
|
909
|
+
Logger.log('Journium: Remote options updated after refresh:', this.effectiveOptions);
|
|
910
|
+
if (this.effectiveOptions.flushInterval !== prevFlushInterval) {
|
|
911
|
+
if (this.effectiveOptions.flushInterval && this.effectiveOptions.flushInterval > 0) {
|
|
912
|
+
this.startFlushTimer();
|
|
913
|
+
}
|
|
914
|
+
else if (this.flushTimer) {
|
|
915
|
+
clearInterval(this.flushTimer);
|
|
916
|
+
this.flushTimer = null;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
this.notifyOptionsChange();
|
|
920
|
+
}
|
|
921
|
+
catch (error) {
|
|
922
|
+
Logger.error('Journium: Periodic remote options refresh encountered an error:', error);
|
|
923
|
+
}
|
|
924
|
+
finally {
|
|
925
|
+
this.isRefreshing = false;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
applyRemoteOptions(remoteOptions) {
|
|
929
|
+
var _a;
|
|
930
|
+
this.lastRemoteOptions = remoteOptions;
|
|
931
|
+
this.effectiveOptions = this.config.options
|
|
932
|
+
? mergeOptions(this.config.options, remoteOptions)
|
|
933
|
+
: remoteOptions;
|
|
934
|
+
this.saveCachedOptions(remoteOptions);
|
|
935
|
+
if (this.effectiveOptions.sessionTimeout) {
|
|
936
|
+
this.identityManager.updateSessionTimeout(this.effectiveOptions.sessionTimeout);
|
|
937
|
+
}
|
|
938
|
+
Logger.setDebug((_a = this.effectiveOptions.debug) !== null && _a !== void 0 ? _a : false);
|
|
939
|
+
}
|
|
940
|
+
buildIdentityProperties(userProperties = {}) {
|
|
941
|
+
const identity = this.identityManager.getIdentity();
|
|
942
|
+
const userAgentInfo = this.identityManager.getUserAgentInfo();
|
|
943
|
+
return {
|
|
944
|
+
$device_id: identity === null || identity === void 0 ? void 0 : identity.$device_id,
|
|
945
|
+
distinct_id: identity === null || identity === void 0 ? void 0 : identity.distinct_id,
|
|
946
|
+
$session_id: identity === null || identity === void 0 ? void 0 : identity.$session_id,
|
|
947
|
+
$is_identified: (identity === null || identity === void 0 ? void 0 : identity.$user_state) === 'identified',
|
|
948
|
+
$current_url: typeof window !== 'undefined' ? window.location.href : '',
|
|
949
|
+
$pathname: typeof window !== 'undefined' ? window.location.pathname : '',
|
|
950
|
+
...userAgentInfo,
|
|
951
|
+
$lib_version: '0.1.0', // TODO: Get from package.json
|
|
952
|
+
$platform: 'web',
|
|
953
|
+
...userProperties,
|
|
954
|
+
};
|
|
955
|
+
}
|
|
924
956
|
async sendEvents(events) {
|
|
925
957
|
if (!events.length)
|
|
926
958
|
return;
|
|
@@ -980,9 +1012,7 @@ class JourniumClient {
|
|
|
980
1012
|
event,
|
|
981
1013
|
properties: { ...properties }, // Only user properties for now
|
|
982
1014
|
};
|
|
983
|
-
// Stage events during initialization, add to queue after initialization
|
|
984
1015
|
if (!this.initializationComplete) {
|
|
985
|
-
// If initialization failed, reject events
|
|
986
1016
|
if (this.initializationFailed) {
|
|
987
1017
|
Logger.warn('Journium: track() call rejected - initialization failed');
|
|
988
1018
|
return;
|
|
@@ -991,34 +1021,17 @@ class JourniumClient {
|
|
|
991
1021
|
Logger.log('Journium: Event staged during initialization', journiumEvent);
|
|
992
1022
|
return;
|
|
993
1023
|
}
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
Logger.warn('Journium: track() call rejected - initialization failed');
|
|
1024
|
+
if (this.ingestionPaused) {
|
|
1025
|
+
Logger.warn('Journium: Ingestion is paused — event dropped:', journiumEvent.event);
|
|
997
1026
|
return;
|
|
998
1027
|
}
|
|
999
|
-
// Add identity properties for immediate events (after initialization)
|
|
1000
|
-
const identity = this.identityManager.getIdentity();
|
|
1001
|
-
const userAgentInfo = this.identityManager.getUserAgentInfo();
|
|
1002
1028
|
const eventWithIdentity = {
|
|
1003
1029
|
...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
|
-
},
|
|
1030
|
+
properties: this.buildIdentityProperties(properties),
|
|
1016
1031
|
};
|
|
1017
1032
|
this.queue.push(eventWithIdentity);
|
|
1018
1033
|
Logger.log('Journium: Event tracked', eventWithIdentity);
|
|
1019
|
-
// Only flush if we have effective options (after initialization)
|
|
1020
1034
|
if (this.effectiveOptions.flushAt && this.queue.length >= this.effectiveOptions.flushAt) {
|
|
1021
|
-
// console.log('3 Journium: Flushing events...'+JSON.stringify(this.effectiveOptions));
|
|
1022
1035
|
this.flush();
|
|
1023
1036
|
}
|
|
1024
1037
|
}
|
|
@@ -1045,12 +1058,20 @@ class JourniumClient {
|
|
|
1045
1058
|
clearInterval(this.flushTimer);
|
|
1046
1059
|
this.flushTimer = null;
|
|
1047
1060
|
}
|
|
1061
|
+
if (this.remoteOptionsRefreshTimer) {
|
|
1062
|
+
clearInterval(this.remoteOptionsRefreshTimer);
|
|
1063
|
+
this.remoteOptionsRefreshTimer = null;
|
|
1064
|
+
}
|
|
1048
1065
|
this.flush();
|
|
1049
1066
|
}
|
|
1050
1067
|
getEffectiveOptions() {
|
|
1051
1068
|
return this.effectiveOptions;
|
|
1052
1069
|
}
|
|
1070
|
+
get ingestionPaused() {
|
|
1071
|
+
return this.effectiveOptions['ingestionPaused'] === true;
|
|
1072
|
+
}
|
|
1053
1073
|
}
|
|
1074
|
+
JourniumClient.REMOTE_OPTIONS_REFRESH_INTERVAL = 15 * 60 * 1000; // 15 minutes
|
|
1054
1075
|
|
|
1055
1076
|
class PageviewTracker {
|
|
1056
1077
|
constructor(client) {
|
|
@@ -1077,10 +1098,13 @@ class PageviewTracker {
|
|
|
1077
1098
|
}
|
|
1078
1099
|
/**
|
|
1079
1100
|
* Start automatic autocapture for pageviews
|
|
1080
|
-
* @
|
|
1101
|
+
* @param captureInitialPageview - whether to fire a $pageview immediately on start (default: true).
|
|
1102
|
+
* Pass false when restarting after a remote options update to avoid a spurious pageview.
|
|
1081
1103
|
*/
|
|
1082
|
-
startAutoPageviewTracking() {
|
|
1083
|
-
|
|
1104
|
+
startAutoPageviewTracking(captureInitialPageview = true) {
|
|
1105
|
+
if (captureInitialPageview) {
|
|
1106
|
+
this.capturePageview();
|
|
1107
|
+
}
|
|
1084
1108
|
if (typeof window !== 'undefined') {
|
|
1085
1109
|
// Store original methods for cleanup
|
|
1086
1110
|
this.originalPushState = window.history.pushState;
|
|
@@ -1599,21 +1623,22 @@ class JourniumAnalytics {
|
|
|
1599
1623
|
* Handle effective options change (e.g., when remote options are fetched)
|
|
1600
1624
|
*/
|
|
1601
1625
|
handleOptionsChange(effectiveOptions) {
|
|
1602
|
-
//
|
|
1626
|
+
// If autocapture was never started before, this is the initial options application
|
|
1627
|
+
// (async init completed) — treat it like a page load and capture a pageview.
|
|
1628
|
+
// If it was already started, this is a periodic remote options update — only
|
|
1629
|
+
// re-register listeners without emitting a spurious pageview.
|
|
1630
|
+
const isFirstStart = !this.autocaptureStarted;
|
|
1603
1631
|
if (this.autocaptureStarted) {
|
|
1604
1632
|
this.pageviewTracker.stopAutocapture();
|
|
1605
1633
|
this.autocaptureTracker.stop();
|
|
1606
1634
|
this.autocaptureStarted = false;
|
|
1607
1635
|
}
|
|
1608
|
-
// Evaluate if autocapture should be enabled with new options
|
|
1609
1636
|
const autoTrackPageviews = effectiveOptions.autoTrackPageviews !== false;
|
|
1610
1637
|
const autocaptureEnabled = effectiveOptions.autocapture !== false;
|
|
1611
|
-
// Update autocapture tracker options
|
|
1612
1638
|
const autocaptureOptions = this.resolveAutocaptureOptions(effectiveOptions.autocapture);
|
|
1613
1639
|
this.autocaptureTracker.updateOptions(autocaptureOptions);
|
|
1614
|
-
// Start autocapture based on new options (even if it wasn't started before)
|
|
1615
1640
|
if (autoTrackPageviews) {
|
|
1616
|
-
this.pageviewTracker.startAutoPageviewTracking();
|
|
1641
|
+
this.pageviewTracker.startAutoPageviewTracking(isFirstStart);
|
|
1617
1642
|
}
|
|
1618
1643
|
if (autocaptureEnabled) {
|
|
1619
1644
|
this.autocaptureTracker.start();
|