@journium/react 1.1.0 → 1.1.2
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 +3 -2
- package/dist/context.d.ts.map +1 -1
- package/dist/index.cjs +136 -136
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.mjs +137 -136
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/context.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import React, { ReactNode } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { init } from '@journium/js';
|
|
3
3
|
import { JourniumConfig, JourniumLocalOptions } from '@journium/core';
|
|
4
|
+
type JourniumAnalyticsInstance = ReturnType<typeof init>;
|
|
4
5
|
interface JourniumContextValue {
|
|
5
|
-
analytics:
|
|
6
|
+
analytics: JourniumAnalyticsInstance | null;
|
|
6
7
|
config: JourniumConfig | null;
|
|
7
8
|
effectiveOptions: JourniumLocalOptions | null;
|
|
8
9
|
}
|
package/dist/context.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAkD,SAAS,EAAE,MAAM,OAAO,CAAC;AACzF,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAkD,SAAS,EAAE,MAAM,OAAO,CAAC;AACzF,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEtE,KAAK,yBAAyB,GAAG,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC;AAEzD,UAAU,oBAAoB;IAC5B,SAAS,EAAE,yBAAyB,GAAG,IAAI,CAAC;IAC5C,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IAC9B,gBAAgB,EAAE,oBAAoB,GAAG,IAAI,CAAC;CAC/C;AAID,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAuC5D,CAAC;AAEF,eAAO,MAAM,WAAW,QAAO,oBAM9B,CAAC"}
|
package/dist/index.cjs
CHANGED
|
@@ -450,9 +450,9 @@ const fetchRemoteOptions = async (apiHost, publishableKey, fetchFn) => {
|
|
|
450
450
|
'Content-Type': 'application/json',
|
|
451
451
|
},
|
|
452
452
|
});
|
|
453
|
-
if (!response.ok) {
|
|
454
|
-
|
|
455
|
-
}
|
|
453
|
+
// if (!response.ok) {
|
|
454
|
+
// throw new Error(`Options fetch failed: ${response.status} ${response.statusText}`);
|
|
455
|
+
// }
|
|
456
456
|
const data = await response.json();
|
|
457
457
|
return data;
|
|
458
458
|
}
|
|
@@ -705,20 +705,19 @@ class JourniumClient {
|
|
|
705
705
|
this.queue = [];
|
|
706
706
|
this.stagedEvents = [];
|
|
707
707
|
this.flushTimer = null;
|
|
708
|
+
this.remoteOptionsRefreshTimer = null;
|
|
709
|
+
this.isRefreshing = false;
|
|
710
|
+
this.lastRemoteOptions = null;
|
|
708
711
|
this.initializationComplete = false;
|
|
709
712
|
this.initializationFailed = false;
|
|
710
|
-
this.disabled = false;
|
|
711
713
|
this.optionsChangeCallbacks = new Set();
|
|
712
|
-
// Validate required configuration
|
|
714
|
+
// Validate required configuration
|
|
713
715
|
if (!config.publishableKey || config.publishableKey.trim() === '') {
|
|
714
|
-
|
|
716
|
+
// Reject initialization with clear error
|
|
717
|
+
const errorMsg = 'Journium: publishableKey is required but not provided or is empty. SDK cannot be initialized.';
|
|
715
718
|
Logger.setDebug(true);
|
|
716
|
-
Logger.error(
|
|
717
|
-
|
|
718
|
-
this.config = { publishableKey: '', apiHost: 'https://events.journium.app' };
|
|
719
|
-
this.effectiveOptions = { debug: true };
|
|
720
|
-
this.optionsStorageKey = 'jrnm_invalid_options';
|
|
721
|
-
return;
|
|
719
|
+
Logger.error(errorMsg);
|
|
720
|
+
throw new Error(errorMsg);
|
|
722
721
|
}
|
|
723
722
|
// Set default apiHost if not provided
|
|
724
723
|
this.config = {
|
|
@@ -762,62 +761,24 @@ class JourniumClient {
|
|
|
762
761
|
}
|
|
763
762
|
}
|
|
764
763
|
async initializeAsync() {
|
|
765
|
-
var _a;
|
|
766
764
|
try {
|
|
767
765
|
Logger.log('Journium: Starting initialization - fetching fresh remote config...');
|
|
768
|
-
// Step 1: Try to fetch fresh remote config with timeout and retry
|
|
769
766
|
const remoteOptions = await this.fetchRemoteOptionsWithRetry();
|
|
770
|
-
if (remoteOptions) {
|
|
771
|
-
|
|
772
|
-
this.
|
|
773
|
-
|
|
774
|
-
if (this.config.options) {
|
|
775
|
-
this.effectiveOptions = mergeOptions(this.config.options, remoteOptions);
|
|
776
|
-
Logger.log('Journium: Using fresh remote config merged with local options:', this.effectiveOptions);
|
|
777
|
-
}
|
|
778
|
-
else {
|
|
779
|
-
this.effectiveOptions = remoteOptions;
|
|
780
|
-
Logger.log('Journium: Using fresh remote config:', this.effectiveOptions);
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
else {
|
|
784
|
-
// Step 4: Fallback to cached config if fresh fetch failed
|
|
785
|
-
const cachedRemoteOptions = this.loadCachedOptions();
|
|
786
|
-
if (cachedRemoteOptions) {
|
|
787
|
-
if (this.config.options) {
|
|
788
|
-
this.effectiveOptions = mergeOptions(this.config.options, cachedRemoteOptions);
|
|
789
|
-
Logger.log('Journium: Fresh config failed, using cached remote config merged with local options:', this.effectiveOptions);
|
|
790
|
-
}
|
|
791
|
-
else {
|
|
792
|
-
this.effectiveOptions = cachedRemoteOptions;
|
|
793
|
-
Logger.log('Journium: Fresh config failed, using cached remote config:', this.effectiveOptions);
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
else {
|
|
797
|
-
// Step 5: No remote config and no cached config - initialization fails
|
|
798
|
-
Logger.error('Journium: Initialization failed - no remote config available and no cached config found');
|
|
799
|
-
this.initializationFailed = true;
|
|
800
|
-
this.initializationComplete = false;
|
|
801
|
-
return;
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
// Step 6: Update identity manager session timeout if provided
|
|
805
|
-
if (this.effectiveOptions.sessionTimeout) {
|
|
806
|
-
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;
|
|
807
771
|
}
|
|
808
|
-
|
|
809
|
-
Logger.
|
|
810
|
-
// Step 8: Mark initialization as complete
|
|
772
|
+
this.applyRemoteOptions(remoteOptions);
|
|
773
|
+
Logger.log('Journium: Effective options after init:', this.effectiveOptions);
|
|
811
774
|
this.initializationComplete = true;
|
|
812
775
|
this.initializationFailed = false;
|
|
813
|
-
// Step 9: Process any staged events
|
|
814
776
|
this.processStagedEvents();
|
|
815
|
-
// Step 10: Start flush timer
|
|
816
777
|
if (this.effectiveOptions.flushInterval && this.effectiveOptions.flushInterval > 0) {
|
|
817
778
|
this.startFlushTimer();
|
|
818
779
|
}
|
|
819
|
-
|
|
820
|
-
|
|
780
|
+
this.startRemoteOptionsRefreshTimer();
|
|
781
|
+
Logger.log('Journium: Initialization complete');
|
|
821
782
|
this.notifyOptionsChange();
|
|
822
783
|
}
|
|
823
784
|
catch (error) {
|
|
@@ -839,11 +800,15 @@ class JourniumClient {
|
|
|
839
800
|
// Race fetch against timeout
|
|
840
801
|
const fetchPromise = fetchRemoteOptions(this.config.apiHost, this.config.publishableKey);
|
|
841
802
|
const remoteOptionsResponse = await Promise.race([fetchPromise, timeoutPromise]);
|
|
842
|
-
if (remoteOptionsResponse && remoteOptionsResponse.success) {
|
|
803
|
+
if (remoteOptionsResponse && remoteOptionsResponse.status === 'success') {
|
|
843
804
|
Logger.log('Journium: Successfully fetched fresh remote config:', remoteOptionsResponse.config);
|
|
844
|
-
return remoteOptionsResponse.config;
|
|
805
|
+
return remoteOptionsResponse.config || null;
|
|
845
806
|
}
|
|
846
|
-
else {
|
|
807
|
+
else if (remoteOptionsResponse && remoteOptionsResponse.status === 'error' && remoteOptionsResponse.errorCode === 'J_ERR_TENANT_NOT_FOUND') {
|
|
808
|
+
Logger.error('Journium: Invalid publishableKey is being used.');
|
|
809
|
+
return null;
|
|
810
|
+
}
|
|
811
|
+
{
|
|
847
812
|
throw new Error('Remote config fetch unsuccessful');
|
|
848
813
|
}
|
|
849
814
|
}
|
|
@@ -884,35 +849,21 @@ class JourniumClient {
|
|
|
884
849
|
processStagedEvents() {
|
|
885
850
|
if (this.stagedEvents.length === 0)
|
|
886
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
|
+
}
|
|
887
857
|
Logger.log(`Journium: Processing ${this.stagedEvents.length} staged events`);
|
|
888
|
-
// Move staged events to main queue, adding identity properties now
|
|
889
|
-
const identity = this.identityManager.getIdentity();
|
|
890
|
-
const userAgentInfo = this.identityManager.getUserAgentInfo();
|
|
891
858
|
for (const stagedEvent of this.stagedEvents) {
|
|
892
|
-
|
|
893
|
-
const eventWithIdentity = {
|
|
859
|
+
this.queue.push({
|
|
894
860
|
...stagedEvent,
|
|
895
|
-
properties:
|
|
896
|
-
|
|
897
|
-
distinct_id: identity === null || identity === void 0 ? void 0 : identity.distinct_id,
|
|
898
|
-
$session_id: identity === null || identity === void 0 ? void 0 : identity.$session_id,
|
|
899
|
-
$is_identified: (identity === null || identity === void 0 ? void 0 : identity.$user_state) === 'identified',
|
|
900
|
-
$current_url: typeof window !== 'undefined' ? window.location.href : '',
|
|
901
|
-
$pathname: typeof window !== 'undefined' ? window.location.pathname : '',
|
|
902
|
-
...userAgentInfo,
|
|
903
|
-
$lib_version: '0.1.0', // TODO: Get from package.json
|
|
904
|
-
$platform: 'web',
|
|
905
|
-
...stagedEvent.properties, // Original properties override system properties
|
|
906
|
-
},
|
|
907
|
-
};
|
|
908
|
-
this.queue.push(eventWithIdentity);
|
|
861
|
+
properties: this.buildIdentityProperties(stagedEvent.properties),
|
|
862
|
+
});
|
|
909
863
|
}
|
|
910
|
-
// Clear staged events
|
|
911
864
|
this.stagedEvents = [];
|
|
912
865
|
Logger.log('Journium: Staged events processed and moved to main queue');
|
|
913
|
-
// Check if we should flush immediately
|
|
914
866
|
if (this.queue.length >= this.effectiveOptions.flushAt) {
|
|
915
|
-
// console.log('1 Journium: Flushing events...'+JSON.stringify(this.effectiveOptions));
|
|
916
867
|
this.flush();
|
|
917
868
|
}
|
|
918
869
|
}
|
|
@@ -920,12 +871,88 @@ class JourniumClient {
|
|
|
920
871
|
if (this.flushTimer) {
|
|
921
872
|
clearInterval(this.flushTimer);
|
|
922
873
|
}
|
|
923
|
-
// Use universal setInterval (works in both browser and Node.js)
|
|
924
874
|
this.flushTimer = setInterval(() => {
|
|
925
|
-
// console.log('2 Journium: Flushing events...'+JSON.stringify(this.effectiveOptions));
|
|
926
875
|
this.flush();
|
|
927
876
|
}, this.effectiveOptions.flushInterval);
|
|
928
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
|
+
}
|
|
929
956
|
async sendEvents(events) {
|
|
930
957
|
if (!events.length)
|
|
931
958
|
return;
|
|
@@ -951,11 +978,6 @@ class JourniumClient {
|
|
|
951
978
|
}
|
|
952
979
|
}
|
|
953
980
|
identify(distinctId, attributes = {}) {
|
|
954
|
-
// Don't identify if SDK is not properly configured or disabled
|
|
955
|
-
if (this.disabled || !this.config || !this.config.publishableKey) {
|
|
956
|
-
Logger.warn('Journium: identify() call rejected - SDK not ready or disabled');
|
|
957
|
-
return;
|
|
958
|
-
}
|
|
959
981
|
// Don't identify if initialization failed
|
|
960
982
|
if (this.initializationFailed) {
|
|
961
983
|
Logger.warn('Journium: identify() call rejected - initialization failed');
|
|
@@ -972,11 +994,6 @@ class JourniumClient {
|
|
|
972
994
|
Logger.log('Journium: User identified', { distinctId, attributes, previousDistinctId });
|
|
973
995
|
}
|
|
974
996
|
reset() {
|
|
975
|
-
// Don't reset if SDK is not properly configured or disabled
|
|
976
|
-
if (this.disabled || !this.config || !this.config.publishableKey) {
|
|
977
|
-
Logger.warn('Journium: reset() call rejected - SDK not ready or disabled');
|
|
978
|
-
return;
|
|
979
|
-
}
|
|
980
997
|
// Don't reset if initialization failed
|
|
981
998
|
if (this.initializationFailed) {
|
|
982
999
|
Logger.warn('Journium: reset() call rejected - initialization failed');
|
|
@@ -987,11 +1004,6 @@ class JourniumClient {
|
|
|
987
1004
|
Logger.log('Journium: User identity reset');
|
|
988
1005
|
}
|
|
989
1006
|
track(event, properties = {}) {
|
|
990
|
-
// Don't track if SDK is not properly configured or disabled
|
|
991
|
-
if (this.disabled || !this.config || !this.config.publishableKey) {
|
|
992
|
-
Logger.warn('Journium: track() call rejected - SDK not ready or disabled');
|
|
993
|
-
return;
|
|
994
|
-
}
|
|
995
1007
|
// Create minimal event without identity properties (will be added later if staging)
|
|
996
1008
|
const journiumEvent = {
|
|
997
1009
|
uuid: generateUuidv7(),
|
|
@@ -1000,9 +1012,7 @@ class JourniumClient {
|
|
|
1000
1012
|
event,
|
|
1001
1013
|
properties: { ...properties }, // Only user properties for now
|
|
1002
1014
|
};
|
|
1003
|
-
// Stage events during initialization, add to queue after initialization
|
|
1004
1015
|
if (!this.initializationComplete) {
|
|
1005
|
-
// If initialization failed, reject events
|
|
1006
1016
|
if (this.initializationFailed) {
|
|
1007
1017
|
Logger.warn('Journium: track() call rejected - initialization failed');
|
|
1008
1018
|
return;
|
|
@@ -1011,42 +1021,21 @@ class JourniumClient {
|
|
|
1011
1021
|
Logger.log('Journium: Event staged during initialization', journiumEvent);
|
|
1012
1022
|
return;
|
|
1013
1023
|
}
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
Logger.warn('Journium: track() call rejected - initialization failed');
|
|
1024
|
+
if (this.ingestionPaused) {
|
|
1025
|
+
Logger.warn('Journium: Ingestion is paused — event dropped:', journiumEvent.event);
|
|
1017
1026
|
return;
|
|
1018
1027
|
}
|
|
1019
|
-
// Add identity properties for immediate events (after initialization)
|
|
1020
|
-
const identity = this.identityManager.getIdentity();
|
|
1021
|
-
const userAgentInfo = this.identityManager.getUserAgentInfo();
|
|
1022
1028
|
const eventWithIdentity = {
|
|
1023
1029
|
...journiumEvent,
|
|
1024
|
-
properties:
|
|
1025
|
-
$device_id: identity === null || identity === void 0 ? void 0 : identity.$device_id,
|
|
1026
|
-
distinct_id: identity === null || identity === void 0 ? void 0 : identity.distinct_id,
|
|
1027
|
-
$session_id: identity === null || identity === void 0 ? void 0 : identity.$session_id,
|
|
1028
|
-
$is_identified: (identity === null || identity === void 0 ? void 0 : identity.$user_state) === 'identified',
|
|
1029
|
-
$current_url: typeof window !== 'undefined' ? window.location.href : '',
|
|
1030
|
-
$pathname: typeof window !== 'undefined' ? window.location.pathname : '',
|
|
1031
|
-
...userAgentInfo,
|
|
1032
|
-
$lib_version: '0.1.0', // TODO: Get from package.json
|
|
1033
|
-
$platform: 'web',
|
|
1034
|
-
...properties, // User-provided properties override system properties
|
|
1035
|
-
},
|
|
1030
|
+
properties: this.buildIdentityProperties(properties),
|
|
1036
1031
|
};
|
|
1037
1032
|
this.queue.push(eventWithIdentity);
|
|
1038
1033
|
Logger.log('Journium: Event tracked', eventWithIdentity);
|
|
1039
|
-
// Only flush if we have effective options (after initialization)
|
|
1040
1034
|
if (this.effectiveOptions.flushAt && this.queue.length >= this.effectiveOptions.flushAt) {
|
|
1041
|
-
// console.log('3 Journium: Flushing events...'+JSON.stringify(this.effectiveOptions));
|
|
1042
1035
|
this.flush();
|
|
1043
1036
|
}
|
|
1044
1037
|
}
|
|
1045
1038
|
async flush() {
|
|
1046
|
-
// Don't flush if SDK is not properly configured
|
|
1047
|
-
if (!this.config || !this.config.publishableKey) {
|
|
1048
|
-
return;
|
|
1049
|
-
}
|
|
1050
1039
|
// Don't flush if initialization failed
|
|
1051
1040
|
if (this.initializationFailed) {
|
|
1052
1041
|
Logger.warn('Journium: flush() call rejected - initialization failed');
|
|
@@ -1069,12 +1058,20 @@ class JourniumClient {
|
|
|
1069
1058
|
clearInterval(this.flushTimer);
|
|
1070
1059
|
this.flushTimer = null;
|
|
1071
1060
|
}
|
|
1061
|
+
if (this.remoteOptionsRefreshTimer) {
|
|
1062
|
+
clearInterval(this.remoteOptionsRefreshTimer);
|
|
1063
|
+
this.remoteOptionsRefreshTimer = null;
|
|
1064
|
+
}
|
|
1072
1065
|
this.flush();
|
|
1073
1066
|
}
|
|
1074
1067
|
getEffectiveOptions() {
|
|
1075
1068
|
return this.effectiveOptions;
|
|
1076
1069
|
}
|
|
1070
|
+
get ingestionPaused() {
|
|
1071
|
+
return this.effectiveOptions['ingestionPaused'] === true;
|
|
1072
|
+
}
|
|
1077
1073
|
}
|
|
1074
|
+
JourniumClient.REMOTE_OPTIONS_REFRESH_INTERVAL = 15 * 60 * 1000; // 15 minutes
|
|
1078
1075
|
|
|
1079
1076
|
class PageviewTracker {
|
|
1080
1077
|
constructor(client) {
|
|
@@ -1101,10 +1098,13 @@ class PageviewTracker {
|
|
|
1101
1098
|
}
|
|
1102
1099
|
/**
|
|
1103
1100
|
* Start automatic autocapture for pageviews
|
|
1104
|
-
* @
|
|
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.
|
|
1105
1103
|
*/
|
|
1106
|
-
startAutoPageviewTracking() {
|
|
1107
|
-
|
|
1104
|
+
startAutoPageviewTracking(captureInitialPageview = true) {
|
|
1105
|
+
if (captureInitialPageview) {
|
|
1106
|
+
this.capturePageview();
|
|
1107
|
+
}
|
|
1108
1108
|
if (typeof window !== 'undefined') {
|
|
1109
1109
|
// Store original methods for cleanup
|
|
1110
1110
|
this.originalPushState = window.history.pushState;
|
|
@@ -1623,21 +1623,22 @@ class JourniumAnalytics {
|
|
|
1623
1623
|
* Handle effective options change (e.g., when remote options are fetched)
|
|
1624
1624
|
*/
|
|
1625
1625
|
handleOptionsChange(effectiveOptions) {
|
|
1626
|
-
//
|
|
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;
|
|
1627
1631
|
if (this.autocaptureStarted) {
|
|
1628
1632
|
this.pageviewTracker.stopAutocapture();
|
|
1629
1633
|
this.autocaptureTracker.stop();
|
|
1630
1634
|
this.autocaptureStarted = false;
|
|
1631
1635
|
}
|
|
1632
|
-
// Evaluate if autocapture should be enabled with new options
|
|
1633
1636
|
const autoTrackPageviews = effectiveOptions.autoTrackPageviews !== false;
|
|
1634
1637
|
const autocaptureEnabled = effectiveOptions.autocapture !== false;
|
|
1635
|
-
// Update autocapture tracker options
|
|
1636
1638
|
const autocaptureOptions = this.resolveAutocaptureOptions(effectiveOptions.autocapture);
|
|
1637
1639
|
this.autocaptureTracker.updateOptions(autocaptureOptions);
|
|
1638
|
-
// Start autocapture based on new options (even if it wasn't started before)
|
|
1639
1640
|
if (autoTrackPageviews) {
|
|
1640
|
-
this.pageviewTracker.startAutoPageviewTracking();
|
|
1641
|
+
this.pageviewTracker.startAutoPageviewTracking(isFirstStart);
|
|
1641
1642
|
}
|
|
1642
1643
|
if (autocaptureEnabled) {
|
|
1643
1644
|
this.autocaptureTracker.start();
|
|
@@ -1674,7 +1675,7 @@ const JourniumProvider = ({ children, config, }) => {
|
|
|
1674
1675
|
const [analytics, setAnalytics] = React.useState(null);
|
|
1675
1676
|
const [effectiveOptions, setEffectiveOptions] = React.useState(null);
|
|
1676
1677
|
React.useEffect(() => {
|
|
1677
|
-
const analyticsInstance =
|
|
1678
|
+
const analyticsInstance = init(config);
|
|
1678
1679
|
// Get initial effective options (may be empty during remote-first initialization)
|
|
1679
1680
|
const initialEffective = analyticsInstance.getEffectiveOptions();
|
|
1680
1681
|
setEffectiveOptions(initialEffective);
|
|
@@ -1760,7 +1761,6 @@ const useAutocapture = () => {
|
|
|
1760
1761
|
|
|
1761
1762
|
exports.AutocaptureTracker = AutocaptureTracker;
|
|
1762
1763
|
exports.BrowserIdentityManager = BrowserIdentityManager;
|
|
1763
|
-
exports.JourniumAnalytics = JourniumAnalytics;
|
|
1764
1764
|
exports.JourniumClient = JourniumClient;
|
|
1765
1765
|
exports.JourniumProvider = JourniumProvider;
|
|
1766
1766
|
exports.Logger = Logger;
|