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