@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/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, token, fetchFn) => {
434
+ const fetchRemoteConfig = async (apiHost, publishableKey, fetchFn) => {
435
435
  const endpoint = '/v1/configs';
436
- const url = `${apiHost}${endpoint}?ingestion_key=${encodeURIComponent(token)}`;
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
- // Deep merge remote config into local config
471
- // Remote config takes precedence over local config
472
- const merged = { ...localConfig };
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(remoteConfig).forEach(key => {
475
- if (remoteConfig[key] !== undefined && remoteConfig[key] !== null) {
476
- if (typeof remoteConfig[key] === 'object' && !Array.isArray(remoteConfig[key])) {
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
- ...remoteConfig[key]
486
+ ...localConfig[key]
481
487
  };
482
488
  }
483
489
  else {
484
- // Override primitive values and arrays
485
- merged[key] = remoteConfig[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, token) {
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 token pattern: jrnm_<token>_journium
501
- this.storageKey = token ? `jrnm_${token}_journium` : '__journium_identity';
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.token) {
674
- console.error('Journium: token is required but not provided. SDK will not function.');
679
+ if (!config.publishableKey) {
680
+ console.error('Journium: publishableKey is required but not provided. SDK will not function.');
675
681
  return;
676
682
  }
677
- if (!config.apiHost) {
678
- console.error('Journium: apiHost is required but not provided. SDK will not function.');
679
- return;
680
- }
681
- this.config = config;
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.token}_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.config.sessionTimeout, this.config.token);
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.config.debug) {
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.config.debug) {
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
- var _a, _b, _c;
720
- // Step 1: Load cached config from localStorage (synchronous)
721
- const cachedConfig = this.loadCachedConfig();
722
- // Step 2: Apply cached config immediately, or use defaults
723
- const localOnlyConfig = {
724
- apiHost: this.config.apiHost,
725
- token: this.config.token,
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.config.flushInterval && this.config.flushInterval > 0) {
751
+ if (this.effectiveConfig.flushInterval && this.effectiveConfig.flushInterval > 0) {
757
752
  this.startFlushTimer();
758
753
  }
759
- if (this.config.debug) {
760
- console.log('Journium: Client initialized and ready to track events');
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.token) {
760
+ if (this.config.publishableKey) {
766
761
  await this.fetchAndCacheRemoteConfig();
767
762
  }
768
763
  }
769
764
  async fetchAndCacheRemoteConfig() {
770
765
  try {
771
- if (this.config.debug) {
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.token);
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
- // Apply fresh config to current session
779
- const localOnlyConfig = {
780
- apiHost: this.config.apiHost,
781
- token: this.config.token,
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
- if (this.config.debug) {
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.config.debug) {
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.config.flushInterval);
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.token}`,
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.config.debug) {
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.config.debug) {
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.token || !this.config.apiHost || !this.initialized) {
843
- if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.debug) {
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.config.debug) {
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.token || !this.config.apiHost || !this.initialized) {
864
- if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.debug) {
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.config.debug) {
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.token || !this.config.apiHost || !this.initialized) {
879
- if ((_a = this.config) === null || _a === void 0 ? void 0 : _a.debug) {
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.token,
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.config.debug) {
903
+ if (this.effectiveConfig.debug) {
908
904
  console.log('Journium: Event tracked', journiumEvent);
909
905
  }
910
- if (this.queue.length >= this.config.flushAt) {
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.token || !this.config.apiHost) {
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
- startAutoCapture() {
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
- stopAutoCapture() {
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 startAutoCapture method
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
- startAutoCapture() {
1382
- this.pageviewTracker.startAutoCapture();
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.stopAutoCapture();
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.stopAutoCapture();
1392
+ this.pageviewTracker.stopAutocapture();
1405
1393
  this.autocaptureTracker.stop();
1406
1394
  this.client.destroy();
1407
1395
  }