@journium/js 1.0.1 → 1.0.3

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
@@ -1,7 +1,7 @@
1
1
  (function (global, factory) {
2
2
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
3
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Journium = {}));
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.JourniumAnalytics = {}));
5
5
  })(this, (function (exports) { 'use strict';
6
6
 
7
7
  /**
@@ -431,7 +431,7 @@
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, publishableKey, fetchFn) => {
434
+ const fetchRemoteOptions = async (apiHost, publishableKey, fetchFn) => {
435
435
  const endpoint = '/v1/configs';
436
436
  const url = `${apiHost}${endpoint}?ingestion_key=${encodeURIComponent(publishableKey)}`;
437
437
  try {
@@ -453,42 +453,43 @@
453
453
  },
454
454
  });
455
455
  if (!response.ok) {
456
- throw new Error(`Config fetch failed: ${response.status} ${response.statusText}`);
456
+ throw new Error(`Options fetch failed: ${response.status} ${response.statusText}`);
457
457
  }
458
458
  const data = await response.json();
459
459
  return data;
460
460
  }
461
461
  catch (error) {
462
- console.warn('Failed to fetch remote config:', error);
462
+ console.warn('Failed to fetch remote options:', error);
463
463
  return null;
464
464
  }
465
465
  };
466
- const mergeConfigs = (localConfig, remoteConfig) => {
467
- if (!remoteConfig && !localConfig) {
466
+ const mergeOptions = (localOptions, remoteOptions) => {
467
+ if (!remoteOptions && !localOptions) {
468
468
  return {};
469
469
  }
470
- if (!remoteConfig) {
471
- return localConfig;
470
+ if (!remoteOptions) {
471
+ return localOptions;
472
472
  }
473
- if (!localConfig) {
474
- return remoteConfig;
473
+ if (!localOptions) {
474
+ return remoteOptions;
475
475
  }
476
- // Deep merge local config into remote config
477
- // Local config takes precedence over remote config
478
- const merged = { ...remoteConfig };
476
+ // Deep merge local options into remote options
477
+ // Local options takes precedence over remote options
478
+ const merged = { ...remoteOptions };
479
479
  // Handle primitive values
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
480
+ Object.keys(localOptions).forEach(key => {
481
+ const localValue = localOptions[key];
482
+ if (localValue !== undefined && localValue !== null) {
483
+ if (typeof localValue === 'object' && !Array.isArray(localValue)) {
484
+ // Deep merge objects - local options overrides remote
484
485
  merged[key] = {
485
486
  ...(merged[key] || {}),
486
- ...localConfig[key]
487
+ ...localValue
487
488
  };
488
489
  }
489
490
  else {
490
- // Override primitive values and arrays with local config
491
- merged[key] = localConfig[key];
491
+ // Override primitive values and arrays with local options
492
+ merged[key] = localValue;
492
493
  }
493
494
  }
494
495
  });
@@ -592,7 +593,7 @@
592
593
  };
593
594
  this.saveIdentity();
594
595
  }
595
- identify(distinctId, attributes = {}) {
596
+ identify(distinctId, _attributes = {}) {
596
597
  if (!this.identity)
597
598
  return { previousDistinctId: null };
598
599
  const previousDistinctId = this.identity.distinct_id;
@@ -685,113 +686,113 @@
685
686
  ...config,
686
687
  apiHost: config.apiHost || 'https://events.journium.app'
687
688
  };
688
- // Generate storage key for config caching
689
- this.configStorageKey = `jrnm_${config.publishableKey}_config`;
689
+ // Generate storage key for options caching
690
+ this.optionsStorageKey = `jrnm_${config.publishableKey}_options`;
690
691
  // Generate default values
691
- const defaultConfig = {
692
+ const defaultOptions = {
692
693
  debug: false,
693
694
  flushAt: 20,
694
695
  flushInterval: 10000,
695
696
  sessionTimeout: 30 * 60 * 1000, // 30 minutes
696
697
  };
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);
698
+ // Initialize effective options with local options taking precedence over defaults
699
+ this.effectiveOptions = { ...defaultOptions };
700
+ if (this.config.options) {
701
+ this.effectiveOptions = mergeOptions(defaultOptions, this.config.options);
701
702
  }
702
703
  // Initialize identity manager
703
- this.identityManager = new BrowserIdentityManager(this.effectiveConfig.sessionTimeout, this.config.publishableKey);
704
+ this.identityManager = new BrowserIdentityManager(this.effectiveOptions.sessionTimeout, this.config.publishableKey);
704
705
  // Initialize synchronously with cached config, fetch fresh config in background
705
706
  this.initializeSync();
706
- this.fetchRemoteConfigAsync();
707
+ this.fetchRemoteOptionsAsync();
707
708
  }
708
- loadCachedConfig() {
709
+ loadCachedOptions() {
709
710
  var _a;
710
711
  if (typeof window === 'undefined' || !window.localStorage) {
711
712
  return null;
712
713
  }
713
714
  try {
714
- const cached = window.localStorage.getItem(this.configStorageKey);
715
+ const cached = window.localStorage.getItem(this.optionsStorageKey);
715
716
  return cached ? JSON.parse(cached) : null;
716
717
  }
717
718
  catch (error) {
718
- if ((_a = this.effectiveConfig) === null || _a === void 0 ? void 0 : _a.debug) {
719
+ if ((_a = this.effectiveOptions) === null || _a === void 0 ? void 0 : _a.debug) {
719
720
  console.warn('Journium: Failed to load cached config:', error);
720
721
  }
721
722
  return null;
722
723
  }
723
724
  }
724
- saveCachedConfig(config) {
725
+ saveCachedOptions(options) {
725
726
  var _a;
726
727
  if (typeof window === 'undefined' || !window.localStorage) {
727
728
  return;
728
729
  }
729
730
  try {
730
- window.localStorage.setItem(this.configStorageKey, JSON.stringify(config));
731
+ window.localStorage.setItem(this.optionsStorageKey, JSON.stringify(options));
731
732
  }
732
733
  catch (error) {
733
- if ((_a = this.effectiveConfig) === null || _a === void 0 ? void 0 : _a.debug) {
734
+ if ((_a = this.effectiveOptions) === null || _a === void 0 ? void 0 : _a.debug) {
734
735
  console.warn('Journium: Failed to save config to cache:', error);
735
736
  }
736
737
  }
737
738
  }
738
739
  initializeSync() {
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);
740
+ // Step 1: Load cached remote options from localStorage (synchronous)
741
+ const cachedRemoteOptions = this.loadCachedOptions();
742
+ // Step 2: If no local options provided, use cached remote options
743
+ if (!this.config.options && cachedRemoteOptions) {
744
+ this.effectiveOptions = cachedRemoteOptions;
745
+ if (this.effectiveOptions.debug) {
746
+ console.log('Journium: Using cached remote options:', cachedRemoteOptions);
746
747
  }
747
748
  }
748
749
  // Step 3: Mark as initialized immediately - no need to wait for remote fetch
749
750
  this.initialized = true;
750
751
  // Step 4: Start flush timer immediately
751
- if (this.effectiveConfig.flushInterval && this.effectiveConfig.flushInterval > 0) {
752
+ if (this.effectiveOptions.flushInterval && this.effectiveOptions.flushInterval > 0) {
752
753
  this.startFlushTimer();
753
754
  }
754
- if (this.effectiveConfig.debug) {
755
- console.log('Journium: Client initialized with effective config:', this.effectiveConfig);
755
+ if (this.effectiveOptions.debug) {
756
+ console.log('Journium: Client initialized with effective options:', this.effectiveOptions);
756
757
  }
757
758
  }
758
- async fetchRemoteConfigAsync() {
759
+ async fetchRemoteOptionsAsync() {
759
760
  // Fetch fresh config in background
760
761
  if (this.config.publishableKey) {
761
- await this.fetchAndCacheRemoteConfig();
762
+ await this.fetchAndCacheRemoteOptions();
762
763
  }
763
764
  }
764
- async fetchAndCacheRemoteConfig() {
765
+ async fetchAndCacheRemoteOptions() {
765
766
  try {
766
- if (this.effectiveConfig.debug) {
767
+ if (this.effectiveOptions.debug) {
767
768
  console.log('Journium: Fetching remote configuration in background...');
768
769
  }
769
- const remoteConfigResponse = await fetchRemoteConfig(this.config.apiHost, this.config.publishableKey);
770
- if (remoteConfigResponse && remoteConfigResponse.success) {
770
+ const remoteOptionsResponse = await fetchRemoteOptions(this.config.apiHost, this.config.publishableKey);
771
+ if (remoteOptionsResponse && remoteOptionsResponse.success) {
771
772
  // Save remote config to cache for next session
772
- this.saveCachedConfig(remoteConfigResponse.config);
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);
773
+ this.saveCachedOptions(remoteOptionsResponse.config);
774
+ // Update effective options: local options (if provided) overrides fresh remote options
775
+ if (!this.config.options) {
776
+ // No local options provided, use fresh remote options
777
+ this.effectiveOptions = remoteOptionsResponse.config;
777
778
  }
778
779
  else {
779
- // Local config provided, merge it over fresh remote config
780
- this.effectiveConfig = mergeConfigs(this.config.config, remoteConfigResponse.config);
780
+ // Local options provided, merge it over fresh remote options
781
+ this.effectiveOptions = mergeOptions(remoteOptionsResponse.config, this.config.options);
781
782
  }
782
- // Update session timeout if provided in fresh effective config
783
- if (this.effectiveConfig.sessionTimeout) {
784
- this.identityManager.updateSessionTimeout(this.effectiveConfig.sessionTimeout);
783
+ // Update session timeout if provided in fresh effective options
784
+ if (this.effectiveOptions.sessionTimeout) {
785
+ this.identityManager.updateSessionTimeout(this.effectiveOptions.sessionTimeout);
785
786
  }
786
- if (this.effectiveConfig.debug) {
787
- console.log('Journium: Background remote configuration applied:', remoteConfigResponse.config);
788
- console.log('Journium: New effective configuration:', this.effectiveConfig);
787
+ if (this.effectiveOptions.debug) {
788
+ console.log('Journium: Background remote options applied:', remoteOptionsResponse.config);
789
+ console.log('Journium: New effective options:', this.effectiveOptions);
789
790
  }
790
791
  }
791
792
  }
792
793
  catch (error) {
793
- if (this.effectiveConfig.debug) {
794
- console.warn('Journium: Background remote config fetch failed:', error);
794
+ if (this.effectiveOptions.debug) {
795
+ console.warn('Journium: Background remote options fetch failed:', error);
795
796
  }
796
797
  }
797
798
  }
@@ -802,7 +803,7 @@
802
803
  // Use universal setInterval (works in both browser and Node.js)
803
804
  this.flushTimer = setInterval(() => {
804
805
  this.flush();
805
- }, this.effectiveConfig.flushInterval);
806
+ }, this.effectiveOptions.flushInterval);
806
807
  }
807
808
  async sendEvents(events) {
808
809
  if (!events.length)
@@ -821,12 +822,12 @@
821
822
  if (!response.ok) {
822
823
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
823
824
  }
824
- if (this.effectiveConfig.debug) {
825
+ if (this.effectiveOptions.debug) {
825
826
  console.log('Journium: Successfully sent events', events);
826
827
  }
827
828
  }
828
829
  catch (error) {
829
- if (this.effectiveConfig.debug) {
830
+ if (this.effectiveOptions.debug) {
830
831
  console.error('Journium: Failed to send events', error);
831
832
  }
832
833
  throw error;
@@ -836,7 +837,7 @@
836
837
  var _a;
837
838
  // Don't identify if SDK is not properly configured
838
839
  if (!this.config || !this.config.publishableKey || !this.initialized) {
839
- if ((_a = this.effectiveConfig) === null || _a === void 0 ? void 0 : _a.debug) {
840
+ if ((_a = this.effectiveOptions) === null || _a === void 0 ? void 0 : _a.debug) {
840
841
  console.warn('Journium: identify() call rejected - SDK not ready');
841
842
  }
842
843
  return;
@@ -849,7 +850,7 @@
849
850
  $anon_distinct_id: previousDistinctId,
850
851
  };
851
852
  this.track('$identify', identifyProperties);
852
- if (this.effectiveConfig.debug) {
853
+ if (this.effectiveOptions.debug) {
853
854
  console.log('Journium: User identified', { distinctId, attributes, previousDistinctId });
854
855
  }
855
856
  }
@@ -857,14 +858,14 @@
857
858
  var _a;
858
859
  // Don't reset if SDK is not properly configured
859
860
  if (!this.config || !this.config.publishableKey || !this.initialized) {
860
- if ((_a = this.effectiveConfig) === null || _a === void 0 ? void 0 : _a.debug) {
861
+ if ((_a = this.effectiveOptions) === null || _a === void 0 ? void 0 : _a.debug) {
861
862
  console.warn('Journium: reset() call rejected - SDK not ready');
862
863
  }
863
864
  return;
864
865
  }
865
866
  // Reset identity in identity manager
866
867
  this.identityManager.reset();
867
- if (this.effectiveConfig.debug) {
868
+ if (this.effectiveOptions.debug) {
868
869
  console.log('Journium: User identity reset');
869
870
  }
870
871
  }
@@ -872,7 +873,7 @@
872
873
  var _a;
873
874
  // Don't track if SDK is not properly configured
874
875
  if (!this.config || !this.config.publishableKey || !this.initialized) {
875
- if ((_a = this.effectiveConfig) === null || _a === void 0 ? void 0 : _a.debug) {
876
+ if ((_a = this.effectiveOptions) === null || _a === void 0 ? void 0 : _a.debug) {
876
877
  console.warn('Journium: track() call rejected - SDK not ready');
877
878
  }
878
879
  return;
@@ -900,10 +901,10 @@
900
901
  properties: eventProperties,
901
902
  };
902
903
  this.queue.push(journiumEvent);
903
- if (this.effectiveConfig.debug) {
904
+ if (this.effectiveOptions.debug) {
904
905
  console.log('Journium: Event tracked', journiumEvent);
905
906
  }
906
- if (this.queue.length >= this.effectiveConfig.flushAt) {
907
+ if (this.queue.length >= this.effectiveOptions.flushAt) {
907
908
  this.flush();
908
909
  }
909
910
  }
@@ -931,6 +932,9 @@
931
932
  }
932
933
  this.flush();
933
934
  }
935
+ getEffectiveOptions() {
936
+ return this.effectiveOptions;
937
+ }
934
938
  }
935
939
 
936
940
  class PageviewTracker {
@@ -996,11 +1000,11 @@
996
1000
  }
997
1001
 
998
1002
  class AutocaptureTracker {
999
- constructor(client, config = {}) {
1003
+ constructor(client, options = {}) {
1000
1004
  this.listeners = new Map();
1001
1005
  this.isActive = false;
1002
1006
  this.client = client;
1003
- this.config = {
1007
+ this.options = {
1004
1008
  captureClicks: true,
1005
1009
  captureFormSubmits: true,
1006
1010
  captureFormChanges: true,
@@ -1008,7 +1012,7 @@
1008
1012
  ignoreClasses: ['journium-ignore'],
1009
1013
  ignoreElements: ['script', 'style', 'noscript'],
1010
1014
  captureContentText: true,
1011
- ...config,
1015
+ ...options,
1012
1016
  };
1013
1017
  }
1014
1018
  start() {
@@ -1016,16 +1020,16 @@
1016
1020
  return;
1017
1021
  }
1018
1022
  this.isActive = true;
1019
- if (this.config.captureClicks) {
1023
+ if (this.options.captureClicks) {
1020
1024
  this.addClickListener();
1021
1025
  }
1022
- if (this.config.captureFormSubmits) {
1026
+ if (this.options.captureFormSubmits) {
1023
1027
  this.addFormSubmitListener();
1024
1028
  }
1025
- if (this.config.captureFormChanges) {
1029
+ if (this.options.captureFormChanges) {
1026
1030
  this.addFormChangeListener();
1027
1031
  }
1028
- if (this.config.captureTextSelection) {
1032
+ if (this.options.captureTextSelection) {
1029
1033
  this.addTextSelectionListener();
1030
1034
  }
1031
1035
  }
@@ -1109,17 +1113,17 @@
1109
1113
  return true;
1110
1114
  }
1111
1115
  // Check if element should be ignored by tag name
1112
- if ((_a = this.config.ignoreElements) === null || _a === void 0 ? void 0 : _a.includes(element.tagName.toLowerCase())) {
1116
+ if ((_a = this.options.ignoreElements) === null || _a === void 0 ? void 0 : _a.includes(element.tagName.toLowerCase())) {
1113
1117
  return true;
1114
1118
  }
1115
1119
  // Check if element has ignore classes
1116
- if ((_b = this.config.ignoreClasses) === null || _b === void 0 ? void 0 : _b.some(cls => element.classList.contains(cls))) {
1120
+ if ((_b = this.options.ignoreClasses) === null || _b === void 0 ? void 0 : _b.some(cls => element.classList.contains(cls))) {
1117
1121
  return true;
1118
1122
  }
1119
1123
  // Check parent elements for ignore classes
1120
1124
  let parent = element.parentElement;
1121
1125
  while (parent) {
1122
- if ((_c = this.config.ignoreClasses) === null || _c === void 0 ? void 0 : _c.some(cls => parent.classList.contains(cls))) {
1126
+ if ((_c = this.options.ignoreClasses) === null || _c === void 0 ? void 0 : _c.some(cls => parent.classList.contains(cls))) {
1123
1127
  return true;
1124
1128
  }
1125
1129
  parent = parent.parentElement;
@@ -1151,7 +1155,7 @@
1151
1155
  }
1152
1156
  });
1153
1157
  // Element content
1154
- if (this.config.captureContentText) {
1158
+ if (this.options.captureContentText) {
1155
1159
  const text = this.getElementText(element);
1156
1160
  if (text) {
1157
1161
  properties.$element_text = text.substring(0, 200); // Limit text length
@@ -1338,18 +1342,18 @@
1338
1342
  }
1339
1343
  }
1340
1344
 
1341
- class Journium {
1345
+ class JourniumAnalytics {
1342
1346
  constructor(config) {
1343
1347
  var _a, _b;
1344
1348
  this.config = config;
1345
1349
  this.client = new JourniumClient(config);
1346
1350
  this.pageviewTracker = new PageviewTracker(this.client);
1347
- const autocaptureConfig = this.resolveAutocaptureConfig((_a = config.config) === null || _a === void 0 ? void 0 : _a.autocapture);
1348
- this.autocaptureTracker = new AutocaptureTracker(this.client, autocaptureConfig);
1351
+ const autocaptureOptions = this.resolveAutocaptureOptions((_a = config.options) === null || _a === void 0 ? void 0 : _a.autocapture);
1352
+ this.autocaptureTracker = new AutocaptureTracker(this.client, autocaptureOptions);
1349
1353
  // Store resolved autocapture state for startAutocapture method
1350
- this.autocaptureEnabled = ((_b = config.config) === null || _b === void 0 ? void 0 : _b.autocapture) !== false;
1354
+ this.autocaptureEnabled = ((_b = config.options) === null || _b === void 0 ? void 0 : _b.autocapture) !== false;
1351
1355
  }
1352
- resolveAutocaptureConfig(autocapture) {
1356
+ resolveAutocaptureOptions(autocapture) {
1353
1357
  if (autocapture === false) {
1354
1358
  return {
1355
1359
  captureClicks: false,
@@ -1376,7 +1380,12 @@
1376
1380
  this.pageviewTracker.capturePageview(properties);
1377
1381
  }
1378
1382
  startAutocapture() {
1379
- this.pageviewTracker.startAutocapture();
1383
+ // Check if automatic pageview tracking is enabled (defaults to true)
1384
+ const effectiveOptions = this.client.getEffectiveOptions();
1385
+ const autoTrackPageviews = effectiveOptions.autoTrackPageviews !== false;
1386
+ if (autoTrackPageviews) {
1387
+ this.pageviewTracker.startAutocapture();
1388
+ }
1380
1389
  if (this.autocaptureEnabled) {
1381
1390
  this.autocaptureTracker.start();
1382
1391
  }
@@ -1388,6 +1397,9 @@
1388
1397
  async flush() {
1389
1398
  return this.client.flush();
1390
1399
  }
1400
+ getEffectiveOptions() {
1401
+ return this.client.getEffectiveOptions();
1402
+ }
1391
1403
  destroy() {
1392
1404
  this.pageviewTracker.stopAutocapture();
1393
1405
  this.autocaptureTracker.stop();
@@ -1395,15 +1407,15 @@
1395
1407
  }
1396
1408
  }
1397
1409
  const init = (config) => {
1398
- return new Journium(config);
1410
+ return new JourniumAnalytics(config);
1399
1411
  };
1400
1412
 
1401
1413
  exports.AutocaptureTracker = AutocaptureTracker;
1402
1414
  exports.BrowserIdentityManager = BrowserIdentityManager;
1403
- exports.Journium = Journium;
1415
+ exports.JourniumAnalytics = JourniumAnalytics;
1404
1416
  exports.JourniumClient = JourniumClient;
1405
1417
  exports.PageviewTracker = PageviewTracker;
1406
- exports.fetchRemoteConfig = fetchRemoteConfig;
1418
+ exports.fetchRemoteOptions = fetchRemoteOptions;
1407
1419
  exports.generateId = generateId;
1408
1420
  exports.generateUuidv7 = generateUuidv7;
1409
1421
  exports.getCurrentTimestamp = getCurrentTimestamp;
@@ -1413,7 +1425,7 @@
1413
1425
  exports.init = init;
1414
1426
  exports.isBrowser = isBrowser;
1415
1427
  exports.isNode = isNode;
1416
- exports.mergeConfigs = mergeConfigs;
1428
+ exports.mergeOptions = mergeOptions;
1417
1429
 
1418
1430
  }));
1419
1431
  //# sourceMappingURL=index.umd.js.map