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