@journium/react 1.2.1 → 1.3.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAkD,SAAS,EAAE,MAAM,OAAO,CAAC;AACzF,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEtE,KAAK,yBAAyB,GAAG,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC;AAEzD,UAAU,oBAAoB;IAC5B,SAAS,EAAE,yBAAyB,GAAG,IAAI,CAAC;IAC5C,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IAC9B,gBAAgB,EAAE,oBAAoB,GAAG,IAAI,CAAC;CAC/C;AAID,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,EAAE,cAAc,CAAC;CACxB;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAuC5D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,WAAW,QAAO,oBAM9B,CAAC"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAA2D,SAAS,EAAE,MAAM,OAAO,CAAC;AAClG,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAGtE,KAAK,yBAAyB,GAAG,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC;AAEzD,UAAU,oBAAoB;IAC5B,SAAS,EAAE,yBAAyB,GAAG,IAAI,CAAC;IAC5C,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IAC9B,gBAAgB,EAAE,oBAAoB,GAAG,IAAI,CAAC;CAC/C;AAID,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,EAAE,cAAc,CAAC;CACxB;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CA4C5D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,WAAW,QAAO,oBAM9B,CAAC"}
package/dist/index.cjs CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  var React = require('react');
4
4
 
5
+ // @journium/js@1.3.0 is replaced at build time by @rollup/plugin-replace
6
+ const SDK_VERSION$1 = '@journium/js@1.3.0';
7
+
5
8
  /**
6
9
  * uuidv7: A JavaScript implementation of UUID version 7
7
10
  *
@@ -942,6 +945,7 @@ class JourniumClient {
942
945
  Logger.setDebug((_a = this.effectiveOptions.debug) !== null && _a !== void 0 ? _a : false);
943
946
  }
944
947
  buildIdentityProperties(userProperties = {}) {
948
+ var _a, _b;
945
949
  const identity = this.identityManager.getIdentity();
946
950
  const userAgentInfo = this.identityManager.getUserAgentInfo();
947
951
  return {
@@ -952,7 +956,7 @@ class JourniumClient {
952
956
  $current_url: typeof window !== 'undefined' ? window.location.href : '',
953
957
  $pathname: typeof window !== 'undefined' ? window.location.pathname : '',
954
958
  ...userAgentInfo,
955
- $lib_version: '0.1.0', // TODO: Get from package.json
959
+ $sdk_version: (_b = (_a = this.config.options) === null || _a === void 0 ? void 0 : _a._sdkVersion) !== null && _b !== void 0 ? _b : 'unknown',
956
960
  $platform: 'web',
957
961
  ...userProperties,
958
962
  };
@@ -1093,7 +1097,7 @@ class PageviewTracker {
1093
1097
  $host: url.host,
1094
1098
  $pathname: url.pathname,
1095
1099
  $search: url.search,
1096
- $title: getPageTitle(),
1100
+ $page_title: getPageTitle(),
1097
1101
  $referrer: getReferrer(),
1098
1102
  ...customProperties,
1099
1103
  };
@@ -1169,6 +1173,8 @@ class AutocaptureTracker {
1169
1173
  ignoreClasses: ['journium-ignore'],
1170
1174
  ignoreElements: ['script', 'style', 'noscript'],
1171
1175
  captureContentText: true,
1176
+ dataAttributePrefixes: ['jrnm-'],
1177
+ dataAttributeNames: ['data-testid', 'data-track'],
1172
1178
  ...options,
1173
1179
  };
1174
1180
  }
@@ -1190,6 +1196,8 @@ class AutocaptureTracker {
1190
1196
  ignoreClasses: ['journium-ignore'],
1191
1197
  ignoreElements: ['script', 'style', 'noscript'],
1192
1198
  captureContentText: true,
1199
+ dataAttributePrefixes: ['jrnm-'],
1200
+ dataAttributeNames: ['data-testid', 'data-track'],
1193
1201
  ...options,
1194
1202
  };
1195
1203
  // Restart if it was active before
@@ -1232,10 +1240,7 @@ class AutocaptureTracker {
1232
1240
  return;
1233
1241
  }
1234
1242
  const properties = this.getElementProperties(target, 'click');
1235
- this.client.track('$autocapture', {
1236
- $event_type: 'click',
1237
- ...properties,
1238
- });
1243
+ this.client.track('$autocapture', properties);
1239
1244
  };
1240
1245
  document.addEventListener('click', clickListener, true);
1241
1246
  this.listeners.set('click', clickListener);
@@ -1247,10 +1252,7 @@ class AutocaptureTracker {
1247
1252
  return;
1248
1253
  }
1249
1254
  const properties = this.getFormProperties(target, 'submit');
1250
- this.client.track('$autocapture', {
1251
- $event_type: 'submit',
1252
- ...properties,
1253
- });
1255
+ this.client.track('$autocapture', properties);
1254
1256
  };
1255
1257
  document.addEventListener('submit', submitListener, true);
1256
1258
  this.listeners.set('submit', submitListener);
@@ -1262,10 +1264,7 @@ class AutocaptureTracker {
1262
1264
  return;
1263
1265
  }
1264
1266
  const properties = this.getInputProperties(target, 'change');
1265
- this.client.track('$autocapture', {
1266
- $event_type: 'change',
1267
- ...properties,
1268
- });
1267
+ this.client.track('$autocapture', properties);
1269
1268
  };
1270
1269
  document.addEventListener('change', changeListener, true);
1271
1270
  this.listeners.set('change', changeListener);
@@ -1318,6 +1317,7 @@ class AutocaptureTracker {
1318
1317
  }
1319
1318
  getElementProperties(element, eventType) {
1320
1319
  const properties = {
1320
+ $event_type: eventType,
1321
1321
  $element_tag: element.tagName.toLowerCase(),
1322
1322
  $element_type: this.getElementType(element),
1323
1323
  };
@@ -1327,6 +1327,7 @@ class AutocaptureTracker {
1327
1327
  }
1328
1328
  if (element.className) {
1329
1329
  properties.$element_classes = Array.from(element.classList);
1330
+ properties.$element_semantic_classes = this.extractSemanticClasses(element.classList);
1330
1331
  }
1331
1332
  // Element attributes
1332
1333
  const relevantAttributes = ['name', 'role', 'aria-label', 'data-testid', 'data-track'];
@@ -1336,6 +1337,33 @@ class AutocaptureTracker {
1336
1337
  properties[`$element_${attr.replace('-', '_')}`] = value;
1337
1338
  }
1338
1339
  });
1340
+ // Configurable data-* attribute capture
1341
+ const prefixes = this.options.dataAttributePrefixes || ['jrnm-'];
1342
+ const exactNames = new Set(this.options.dataAttributeNames || ['data-testid', 'data-track']);
1343
+ const relevantSet = new Set(relevantAttributes);
1344
+ let dataAttrCount = 0;
1345
+ for (let i = 0; i < element.attributes.length && dataAttrCount < 10; i++) {
1346
+ const attr = element.attributes.item(i);
1347
+ if (!attr || !attr.name.startsWith('data-'))
1348
+ continue;
1349
+ if (relevantSet.has(attr.name))
1350
+ continue;
1351
+ const suffix = attr.name.slice(5); // strip 'data-'
1352
+ const matchesPrefix = prefixes.some(p => suffix.startsWith(p));
1353
+ const matchesName = exactNames.has(attr.name);
1354
+ if (matchesPrefix || matchesName) {
1355
+ const propName = `$attr_${attr.name.replace(/-/g, '_')}`;
1356
+ properties[propName] = attr.value;
1357
+ dataAttrCount++;
1358
+ }
1359
+ }
1360
+ // Link href as first-class property
1361
+ if (element.tagName.toLowerCase() === 'a') {
1362
+ const href = element.getAttribute('href');
1363
+ if (href) {
1364
+ properties.$element_href = href;
1365
+ }
1366
+ }
1339
1367
  // Element content
1340
1368
  if (this.options.captureContentText) {
1341
1369
  const text = this.getElementText(element);
@@ -1365,10 +1393,13 @@ class AutocaptureTracker {
1365
1393
  properties.$parent_id = element.parentElement.id;
1366
1394
  }
1367
1395
  }
1368
- // URL information
1396
+ // URL and page context
1369
1397
  properties.$current_url = window.location.href;
1370
1398
  properties.$host = window.location.host;
1371
1399
  properties.$pathname = window.location.pathname;
1400
+ properties.$search = window.location.search;
1401
+ properties.$page_title = document.title;
1402
+ properties.$referrer = document.referrer;
1372
1403
  return properties;
1373
1404
  }
1374
1405
  getFormProperties(form, eventType) {
@@ -1517,6 +1548,38 @@ class AutocaptureTracker {
1517
1548
  ids: ids.reverse()
1518
1549
  };
1519
1550
  }
1551
+ extractSemanticClasses(classList) {
1552
+ const results = new Set();
1553
+ for (let i = 0; i < classList.length; i++) {
1554
+ const cls = classList.item(i);
1555
+ if (!cls)
1556
+ continue;
1557
+ const parts = cls.split('__');
1558
+ if (parts.length >= 3) {
1559
+ // CSS module pattern: Module__hash__name → take last segment
1560
+ const last = parts[parts.length - 1];
1561
+ if (last)
1562
+ results.add(last);
1563
+ }
1564
+ else if (parts.length === 2) {
1565
+ // 2-part __ class (e.g., Module__hash) → drop, no semantic name
1566
+ continue;
1567
+ }
1568
+ else {
1569
+ // Single-part class — keep unless it looks like a hash
1570
+ if (!this.isHashLike(cls)) {
1571
+ results.add(cls);
1572
+ }
1573
+ }
1574
+ }
1575
+ return Array.from(results);
1576
+ }
1577
+ isHashLike(value) {
1578
+ // Hash-like: alphanumeric, 5-10 chars, contains both letters and digits
1579
+ return /^[a-zA-Z0-9]{5,10}$/.test(value)
1580
+ && /[a-zA-Z]/.test(value)
1581
+ && /[0-9]/.test(value);
1582
+ }
1520
1583
  isSafeInputType(type) {
1521
1584
  // Don't capture values for sensitive input types
1522
1585
  const sensitiveTypes = ['password', 'email', 'tel', 'credit-card-number'];
@@ -1703,9 +1766,20 @@ class JourniumAnalytics {
1703
1766
  }
1704
1767
  /** Create and return a new JourniumAnalytics instance for the given config. */
