@journium/react 1.2.0 → 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.
- package/dist/context.d.ts.map +1 -1
- package/dist/index.cjs +100 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +101 -23
- package/dist/index.mjs.map +1 -1
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/package.json +3 -3
package/dist/context.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
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
|
-
$
|
|
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
|
-
$
|
|
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
|
|
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'];
|
|
@@ -1543,8 +1606,8 @@ class JourniumAnalytics {
|
|
|
1543
1606
|
// This handles cached remote options or local options with autocapture enabled
|
|
1544
1607
|
this.startAutocaptureIfEnabled(initialEffectiveOptions);
|
|
1545
1608
|
}
|
|
1546
|
-
resolvePageviewOptions(autoTrackPageviews) {
|
|
1547
|
-
if (autoTrackPageviews === false) {
|
|
1609
|
+
resolvePageviewOptions(autoTrackPageviews, frameworkHandlesPageviews) {
|
|
1610
|
+
if (autoTrackPageviews === false || frameworkHandlesPageviews) {
|
|
1548
1611
|
return { enabled: false, trackSpaPageviews: false, captureInitialPageview: false };
|
|
1549
1612
|
}
|
|
1550
1613
|
if (autoTrackPageviews === true || autoTrackPageviews === undefined) {
|
|
@@ -1598,7 +1661,7 @@ class JourniumAnalytics {
|
|
|
1598
1661
|
// Only start if effectiveOptions are actually loaded (non-empty)
|
|
1599
1662
|
const hasOptions = effectiveOptions && Object.keys(effectiveOptions).length > 0;
|
|
1600
1663
|
const { enabled: autoTrackPageviews, trackSpaPageviews, captureInitialPageview } = hasOptions
|
|
1601
|
-
? this.resolvePageviewOptions(effectiveOptions.autoTrackPageviews)
|
|
1664
|
+
? this.resolvePageviewOptions(effectiveOptions.autoTrackPageviews, effectiveOptions._frameworkHandlesPageviews)
|
|
1602
1665
|
: { enabled: false, trackSpaPageviews: false, captureInitialPageview: false };
|
|
1603
1666
|
const autocaptureEnabled = hasOptions
|
|
1604
1667
|
? effectiveOptions.autocapture !== false
|
|
@@ -1634,7 +1697,7 @@ class JourniumAnalytics {
|
|
|
1634
1697
|
const hasActualOptions = effectiveOptions && Object.keys(effectiveOptions).length > 0;
|
|
1635
1698
|
if (hasActualOptions) {
|
|
1636
1699
|
// Use same logic as manual startAutocapture() but only start automatically
|
|
1637
|
-
const { enabled: autoTrackPageviews, trackSpaPageviews, captureInitialPageview } = this.resolvePageviewOptions(effectiveOptions.autoTrackPageviews);
|
|
1700
|
+
const { enabled: autoTrackPageviews, trackSpaPageviews, captureInitialPageview } = this.resolvePageviewOptions(effectiveOptions.autoTrackPageviews, effectiveOptions._frameworkHandlesPageviews);
|
|
1638
1701
|
const autocaptureEnabled = effectiveOptions.autocapture !== false;
|
|
1639
1702
|
// Update autocapture tracker options
|
|
1640
1703
|
const autocaptureOptions = this.resolveAutocaptureOptions(effectiveOptions.autocapture);
|
|
@@ -1665,7 +1728,7 @@ class JourniumAnalytics {
|
|
|
1665
1728
|
this.autocaptureTracker.stop();
|
|
1666
1729
|
this.autocaptureStarted = false;
|
|
1667
1730
|
}
|
|
1668
|
-
const { enabled: autoTrackPageviews, trackSpaPageviews, captureInitialPageview } = this.resolvePageviewOptions(effectiveOptions.autoTrackPageviews);
|
|
1731
|
+
const { enabled: autoTrackPageviews, trackSpaPageviews, captureInitialPageview } = this.resolvePageviewOptions(effectiveOptions.autoTrackPageviews, effectiveOptions._frameworkHandlesPageviews);
|
|
1669
1732
|
const autocaptureEnabled = effectiveOptions.autocapture !== false;
|
|
1670
1733
|
const autocaptureOptions = this.resolveAutocaptureOptions(effectiveOptions.autocapture);
|
|
1671
1734
|
this.autocaptureTracker.updateOptions(autocaptureOptions);
|
|
@@ -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(
|
|
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
|
-
}, [
|
|
1817
|
+
}, [configWithSdk]);
|
|
1740
1818
|
return (React.createElement(JourniumContext.Provider, { value: { analytics, config, effectiveOptions } }, children));
|
|
1741
1819
|
};
|
|
1742
1820
|
/**
|