@journium/js 1.0.0 → 1.0.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/README.md +88 -272
- package/dist/client.d.ts +1 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/index.cjs +102 -114
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -6
- package/dist/index.esm.js +102 -114
- package/dist/index.esm.js.map +1 -1
- package/dist/index.umd.js +102 -114
- package/dist/index.umd.js.map +1 -1
- package/dist/journium.d.ts +0 -4
- package/dist/journium.d.ts.map +1 -1
- package/dist/pageview.d.ts +2 -2
- package/package.json +4 -4
package/dist/index.umd.js
CHANGED
|
@@ -431,9 +431,9 @@
|
|
|
431
431
|
var _a;
|
|
432
432
|
return typeof process !== 'undefined' && !!((_a = process.versions) === null || _a === void 0 ? void 0 : _a.node);
|
|
433
433
|
};
|
|
434
|
-
const fetchRemoteConfig = async (apiHost,
|
|
434
|
+
const fetchRemoteConfig = async (apiHost, publishableKey, fetchFn) => {
|
|
435
435
|
const endpoint = '/v1/configs';
|
|
436
|
-
const url = `${apiHost}${endpoint}?ingestion_key=${encodeURIComponent(
|
|
436
|
+
const url = `${apiHost}${endpoint}?ingestion_key=${encodeURIComponent(publishableKey)}`;
|
|
437
437
|
try {
|
|
438
438
|
let fetch = fetchFn;
|
|
439
439
|
if (!fetch) {
|
|
@@ -464,25 +464,31 @@
|
|
|
464
464
|
}
|
|
465
465
|
};
|
|
466
466
|
const mergeConfigs = (localConfig, remoteConfig) => {
|
|
467
|
+
if (!remoteConfig && !localConfig) {
|
|
468
|
+
return {};
|
|
469
|
+
}
|
|
467
470
|
if (!remoteConfig) {
|
|
468
471
|
return localConfig;
|
|
469
472
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
+
if (!localConfig) {
|
|
474
|
+
return remoteConfig;
|
|
475
|
+
}
|
|
476
|
+
// Deep merge local config into remote config
|
|
477
|
+
// Local config takes precedence over remote config
|
|
478
|
+
const merged = { ...remoteConfig };
|
|
473
479
|
// Handle primitive values
|
|
474
|
-
Object.keys(
|
|
475
|
-
if (
|
|
476
|
-
if (typeof
|
|
477
|
-
// Deep merge objects
|
|
480
|
+
Object.keys(localConfig).forEach(key => {
|
|
481
|
+
if (localConfig[key] !== undefined && localConfig[key] !== null) {
|
|
482
|
+
if (typeof localConfig[key] === 'object' && !Array.isArray(localConfig[key])) {
|
|
483
|
+
// Deep merge objects - local config overrides remote
|
|
478
484
|
merged[key] = {
|
|
479
485
|
...(merged[key] || {}),
|
|
480
|
-
...
|
|
486
|
+
...localConfig[key]
|
|
481
487
|
};
|
|
482
488
|
}
|
|
483
489
|
else {
|
|
484
|
-
// Override primitive values and arrays
|
|
485
|
-
merged[key] =
|
|
490
|
+
// Override primitive values and arrays with local config
|
|
491
|
+
merged[key] = localConfig[key];
|
|
486
492
|
}
|
|
487
493
|
}
|
|
488
494
|
});
|
|
@@ -491,14 +497,14 @@
|
|
|
491
497
|
|
|
492
498
|
const DEFAULT_SESSION_TIMEOUT = 30 * 60 * 1000; // 30 minutes in ms
|
|
493
499
|
class BrowserIdentityManager {
|
|
494
|
-
constructor(sessionTimeout,
|
|
500
|
+
constructor(sessionTimeout, publishableKey) {
|
|
495
501
|
this.identity = null;
|
|
496
502
|
this.sessionTimeout = DEFAULT_SESSION_TIMEOUT;
|
|
497
503
|
if (sessionTimeout) {
|
|
498
504
|
this.sessionTimeout = sessionTimeout;
|
|
499
505
|
}
|
|
500
|
-
// Generate storage key with
|
|
501
|
-
this.storageKey =
|
|
506
|
+
// Generate storage key with publishableKey pattern: jrnm_<publishableKey>_journium
|
|
507
|
+
this.storageKey = publishableKey ? `jrnm_${publishableKey}_journium` : '__journium_identity';
|
|
502
508
|
this.loadOrCreateIdentity();
|
|
503
509
|
}
|
|
504
510
|
loadOrCreateIdentity() {
|
|
@@ -670,24 +676,37 @@
|
|
|
670
676
|
this.flushTimer = null;
|
|
671
677
|
this.initialized = false;
|
|
672
678
|
// Validate required configuration
|
|
673
|
-
if (!config.
|
|
674
|
-
console.error('Journium:
|
|
679
|
+
if (!config.publishableKey) {
|
|
680
|
+
console.error('Journium: publishableKey is required but not provided. SDK will not function.');
|
|
675
681
|
return;
|
|
676
682
|
}
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
683
|
+
// Set default apiHost if not provided
|
|
684
|
+
this.config = {
|
|
685
|
+
...config,
|
|
686
|
+
apiHost: config.apiHost || 'https://events.journium.app'
|
|
687
|
+
};
|
|
682
688
|
// Generate storage key for config caching
|
|
683
|
-
this.configStorageKey = `jrnm_${config.
|
|
689
|
+
this.configStorageKey = `jrnm_${config.publishableKey}_config`;
|
|
690
|
+
// Generate default values
|
|
691
|
+
const defaultConfig = {
|
|
692
|
+
debug: false,
|
|
693
|
+
flushAt: 20,
|
|
694
|
+
flushInterval: 10000,
|
|
695
|
+
sessionTimeout: 30 * 60 * 1000, // 30 minutes
|
|
696
|
+
};
|
|
697
|
+
// Initialize effective config with local config taking precedence over defaults
|
|
698
|
+
this.effectiveConfig = { ...defaultConfig };
|
|
699
|
+
if (this.config.config) {
|
|
700
|
+
this.effectiveConfig = mergeConfigs(this.config.config, defaultConfig);
|
|
701
|
+
}
|
|
684
702
|
// Initialize identity manager
|
|
685
|
-
this.identityManager = new BrowserIdentityManager(this.
|
|
703
|
+
this.identityManager = new BrowserIdentityManager(this.effectiveConfig.sessionTimeout, this.config.publishableKey);
|
|
686
704
|
// Initialize synchronously with cached config, fetch fresh config in background
|
|
687
705
|
this.initializeSync();
|
|
688
706
|
this.fetchRemoteConfigAsync();
|
|
689
707
|
}
|
|
690
708
|
loadCachedConfig() {
|
|
709
|
+
var _a;
|
|
691
710
|
if (typeof window === 'undefined' || !window.localStorage) {
|
|
692
711
|
return null;
|
|
693
712
|
}
|
|
@@ -696,13 +715,14 @@
|
|
|
696
715
|
return cached ? JSON.parse(cached) : null;
|
|
697
716
|
}
|
|
698
717
|
catch (error) {
|
|
699
|
-
if (this.
|
|
718
|
+
if ((_a = this.effectiveConfig) === null || _a === void 0 ? void 0 : _a.debug) {
|
|
700
719
|
console.warn('Journium: Failed to load cached config:', error);
|
|
701
720
|
}
|
|
702
721
|
return null;
|
|
703
722
|
}
|
|
704
723
|
}
|
|
705
724
|
saveCachedConfig(config) {
|
|
725
|
+
var _a;
|
|
706
726
|
if (typeof window === 'undefined' || !window.localStorage) {
|
|
707
727
|
return;
|
|
708
728
|
}
|
|
@@ -710,91 +730,67 @@
|
|
|
710
730
|
window.localStorage.setItem(this.configStorageKey, JSON.stringify(config));
|
|
711
731
|
}
|
|
712
732
|
catch (error) {
|
|
713
|
-
if (this.
|
|
733
|
+
if ((_a = this.effectiveConfig) === null || _a === void 0 ? void 0 : _a.debug) {
|
|
714
734
|
console.warn('Journium: Failed to save config to cache:', error);
|
|
715
735
|
}
|
|
716
736
|
}
|
|
717
737
|
}
|
|
718
738
|
initializeSync() {
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
};
|
|
727
|
-
if (cachedConfig) {
|
|
728
|
-
// Use cached remote config
|
|
729
|
-
this.config = {
|
|
730
|
-
...localOnlyConfig,
|
|
731
|
-
...cachedConfig,
|
|
732
|
-
};
|
|
733
|
-
if (this.config.debug) {
|
|
734
|
-
console.log('Journium: Using cached configuration:', cachedConfig);
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
else {
|
|
738
|
-
// Use defaults for first-time initialization
|
|
739
|
-
this.config = {
|
|
740
|
-
...this.config,
|
|
741
|
-
debug: (_a = this.config.debug) !== null && _a !== void 0 ? _a : false,
|
|
742
|
-
flushAt: (_b = this.config.flushAt) !== null && _b !== void 0 ? _b : 20,
|
|
743
|
-
flushInterval: (_c = this.config.flushInterval) !== null && _c !== void 0 ? _c : 10000,
|
|
744
|
-
};
|
|
745
|
-
if (this.config.debug) {
|
|
746
|
-
console.log('Journium: No cached config found, using defaults');
|
|
739
|
+
// Step 1: Load cached remote config from localStorage (synchronous)
|
|
740
|
+
const cachedRemoteConfig = this.loadCachedConfig();
|
|
741
|
+
// Step 2: If no local config provided, use cached remote config
|
|
742
|
+
if (!this.config.config && cachedRemoteConfig) {
|
|
743
|
+
this.effectiveConfig = mergeConfigs(undefined, cachedRemoteConfig);
|
|
744
|
+
if (this.effectiveConfig.debug) {
|
|
745
|
+
console.log('Journium: Using cached remote configuration:', cachedRemoteConfig);
|
|
747
746
|
}
|
|
748
747
|
}
|
|
749
|
-
// Update session timeout from config
|
|
750
|
-
if (this.config.sessionTimeout) {
|
|
751
|
-
this.identityManager.updateSessionTimeout(this.config.sessionTimeout);
|
|
752
|
-
}
|
|
753
748
|
// Step 3: Mark as initialized immediately - no need to wait for remote fetch
|
|
754
749
|
this.initialized = true;
|
|
755
750
|
// Step 4: Start flush timer immediately
|
|
756
|
-
if (this.
|
|
751
|
+
if (this.effectiveConfig.flushInterval && this.effectiveConfig.flushInterval > 0) {
|
|
757
752
|
this.startFlushTimer();
|
|
758
753
|
}
|
|
759
|
-
if (this.
|
|
760
|
-
console.log('Journium: Client initialized
|
|
754
|
+
if (this.effectiveConfig.debug) {
|
|
755
|
+
console.log('Journium: Client initialized with effective config:', this.effectiveConfig);
|
|
761
756
|
}
|
|
762
757
|
}
|
|
763
758
|
async fetchRemoteConfigAsync() {
|
|
764
759
|
// Fetch fresh config in background
|
|
765
|
-
if (this.config.
|
|
760
|
+
if (this.config.publishableKey) {
|
|
766
761
|
await this.fetchAndCacheRemoteConfig();
|
|
767
762
|
}
|
|
768
763
|
}
|
|
769
764
|
async fetchAndCacheRemoteConfig() {
|
|
770
765
|
try {
|
|
771
|
-
if (this.
|
|
766
|
+
if (this.effectiveConfig.debug) {
|
|
772
767
|
console.log('Journium: Fetching remote configuration in background...');
|
|
773
768
|
}
|
|
774
|
-
const remoteConfigResponse = await fetchRemoteConfig(this.config.apiHost, this.config.
|
|
769
|
+
const remoteConfigResponse = await fetchRemoteConfig(this.config.apiHost, this.config.publishableKey);
|
|
775
770
|
if (remoteConfigResponse && remoteConfigResponse.success) {
|
|
776
|
-
// Save to cache for next session
|
|
771
|
+
// Save remote config to cache for next session
|
|
777
772
|
this.saveCachedConfig(remoteConfigResponse.config);
|
|
778
|
-
//
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
};
|
|
783
|
-
this.config = {
|
|
784
|
-
...localOnlyConfig,
|
|
785
|
-
...remoteConfigResponse.config,
|
|
786
|
-
};
|
|
787
|
-
// Update session timeout if provided in fresh config
|
|
788
|
-
if (remoteConfigResponse.config.sessionTimeout) {
|
|
789
|
-
this.identityManager.updateSessionTimeout(remoteConfigResponse.config.sessionTimeout);
|
|
773
|
+
// Update effective config: local config (if provided) overrides fresh remote config
|
|
774
|
+
if (!this.config.config) {
|
|
775
|
+
// No local config provided, use fresh remote config
|
|
776
|
+
this.effectiveConfig = mergeConfigs(undefined, remoteConfigResponse.config);
|
|
790
777
|
}
|
|
791
|
-
|
|
778
|
+
else {
|
|
779
|
+
// Local config provided, merge it over fresh remote config
|
|
780
|
+
this.effectiveConfig = mergeConfigs(this.config.config, remoteConfigResponse.config);
|
|
781
|
+
}
|
|
782
|
+
// Update session timeout if provided in fresh effective config
|
|
783
|
+
if (this.effectiveConfig.sessionTimeout) {
|
|
784
|
+
this.identityManager.updateSessionTimeout(this.effectiveConfig.sessionTimeout);
|
|
785
|
+
}
|
|
786
|
+
if (this.effectiveConfig.debug) {
|
|
792
787
|
console.log('Journium: Background remote configuration applied:', remoteConfigResponse.config);
|
|
788
|
+
console.log('Journium: New effective configuration:', this.effectiveConfig);
|
|
793
789
|
}
|
|
794
790
|
}
|
|
795
791
|
}
|
|
796
792
|
catch (error) {
|
|
797
|
-
if (this.
|
|
793
|
+
if (this.effectiveConfig.debug) {
|
|
798
794
|
console.warn('Journium: Background remote config fetch failed:', error);
|
|
799
795
|
}
|
|
800
796
|
}
|
|
@@ -806,7 +802,7 @@
|
|
|
806
802
|
// Use universal setInterval (works in both browser and Node.js)
|
|
807
803
|
this.flushTimer = setInterval(() => {
|
|
808
804
|
this.flush();
|
|
809
|
-
}, this.
|
|
805
|
+
}, this.effectiveConfig.flushInterval);
|
|
810
806
|
}
|
|
811
807
|
async sendEvents(events) {
|
|
812
808
|
if (!events.length)
|
|
@@ -816,7 +812,7 @@
|
|
|
816
812
|
method: 'POST',
|
|
817
813
|
headers: {
|
|
818
814
|
'Content-Type': 'application/json',
|
|
819
|
-
'Authorization': `Bearer ${this.config.
|
|
815
|
+
'Authorization': `Bearer ${this.config.publishableKey}`,
|
|
820
816
|
},
|
|
821
817
|
body: JSON.stringify({
|
|
822
818
|
events,
|
|
@@ -825,12 +821,12 @@
|
|
|
825
821
|
if (!response.ok) {
|
|
826
822
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
827
823
|
}
|
|
828
|
-
if (this.
|
|
824
|
+
if (this.effectiveConfig.debug) {
|
|
829
825
|
console.log('Journium: Successfully sent events', events);
|
|
830
826
|
}
|
|
831
827
|
}
|
|
832
828
|
catch (error) {
|
|
833
|
-
if (this.
|
|
829
|
+
if (this.effectiveConfig.debug) {
|
|
834
830
|
console.error('Journium: Failed to send events', error);
|
|
835
831
|
}
|
|
836
832
|
throw error;
|
|
@@ -839,8 +835,8 @@
|
|
|
839
835
|
identify(distinctId, attributes = {}) {
|
|
840
836
|
var _a;
|
|
841
837
|
// Don't identify if SDK is not properly configured
|
|
842
|
-
if (!this.config || !this.config.
|
|
843
|
-
if ((_a = this.
|
|
838
|
+
if (!this.config || !this.config.publishableKey || !this.initialized) {
|
|
839
|
+
if ((_a = this.effectiveConfig) === null || _a === void 0 ? void 0 : _a.debug) {
|
|
844
840
|
console.warn('Journium: identify() call rejected - SDK not ready');
|
|
845
841
|
}
|
|
846
842
|
return;
|
|
@@ -853,30 +849,30 @@
|
|
|
853
849
|
$anon_distinct_id: previousDistinctId,
|
|
854
850
|
};
|
|
855
851
|
this.track('$identify', identifyProperties);
|
|
856
|
-
if (this.
|
|
852
|
+
if (this.effectiveConfig.debug) {
|
|
857
853
|
console.log('Journium: User identified', { distinctId, attributes, previousDistinctId });
|
|
858
854
|
}
|
|
859
855
|
}
|
|
860
856
|
reset() {
|
|
861
857
|
var _a;
|
|
862
858
|
// Don't reset if SDK is not properly configured
|
|
863
|
-
if (!this.config || !this.config.
|
|
864
|
-
if ((_a = this.
|
|
859
|
+
if (!this.config || !this.config.publishableKey || !this.initialized) {
|
|
860
|
+
if ((_a = this.effectiveConfig) === null || _a === void 0 ? void 0 : _a.debug) {
|
|
865
861
|
console.warn('Journium: reset() call rejected - SDK not ready');
|
|
866
862
|
}
|
|
867
863
|
return;
|
|
868
864
|
}
|
|
869
865
|
// Reset identity in identity manager
|
|
870
866
|
this.identityManager.reset();
|
|
871
|
-
if (this.
|
|
867
|
+
if (this.effectiveConfig.debug) {
|
|
872
868
|
console.log('Journium: User identity reset');
|
|
873
869
|
}
|
|
874
870
|
}
|
|
875
871
|
track(event, properties = {}) {
|
|
876
872
|
var _a;
|
|
877
873
|
// Don't track if SDK is not properly configured
|
|
878
|
-
if (!this.config || !this.config.
|
|
879
|
-
if ((_a = this.
|
|
874
|
+
if (!this.config || !this.config.publishableKey || !this.initialized) {
|
|
875
|
+
if ((_a = this.effectiveConfig) === null || _a === void 0 ? void 0 : _a.debug) {
|
|
880
876
|
console.warn('Journium: track() call rejected - SDK not ready');
|
|
881
877
|
}
|
|
882
878
|
return;
|
|
@@ -898,22 +894,22 @@
|
|
|
898
894
|
};
|
|
899
895
|
const journiumEvent = {
|
|
900
896
|
uuid: generateUuidv7(),
|
|
901
|
-
ingestion_key: this.config.
|
|
897
|
+
ingestion_key: this.config.publishableKey,
|
|
902
898
|
client_timestamp: getCurrentTimestamp(),
|
|
903
899
|
event,
|
|
904
900
|
properties: eventProperties,
|
|
905
901
|
};
|
|
906
902
|
this.queue.push(journiumEvent);
|
|
907
|
-
if (this.
|
|
903
|
+
if (this.effectiveConfig.debug) {
|
|
908
904
|
console.log('Journium: Event tracked', journiumEvent);
|
|
909
905
|
}
|
|
910
|
-
if (this.queue.length >= this.
|
|
906
|
+
if (this.queue.length >= this.effectiveConfig.flushAt) {
|
|
911
907
|
this.flush();
|
|
912
908
|
}
|
|
913
909
|
}
|
|
914
910
|
async flush() {
|
|
915
911
|
// Don't flush if SDK is not properly configured
|
|
916
|
-
if (!this.config || !this.config.
|
|
912
|
+
if (!this.config || !this.config.publishableKey) {
|
|
917
913
|
return;
|
|
918
914
|
}
|
|
919
915
|
if (this.queue.length === 0)
|
|
@@ -960,7 +956,7 @@
|
|
|
960
956
|
this.client.track('$pageview', properties);
|
|
961
957
|
this.lastUrl = currentUrl;
|
|
962
958
|
}
|
|
963
|
-
|
|
959
|
+
startAutocapture() {
|
|
964
960
|
this.capturePageview();
|
|
965
961
|
if (typeof window !== 'undefined') {
|
|
966
962
|
// Store original methods for cleanup
|
|
@@ -980,7 +976,7 @@
|
|
|
980
976
|
window.addEventListener('popstate', this.popStateHandler);
|
|
981
977
|
}
|
|
982
978
|
}
|
|
983
|
-
|
|
979
|
+
stopAutocapture() {
|
|
984
980
|
if (typeof window !== 'undefined') {
|
|
985
981
|
// Restore original methods
|
|
986
982
|
if (this.originalPushState) {
|
|
@@ -1344,13 +1340,14 @@
|
|
|
1344
1340
|
|
|
1345
1341
|
class Journium {
|
|
1346
1342
|
constructor(config) {
|
|
1343
|
+
var _a, _b;
|
|
1347
1344
|
this.config = config;
|
|
1348
1345
|
this.client = new JourniumClient(config);
|
|
1349
1346
|
this.pageviewTracker = new PageviewTracker(this.client);
|
|
1350
|
-
const autocaptureConfig = this.resolveAutocaptureConfig(config.autocapture);
|
|
1347
|
+
const autocaptureConfig = this.resolveAutocaptureConfig((_a = config.config) === null || _a === void 0 ? void 0 : _a.autocapture);
|
|
1351
1348
|
this.autocaptureTracker = new AutocaptureTracker(this.client, autocaptureConfig);
|
|
1352
|
-
// Store resolved autocapture state for
|
|
1353
|
-
this.autocaptureEnabled = config.autocapture !== false;
|
|
1349
|
+
// Store resolved autocapture state for startAutocapture method
|
|
1350
|
+
this.autocaptureEnabled = ((_b = config.config) === null || _b === void 0 ? void 0 : _b.autocapture) !== false;
|
|
1354
1351
|
}
|
|
1355
1352
|
resolveAutocaptureConfig(autocapture) {
|
|
1356
1353
|
if (autocapture === false) {
|
|
@@ -1378,30 +1375,21 @@
|
|
|
1378
1375
|
capturePageview(properties) {
|
|
1379
1376
|
this.pageviewTracker.capturePageview(properties);
|
|
1380
1377
|
}
|
|
1381
|
-
|
|
1382
|
-
this.pageviewTracker.
|
|
1378
|
+
startAutocapture() {
|
|
1379
|
+
this.pageviewTracker.startAutocapture();
|
|
1383
1380
|
if (this.autocaptureEnabled) {
|
|
1384
1381
|
this.autocaptureTracker.start();
|
|
1385
1382
|
}
|
|
1386
1383
|
}
|
|
1387
|
-
stopAutoCapture() {
|
|
1388
|
-
this.pageviewTracker.stopAutoCapture();
|
|
1389
|
-
this.autocaptureTracker.stop();
|
|
1390
|
-
}
|
|
1391
|
-
// Aliases for consistency (deprecated - use startAutoCapture)
|
|
1392
|
-
/** @deprecated Use startAutoCapture() instead */
|
|
1393
|
-
startAutocapture() {
|
|
1394
|
-
this.startAutoCapture();
|
|
1395
|
-
}
|
|
1396
|
-
/** @deprecated Use stopAutoCapture() instead */
|
|
1397
1384
|
stopAutocapture() {
|
|
1398
|
-
this.
|
|
1385
|
+
this.pageviewTracker.stopAutocapture();
|
|
1386
|
+
this.autocaptureTracker.stop();
|
|
1399
1387
|
}
|
|
1400
1388
|
async flush() {
|
|
1401
1389
|
return this.client.flush();
|
|
1402
1390
|
}
|
|
1403
1391
|
destroy() {
|
|
1404
|
-
this.pageviewTracker.
|
|
1392
|
+
this.pageviewTracker.stopAutocapture();
|
|
1405
1393
|
this.autocaptureTracker.stop();
|
|
1406
1394
|
this.client.destroy();
|
|
1407
1395
|
}
|