@journium/react 1.0.7 → 1.1.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/context.d.ts +3 -2
- package/dist/context.d.ts.map +1 -1
- package/dist/index.cjs +257 -138
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.mjs +258 -138
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -3
- package/readme.md +30 -326
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
|
}
|
|
@@ -701,16 +701,20 @@ 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;
|
|
708
710
|
this.optionsChangeCallbacks = new Set();
|
|
709
711
|
// Validate required configuration
|
|
710
|
-
if (!config.publishableKey) {
|
|
712
|
+
if (!config.publishableKey || config.publishableKey.trim() === '') {
|
|
713
|
+
// Reject initialization with clear error
|
|
714
|
+
const errorMsg = 'Journium: publishableKey is required but not provided or is empty. SDK cannot be initialized.';
|
|
711
715
|
Logger.setDebug(true);
|
|
712
|
-
Logger.error(
|
|
713
|
-
|
|
716
|
+
Logger.error(errorMsg);
|
|
717
|
+
throw new Error(errorMsg);
|
|
714
718
|
}
|
|
715
719
|
// Set default apiHost if not provided
|
|
716
720
|
this.config = {
|
|
@@ -719,25 +723,15 @@ class JourniumClient {
|
|
|
719
723
|
};
|
|
720
724
|
// Generate storage key for options caching
|
|
721
725
|
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();
|
|
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();
|
|
741
735
|
}
|
|
742
736
|
loadCachedOptions() {
|
|
743
737
|
if (typeof window === 'undefined' || !window.localStorage) {
|
|
@@ -763,70 +757,108 @@ class JourniumClient {
|
|
|
763
757
|
Logger.warn('Journium: Failed to save config to cache:', error);
|
|
764
758
|
}
|
|
765
759
|
}
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
if (
|
|
773
|
-
//
|
|
774
|
-
this.
|
|
775
|
-
|
|
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
|
+
}
|
|
776
778
|
}
|
|
777
779
|
else {
|
|
778
|
-
//
|
|
779
|
-
|
|
780
|
-
|
|
780
|
+
// Step 4: Fallback to cached config if fresh fetch failed
|
|
781
|
+
/* const cachedRemoteOptions = this.loadCachedOptions();
|
|
782
|
+
|
|
783
|
+
if (cachedRemoteOptions) {
|
|
784
|
+
if (this.config.options) {
|
|
785
|
+
this.effectiveOptions = mergeOptions(this.config.options, cachedRemoteOptions);
|
|
786
|
+
Logger.log('Journium: Fresh config failed, using cached remote config merged with local options:', this.effectiveOptions);
|
|
787
|
+
} else {
|
|
788
|
+
this.effectiveOptions = cachedRemoteOptions;
|
|
789
|
+
Logger.log('Journium: Fresh config failed, using cached remote config:', this.effectiveOptions);
|
|
790
|
+
}
|
|
791
|
+
} else {
|
|
792
|
+
// Step 5: No remote config and no cached config - initialization fails
|
|
793
|
+
Logger.error('Journium: Initialization failed - no remote config available and no cached config found');
|
|
794
|
+
this.initializationFailed = true;
|
|
795
|
+
this.initializationComplete = false;
|
|
796
|
+
return;
|
|
797
|
+
} */
|
|
781
798
|
}
|
|
799
|
+
// Step 6: Update identity manager session timeout if provided
|
|
800
|
+
if (this.effectiveOptions.sessionTimeout) {
|
|
801
|
+
this.identityManager.updateSessionTimeout(this.effectiveOptions.sessionTimeout);
|
|
802
|
+
}
|
|
803
|
+
// Step 7: Update Logger debug setting
|
|
804
|
+
Logger.setDebug((_a = this.effectiveOptions.debug) !== null && _a !== void 0 ? _a : false);
|
|
805
|
+
// Step 8: Mark initialization as complete
|
|
806
|
+
this.initializationComplete = true;
|
|
807
|
+
this.initializationFailed = false;
|
|
808
|
+
// Step 9: Process any staged events
|
|
809
|
+
this.processStagedEvents();
|
|
810
|
+
// Step 10: Start flush timer
|
|
811
|
+
if (this.effectiveOptions.flushInterval && this.effectiveOptions.flushInterval > 0) {
|
|
812
|
+
this.startFlushTimer();
|
|
813
|
+
}
|
|
814
|
+
Logger.log('Journium: Initialization complete with options:', this.effectiveOptions);
|
|
815
|
+
// Step 11: Notify callbacks about options
|
|
816
|
+
this.notifyOptionsChange();
|
|
782
817
|
}
|
|
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();
|
|
818
|
+
catch (error) {
|
|
819
|
+
Logger.error('Journium: Initialization failed:', error);
|
|
820
|
+
this.initializationFailed = true;
|
|
821
|
+
this.initializationComplete = false;
|
|
796
822
|
}
|
|
797
823
|
}
|
|
798
|
-
async
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
//
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
824
|
+
async fetchRemoteOptionsWithRetry() {
|
|
825
|
+
const maxRetries = 2;
|
|
826
|
+
const timeoutMs = 15000; // 15 seconds
|
|
827
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
828
|
+
try {
|
|
829
|
+
Logger.log(`Journium: Fetching remote config (attempt ${attempt}/${maxRetries})...`);
|
|
830
|
+
// Create timeout promise
|
|
831
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
832
|
+
setTimeout(() => reject(new Error('Timeout')), timeoutMs);
|
|
833
|
+
});
|
|
834
|
+
// Race fetch against timeout
|
|
835
|
+
const fetchPromise = fetchRemoteOptions(this.config.apiHost, this.config.publishableKey);
|
|
836
|
+
const remoteOptionsResponse = await Promise.race([fetchPromise, timeoutPromise]);
|
|
837
|
+
if (remoteOptionsResponse && remoteOptionsResponse.status === 'success') {
|
|
838
|
+
Logger.log('Journium: Successfully fetched fresh remote config:', remoteOptionsResponse.config);
|
|
839
|
+
return remoteOptionsResponse.config || null;
|
|
810
840
|
}
|
|
811
|
-
else {
|
|
812
|
-
|
|
813
|
-
|
|
841
|
+
else if (remoteOptionsResponse && remoteOptionsResponse.status === 'error' && remoteOptionsResponse.errorCode === 'J_ERR_TENANT_NOT_FOUND') {
|
|
842
|
+
Logger.error('Journium: Invalid publishableKey is being used.');
|
|
843
|
+
return null;
|
|
814
844
|
}
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
845
|
+
{
|
|
846
|
+
throw new Error('Remote config fetch unsuccessful');
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
catch (error) {
|
|
850
|
+
Logger.warn(`Journium: Remote config fetch attempt ${attempt} failed:`, error);
|
|
851
|
+
if (attempt === maxRetries) {
|
|
852
|
+
Logger.warn('Journium: All remote config fetch attempts failed, falling back to cached config');
|
|
853
|
+
return null;
|
|
854
|
+
}
|
|
855
|
+
// Wait 1 second before retry (except on last attempt)
|
|
856
|
+
if (attempt < maxRetries) {
|
|
857
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
818
858
|
}
|
|
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
859
|
}
|
|
826
860
|
}
|
|
827
|
-
|
|
828
|
-
Logger.warn('Journium: Background remote options fetch failed:', error);
|
|
829
|
-
}
|
|
861
|
+
return null;
|
|
830
862
|
}
|
|
831
863
|
/**
|
|
832
864
|
* Register a callback to be notified when effective options change (e.g., when remote options are fetched)
|
|
@@ -848,12 +880,48 @@ class JourniumClient {
|
|
|
848
880
|
}
|
|
849
881
|
});
|
|
850
882
|
}
|
|
883
|
+
processStagedEvents() {
|
|
884
|
+
if (this.stagedEvents.length === 0)
|
|
885
|
+
return;
|
|
886
|
+
Logger.log(`Journium: Processing ${this.stagedEvents.length} staged events`);
|
|
887
|
+
// Move staged events to main queue, adding identity properties now
|
|
888
|
+
const identity = this.identityManager.getIdentity();
|
|
889
|
+
const userAgentInfo = this.identityManager.getUserAgentInfo();
|
|
890
|
+
for (const stagedEvent of this.stagedEvents) {
|
|
891
|
+
// Add identity properties that weren't available during staging
|
|
892
|
+
const eventWithIdentity = {
|
|
893
|
+
...stagedEvent,
|
|
894
|
+
properties: {
|
|
895
|
+
$device_id: identity === null || identity === void 0 ? void 0 : identity.$device_id,
|
|
896
|
+
distinct_id: identity === null || identity === void 0 ? void 0 : identity.distinct_id,
|
|
897
|
+
$session_id: identity === null || identity === void 0 ? void 0 : identity.$session_id,
|
|
898
|
+
$is_identified: (identity === null || identity === void 0 ? void 0 : identity.$user_state) === 'identified',
|
|
899
|
+
$current_url: typeof window !== 'undefined' ? window.location.href : '',
|
|
900
|
+
$pathname: typeof window !== 'undefined' ? window.location.pathname : '',
|
|
901
|
+
...userAgentInfo,
|
|
902
|
+
$lib_version: '0.1.0', // TODO: Get from package.json
|
|
903
|
+
$platform: 'web',
|
|
904
|
+
...stagedEvent.properties, // Original properties override system properties
|
|
905
|
+
},
|
|
906
|
+
};
|
|
907
|
+
this.queue.push(eventWithIdentity);
|
|
908
|
+
}
|
|
909
|
+
// Clear staged events
|
|
910
|
+
this.stagedEvents = [];
|
|
911
|
+
Logger.log('Journium: Staged events processed and moved to main queue');
|
|
912
|
+
// Check if we should flush immediately
|
|
913
|
+
if (this.queue.length >= this.effectiveOptions.flushAt) {
|
|
914
|
+
// console.log('1 Journium: Flushing events...'+JSON.stringify(this.effectiveOptions));
|
|
915
|
+
this.flush();
|
|
916
|
+
}
|
|
917
|
+
}
|
|
851
918
|
startFlushTimer() {
|
|
852
919
|
if (this.flushTimer) {
|
|
853
920
|
clearInterval(this.flushTimer);
|
|
854
921
|
}
|
|
855
922
|
// Use universal setInterval (works in both browser and Node.js)
|
|
856
923
|
this.flushTimer = setInterval(() => {
|
|
924
|
+
// console.log('2 Journium: Flushing events...'+JSON.stringify(this.effectiveOptions));
|
|
857
925
|
this.flush();
|
|
858
926
|
}, this.effectiveOptions.flushInterval);
|
|
859
927
|
}
|
|
@@ -882,9 +950,9 @@ class JourniumClient {
|
|
|
882
950
|
}
|
|
883
951
|
}
|
|
884
952
|
identify(distinctId, attributes = {}) {
|
|
885
|
-
// Don't identify if
|
|
886
|
-
if (
|
|
887
|
-
Logger.warn('Journium: identify() call rejected -
|
|
953
|
+
// Don't identify if initialization failed
|
|
954
|
+
if (this.initializationFailed) {
|
|
955
|
+
Logger.warn('Journium: identify() call rejected - initialization failed');
|
|
888
956
|
return;
|
|
889
957
|
}
|
|
890
958
|
// Call identify on identity manager to get previous distinct ID
|
|
@@ -898,9 +966,9 @@ class JourniumClient {
|
|
|
898
966
|
Logger.log('Journium: User identified', { distinctId, attributes, previousDistinctId });
|
|
899
967
|
}
|
|
900
968
|
reset() {
|
|
901
|
-
// Don't reset if
|
|
902
|
-
if (
|
|
903
|
-
Logger.warn('Journium: reset() call rejected -
|
|
969
|
+
// Don't reset if initialization failed
|
|
970
|
+
if (this.initializationFailed) {
|
|
971
|
+
Logger.warn('Journium: reset() call rejected - initialization failed');
|
|
904
972
|
return;
|
|
905
973
|
}
|
|
906
974
|
// Reset identity in identity manager
|
|
@@ -908,42 +976,60 @@ class JourniumClient {
|
|
|
908
976
|
Logger.log('Journium: User identity reset');
|
|
909
977
|
}
|
|
910
978
|
track(event, properties = {}) {
|
|
911
|
-
//
|
|
912
|
-
if (!this.config || !this.config.publishableKey || !this.initialized) {
|
|
913
|
-
Logger.warn('Journium: track() call rejected - SDK not ready');
|
|
914
|
-
return;
|
|
915
|
-
}
|
|
916
|
-
const identity = this.identityManager.getIdentity();
|
|
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
|
-
};
|
|
979
|
+
// Create minimal event without identity properties (will be added later if staging)
|
|
931
980
|
const journiumEvent = {
|
|
932
981
|
uuid: generateUuidv7(),
|
|
933
982
|
ingestion_key: this.config.publishableKey,
|
|
934
983
|
client_timestamp: getCurrentTimestamp(),
|
|
935
984
|
event,
|
|
936
|
-
properties:
|
|
985
|
+
properties: { ...properties }, // Only user properties for now
|
|
937
986
|
};
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
987
|
+
// Stage events during initialization, add to queue after initialization
|
|
988
|
+
if (!this.initializationComplete) {
|
|
989
|
+
// If initialization failed, reject events
|
|
990
|
+
if (this.initializationFailed) {
|
|
991
|
+
Logger.warn('Journium: track() call rejected - initialization failed');
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
this.stagedEvents.push(journiumEvent);
|
|
995
|
+
Logger.log('Journium: Event staged during initialization', journiumEvent);
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
// If initialization failed, reject events
|
|
999
|
+
if (this.initializationFailed) {
|
|
1000
|
+
Logger.warn('Journium: track() call rejected - initialization failed');
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
// Add identity properties for immediate events (after initialization)
|
|
1004
|
+
const identity = this.identityManager.getIdentity();
|
|
1005
|
+
const userAgentInfo = this.identityManager.getUserAgentInfo();
|
|
1006
|
+
const eventWithIdentity = {
|
|
1007
|
+
...journiumEvent,
|
|
1008
|
+
properties: {
|
|
1009
|
+
$device_id: identity === null || identity === void 0 ? void 0 : identity.$device_id,
|
|
1010
|
+
distinct_id: identity === null || identity === void 0 ? void 0 : identity.distinct_id,
|
|
1011
|
+
$session_id: identity === null || identity === void 0 ? void 0 : identity.$session_id,
|
|
1012
|
+
$is_identified: (identity === null || identity === void 0 ? void 0 : identity.$user_state) === 'identified',
|
|
1013
|
+
$current_url: typeof window !== 'undefined' ? window.location.href : '',
|
|
1014
|
+
$pathname: typeof window !== 'undefined' ? window.location.pathname : '',
|
|
1015
|
+
...userAgentInfo,
|
|
1016
|
+
$lib_version: '0.1.0', // TODO: Get from package.json
|
|
1017
|
+
$platform: 'web',
|
|
1018
|
+
...properties, // User-provided properties override system properties
|
|
1019
|
+
},
|
|
1020
|
+
};
|
|
1021
|
+
this.queue.push(eventWithIdentity);
|
|
1022
|
+
Logger.log('Journium: Event tracked', eventWithIdentity);
|
|
1023
|
+
// Only flush if we have effective options (after initialization)
|
|
1024
|
+
if (this.effectiveOptions.flushAt && this.queue.length >= this.effectiveOptions.flushAt) {
|
|
1025
|
+
// console.log('3 Journium: Flushing events...'+JSON.stringify(this.effectiveOptions));
|
|
941
1026
|
this.flush();
|
|
942
1027
|
}
|
|
943
1028
|
}
|
|
944
1029
|
async flush() {
|
|
945
|
-
// Don't flush if
|
|
946
|
-
if (
|
|
1030
|
+
// Don't flush if initialization failed
|
|
1031
|
+
if (this.initializationFailed) {
|
|
1032
|
+
Logger.warn('Journium: flush() call rejected - initialization failed');
|
|
947
1033
|
return;
|
|
948
1034
|
}
|
|
949
1035
|
if (this.queue.length === 0)
|
|
@@ -997,7 +1083,7 @@ class PageviewTracker {
|
|
|
997
1083
|
* Start automatic autocapture for pageviews
|
|
998
1084
|
* @returns void
|
|
999
1085
|
*/
|
|
1000
|
-
|
|
1086
|
+
startAutoPageviewTracking() {
|
|
1001
1087
|
this.capturePageview();
|
|
1002
1088
|
if (typeof window !== 'undefined') {
|
|
1003
1089
|
// Store original methods for cleanup
|
|
@@ -1426,6 +1512,9 @@ class JourniumAnalytics {
|
|
|
1426
1512
|
this.unsubscribeOptionsChange = this.client.onOptionsChange((effectiveOptions) => {
|
|
1427
1513
|
this.handleOptionsChange(effectiveOptions);
|
|
1428
1514
|
});
|
|
1515
|
+
// Start automatic autocapture immediately if initial options support it
|
|
1516
|
+
// This handles cached remote options or local options with autocapture enabled
|
|
1517
|
+
this.startAutocaptureIfEnabled(initialEffectiveOptions);
|
|
1429
1518
|
}
|
|
1430
1519
|
resolveAutocaptureOptions(autocapture) {
|
|
1431
1520
|
if (autocapture === false) {
|
|
@@ -1456,13 +1545,18 @@ class JourniumAnalytics {
|
|
|
1456
1545
|
startAutocapture() {
|
|
1457
1546
|
// Always check effective options (which may include remote options)
|
|
1458
1547
|
const effectiveOptions = this.client.getEffectiveOptions();
|
|
1459
|
-
|
|
1460
|
-
const
|
|
1548
|
+
// Only enable if effectiveOptions are loaded and autoTrackPageviews is not explicitly false
|
|
1549
|
+
const autoTrackPageviews = effectiveOptions && Object.keys(effectiveOptions).length > 0
|
|
1550
|
+
? effectiveOptions.autoTrackPageviews !== false
|
|
1551
|
+
: false;
|
|
1552
|
+
const autocaptureEnabled = effectiveOptions && Object.keys(effectiveOptions).length > 0
|
|
1553
|
+
? effectiveOptions.autocapture !== false
|
|
1554
|
+
: false;
|
|
1461
1555
|
// Update autocapture tracker options if they've changed
|
|
1462
1556
|
const autocaptureOptions = this.resolveAutocaptureOptions(effectiveOptions.autocapture);
|
|
1463
1557
|
this.autocaptureTracker.updateOptions(autocaptureOptions);
|
|
1464
1558
|
if (autoTrackPageviews) {
|
|
1465
|
-
this.pageviewTracker.
|
|
1559
|
+
this.pageviewTracker.startAutoPageviewTracking();
|
|
1466
1560
|
}
|
|
1467
1561
|
if (autocaptureEnabled) {
|
|
1468
1562
|
this.autocaptureTracker.start();
|
|
@@ -1475,30 +1569,60 @@ class JourniumAnalytics {
|
|
|
1475
1569
|
this.autocaptureStarted = false;
|
|
1476
1570
|
}
|
|
1477
1571
|
/**
|
|
1478
|
-
*
|
|
1572
|
+
* Automatically start autocapture if enabled in options
|
|
1573
|
+
* Handles both initial options and empty options during remote-first initialization
|
|
1479
1574
|
*/
|
|
1480
|
-
|
|
1481
|
-
//
|
|
1575
|
+
startAutocaptureIfEnabled(effectiveOptions) {
|
|
1576
|
+
// Skip if autocapture was already started manually
|
|
1482
1577
|
if (this.autocaptureStarted) {
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1578
|
+
return;
|
|
1579
|
+
}
|
|
1580
|
+
// During remote-first initialization, effective options might be empty initially
|
|
1581
|
+
// Only auto-start if we have actual options loaded, not empty options
|
|
1582
|
+
const hasActualOptions = effectiveOptions && Object.keys(effectiveOptions).length > 0;
|
|
1583
|
+
if (hasActualOptions) {
|
|
1584
|
+
// Use same logic as manual startAutocapture() but only start automatically
|
|
1488
1585
|
const autoTrackPageviews = effectiveOptions.autoTrackPageviews !== false;
|
|
1489
1586
|
const autocaptureEnabled = effectiveOptions.autocapture !== false;
|
|
1490
1587
|
// Update autocapture tracker options
|
|
1491
1588
|
const autocaptureOptions = this.resolveAutocaptureOptions(effectiveOptions.autocapture);
|
|
1492
1589
|
this.autocaptureTracker.updateOptions(autocaptureOptions);
|
|
1493
|
-
// Restart only if still enabled
|
|
1494
1590
|
if (autoTrackPageviews) {
|
|
1495
|
-
this.pageviewTracker.
|
|
1591
|
+
this.pageviewTracker.startAutoPageviewTracking();
|
|
1496
1592
|
}
|
|
1497
1593
|
if (autocaptureEnabled) {
|
|
1498
1594
|
this.autocaptureTracker.start();
|
|
1499
1595
|
}
|
|
1500
|
-
|
|
1596
|
+
if (autoTrackPageviews || autocaptureEnabled) {
|
|
1597
|
+
this.autocaptureStarted = true;
|
|
1598
|
+
}
|
|
1501
1599
|
}
|
|
1600
|
+
// If options are empty (during initialization), wait for options change callback
|
|
1601
|
+
}
|
|
1602
|
+
/**
|
|
1603
|
+
* Handle effective options change (e.g., when remote options are fetched)
|
|
1604
|
+
*/
|
|
1605
|
+
handleOptionsChange(effectiveOptions) {
|
|
1606
|
+
// Stop current autocapture if it was already started
|
|
1607
|
+
if (this.autocaptureStarted) {
|
|
1608
|
+
this.pageviewTracker.stopAutocapture();
|
|
1609
|
+
this.autocaptureTracker.stop();
|
|
1610
|
+
this.autocaptureStarted = false;
|
|
1611
|
+
}
|
|
1612
|
+
// Evaluate if autocapture should be enabled with new options
|
|
1613
|
+
const autoTrackPageviews = effectiveOptions.autoTrackPageviews !== false;
|
|
1614
|
+
const autocaptureEnabled = effectiveOptions.autocapture !== false;
|
|
1615
|
+
// Update autocapture tracker options
|
|
1616
|
+
const autocaptureOptions = this.resolveAutocaptureOptions(effectiveOptions.autocapture);
|
|
1617
|
+
this.autocaptureTracker.updateOptions(autocaptureOptions);
|
|
1618
|
+
// Start autocapture based on new options (even if it wasn't started before)
|
|
1619
|
+
if (autoTrackPageviews) {
|
|
1620
|
+
this.pageviewTracker.startAutoPageviewTracking();
|
|
1621
|
+
}
|
|
1622
|
+
if (autocaptureEnabled) {
|
|
1623
|
+
this.autocaptureTracker.start();
|
|
1624
|
+
}
|
|
1625
|
+
this.autocaptureStarted = autoTrackPageviews || autocaptureEnabled;
|
|
1502
1626
|
}
|
|
1503
1627
|
async flush() {
|
|
1504
1628
|
return this.client.flush();
|
|
@@ -1525,24 +1649,20 @@ const init = (config) => {
|
|
|
1525
1649
|
return new JourniumAnalytics(config);
|
|
1526
1650
|
};
|
|
1527
1651
|
|
|
1528
|
-
const JourniumContext = React.createContext(
|
|
1652
|
+
const JourniumContext = React.createContext(undefined);
|
|
1529
1653
|
const JourniumProvider = ({ children, config, }) => {
|
|
1530
1654
|
const [analytics, setAnalytics] = React.useState(null);
|
|
1531
1655
|
const [effectiveOptions, setEffectiveOptions] = React.useState(null);
|
|
1532
1656
|
React.useEffect(() => {
|
|
1533
|
-
const analyticsInstance =
|
|
1534
|
-
// Get initial effective options (may
|
|
1657
|
+
const analyticsInstance = init(config);
|
|
1658
|
+
// Get initial effective options (may be empty during remote-first initialization)
|
|
1535
1659
|
const initialEffective = analyticsInstance.getEffectiveOptions();
|
|
1536
1660
|
setEffectiveOptions(initialEffective);
|
|
1537
|
-
//
|
|
1538
|
-
|
|
1539
|
-
if (autocaptureEnabled) {
|
|
1540
|
-
analyticsInstance.startAutocapture();
|
|
1541
|
-
}
|
|
1661
|
+
// Don't start autocapture immediately with potentially empty options
|
|
1662
|
+
// Let the analytics instance handle autocapture after initialization completes
|
|
1542
1663
|
setAnalytics(analyticsInstance);
|
|
1543
1664
|
// Listen for options changes (when remote options are fetched)
|
|
1544
|
-
//
|
|
1545
|
-
// We just need to update the effectiveOptions state for consumers
|
|
1665
|
+
// The JourniumAnalytics will automatically start autocapture when initialization completes
|
|
1546
1666
|
const unsubscribe = analyticsInstance.onOptionsChange((newOptions) => {
|
|
1547
1667
|
setEffectiveOptions(newOptions);
|
|
1548
1668
|
});
|
|
@@ -1620,7 +1740,6 @@ const useAutocapture = () => {
|
|
|
1620
1740
|
|
|
1621
1741
|
exports.AutocaptureTracker = AutocaptureTracker;
|
|
1622
1742
|
exports.BrowserIdentityManager = BrowserIdentityManager;
|
|
1623
|
-
exports.JourniumAnalytics = JourniumAnalytics;
|
|
1624
1743
|
exports.JourniumClient = JourniumClient;
|
|
1625
1744
|
exports.JourniumProvider = JourniumProvider;
|
|
1626
1745
|
exports.Logger = Logger;
|