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