1705
1768
  const init = (config) => {
1769
+ var _a;
1770
+ // Set SDK version if not already set by a framework SDK (React, Next.js, Angular)
1771
+ if (!((_a = config.options) === null || _a === void 0 ? void 0 : _a._sdkVersion)) {
1772
+ config = {
1773
+ ...config,
1774
+ options: { ...config.options, _sdkVersion: SDK_VERSION$1 },
1775
+ };
1776
+ }
1706
1777
  return new JourniumAnalytics(config);
1707
1778
  };
1708
1779
 
1780
+ // @journium/react@1.3.0 is replaced at build time by @rollup/plugin-replace
1781
+ const SDK_VERSION = '@journium/react@1.3.0';
1782
+
1709
1783
  const JourniumContext = React.createContext(undefined);
1710
1784
  /**
1711
1785
  * Provides the Journium analytics instance to the React tree.
@@ -1715,8 +1789,12 @@ const JourniumContext = React.createContext(undefined);
1715
1789
  const JourniumProvider = ({ children, config, }) => {
1716
1790
  const [analytics, setAnalytics] = React.useState(null);
1717
1791
  const [effectiveOptions, setEffectiveOptions] = React.useState(null);
1792
+ const configWithSdk = React.useMemo(() => ({
1793
+ ...config,
1794
+ options: { _sdkVersion: SDK_VERSION, ...config.options },
1795
+ }), [config]);
1718
1796
  React.useEffect(() => {
1719
- const analyticsInstance = init(config);
1797
+ const analyticsInstance = init(configWithSdk);
1720
1798
  // Get initial effective options (may be empty during remote-first initialization)
1721
1799
  const initialEffective = analyticsInstance.getEffectiveOptions();
1722
1800
  setEffectiveOptions(initialEffective);
@@ -1736,7 +1814,7 @@ const JourniumProvider = ({ children, config, }) => {
1736
1814
  setAnalytics(null);
1737
1815
  setEffectiveOptions(null);
1738
1816
  };
1739
- }, [config]);
1817
+ }, [configWithSdk]);
1740
1818
  return (React.createElement(JourniumContext.Provider, { value: { analytics, config, effectiveOptions } }, children));
1741
1819
  };
1742
1820
  /**