@journium/js 1.2.3 → 1.3.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.
@@ -27,6 +27,11 @@ export declare class AutocaptureTracker {
27
27
  private getElementType;
28
28
  private getElementText;
29
29
  private getElementsChain;
30
+ private extractSemanticClasses;
31
+ private isHashLike;
32
+ private getVisibleTextContent;
33
+ private getElementState;
34
+ private findInteractiveAncestor;
30
35
  private isSafeInputType;
31
36
  }
32
37
  //# sourceMappingURL=AutocaptureTracker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AutocaptureTracker.d.ts","sourceRoot":"","sources":["../src/AutocaptureTracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAa,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAE/D;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,SAAS,CAAyC;IAC1D,OAAO,CAAC,QAAQ,CAAkB;gBAEtB,MAAM,EAAE,cAAc,EAAE,OAAO,GAAE,kBAAuB;IAcpE;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI;IA0BhD,KAAK,IAAI,IAAI;IAwBb,IAAI,IAAI,IAAI;IAcZ,OAAO,CAAC,gBAAgB;IAoBxB,OAAO,CAAC,qBAAqB;IAoB7B,OAAO,CAAC,qBAAqB;IAoB7B,OAAO,CAAC,wBAAwB;IAuBhC,OAAO,CAAC,mBAAmB;IA2B3B,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,oBAAoB;IAiE5B,OAAO,CAAC,iBAAiB;IAsBzB,OAAO,CAAC,kBAAkB;IAuC1B,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,cAAc;IAiBtB,OAAO,CAAC,gBAAgB;IAqFxB,OAAO,CAAC,eAAe;CAKxB"}
1
+ {"version":3,"file":"AutocaptureTracker.d.ts","sourceRoot":"","sources":["../src/AutocaptureTracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAa,kBAAkB,EAA6B,MAAM,gBAAgB,CAAC;AAE1F;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,SAAS,CAAyC;IAC1D,OAAO,CAAC,QAAQ,CAAkB;gBAEtB,MAAM,EAAE,cAAc,EAAE,OAAO,GAAE,kBAAuB;IAgBpE;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI;IA4BhD,KAAK,IAAI,IAAI;IAwBb,IAAI,IAAI,IAAI;IAcZ,OAAO,CAAC,gBAAgB;IAiBxB,OAAO,CAAC,qBAAqB;IAgB7B,OAAO,CAAC,qBAAqB;IAgB7B,OAAO,CAAC,wBAAwB;IA6BhC,OAAO,CAAC,mBAAmB;IA2B3B,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,oBAAoB;IA2G5B,OAAO,CAAC,iBAAiB;IAsBzB,OAAO,CAAC,kBAAkB;IAuC1B,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,cAAc;IAqDtB,OAAO,CAAC,gBAAgB;IAqFxB,OAAO,CAAC,sBAAsB;IA0B9B,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,qBAAqB;IAiB7B,OAAO,CAAC,eAAe;IA2BvB,OAAO,CAAC,uBAAuB;IAgB/B,OAAO,CAAC,eAAe;CAKxB"}
@@ -1 +1 @@
1
- {"version":3,"file":"JourniumAnalytics.d.ts","sourceRoot":"","sources":["../src/JourniumAnalytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAiD,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAKrH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,wBAAwB,CAAC,CAAa;gBAElC,MAAM,EAAE,cAAc;IAqBlC,OAAO,CAAC,sBAAsB;IAsB9B,OAAO,CAAC,yBAAyB;IAiBjC,qDAAqD;IACrD,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIhE,wFAAwF;IACxF,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIxE,oEAAoE;IACpE,KAAK,IAAI,IAAI;IAIb,0EAA0E;IAC1E,eAAe,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI3D;;;;OAIG;IACH,gBAAgB,IAAI,IAAI;IA6BxB,yEAAyE;IACzE,eAAe,IAAI,IAAI;IAMvB;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAoCjC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAiC3B,qEAAqE;IAC/D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,0EAA0E;IAC1E,mBAAmB;IAInB;;OAEG;IACH,eAAe,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,GAAG,MAAM,IAAI;IAI9E,wGAAwG;IACxG,OAAO,IAAI,IAAI;CAQhB;AAED,+EAA+E;AAC/E,eAAO,MAAM,IAAI,GAAI,QAAQ,cAAc,KAAG,iBAE7C,CAAC;;mBAF2B,cAAc,KAAG,iBAAiB;;AAI/D,wBAAwB"}
1
+ {"version":3,"file":"JourniumAnalytics.d.ts","sourceRoot":"","sources":["../src/JourniumAnalytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAiD,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAMrH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,wBAAwB,CAAC,CAAa;gBAElC,MAAM,EAAE,cAAc;IAqBlC,OAAO,CAAC,sBAAsB;IAsB9B,OAAO,CAAC,yBAAyB;IAiBjC,qDAAqD;IACrD,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIhE,wFAAwF;IACxF,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIxE,oEAAoE;IACpE,KAAK,IAAI,IAAI;IAIb,0EAA0E;IAC1E,eAAe,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI3D;;;;OAIG;IACH,gBAAgB,IAAI,IAAI;IA6BxB,yEAAyE;IACzE,eAAe,IAAI,IAAI;IAMvB;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAoCjC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAiC3B,qEAAqE;IAC/D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,0EAA0E;IAC1E,mBAAmB;IAInB;;OAEG;IACH,eAAe,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,GAAG,MAAM,IAAI;IAI9E,wGAAwG;IACxG,OAAO,IAAI,IAAI;CAQhB;AAED,+EAA+E;AAC/E,eAAO,MAAM,IAAI,GAAI,QAAQ,cAAc,KAAG,iBAS7C,CAAC;;mBAT2B,cAAc,KAAG,iBAAiB;;AAW/D,wBAAwB"}
@@ -1,3 +1,4 @@
1
+ import { PageviewProperties } from '@journium/core';
1
2
  import { JourniumClient } from './JourniumClient';
2
3
  export declare class PageviewTracker {
3
4
  private client;
@@ -6,7 +7,7 @@ export declare class PageviewTracker {
6
7
  private originalReplaceState;
7
8
  private popStateHandler;
8
9
  constructor(client: JourniumClient);
9
- capturePageview(customProperties?: Record<string, unknown>): void;
10
+ capturePageview(customProperties?: PageviewProperties): void;
10
11
  /**
11
12
  * Start automatic autocapture for pageviews
12
13
  * @param captureInitialPageview - whether to fire a $pageview immediately on start (default: true).
@@ -1 +1 @@
1
- {"version":3,"file":"PageviewTracker.d.ts","sourceRoot":"","sources":["../src/PageviewTracker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,iBAAiB,CAAgD;IACzE,OAAO,CAAC,oBAAoB,CAAmD;IAC/E,OAAO,CAAC,eAAe,CAA6B;gBAExC,MAAM,EAAE,cAAc;IAIlC,eAAe,CAAC,gBAAgB,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI;IAkBrE;;;;;;OAMG;IACH,yBAAyB,CAAC,sBAAsB,GAAE,OAAc,EAAE,YAAY,GAAE,OAAc,GAAG,IAAI;IA8BrG;;;OAGG;IACH,eAAe,IAAI,IAAI;CAmBxB"}
1
+ {"version":3,"file":"PageviewTracker.d.ts","sourceRoot":"","sources":["../src/PageviewTracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAA4C,MAAM,gBAAgB,CAAC;AAC9F,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,iBAAiB,CAAgD;IACzE,OAAO,CAAC,oBAAoB,CAAmD;IAC/E,OAAO,CAAC,eAAe,CAA6B;gBAExC,MAAM,EAAE,cAAc;IAIlC,eAAe,CAAC,gBAAgB,GAAE,kBAAuB,GAAG,IAAI;IAoBhE;;;;;;OAMG;IACH,yBAAyB,CAAC,sBAAsB,GAAE,OAAc,EAAE,YAAY,GAAE,OAAc,GAAG,IAAI;IA8BrG;;;OAGG;IACH,eAAe,IAAI,IAAI;CAmBxB"}
package/dist/index.cjs CHANGED
@@ -1,5 +1,8 @@
1
1
  'use strict';
2
2
 
3
+ // @journium/js@1.3.1 is replaced at build time by @rollup/plugin-replace
4
+ const SDK_VERSION = '@journium/js@1.3.1';
5
+
3
6
  /**
4
7
  * uuidv7: A JavaScript implementation of UUID version 7
5
8
  *
@@ -940,6 +943,7 @@ class JourniumClient {
940
943
  Logger.setDebug((_a = this.effectiveOptions.debug) !== null && _a !== void 0 ? _a : false);
941
944
  }
942
945
  buildIdentityProperties(userProperties = {}) {
946
+ var _a, _b;
943
947
  const identity = this.identityManager.getIdentity();
944
948
  const userAgentInfo = this.identityManager.getUserAgentInfo();
945
949
  return {
@@ -950,7 +954,7 @@ class JourniumClient {
950
954
  $current_url: typeof window !== 'undefined' ? window.location.href : '',
951
955
  $pathname: typeof window !== 'undefined' ? window.location.pathname : '',
952
956
  ...userAgentInfo,
953
- $lib_version: '0.1.0', // TODO: Get from package.json
957
+ $sdk_version: (_b = (_a = this.config.options) === null || _a === void 0 ? void 0 : _a._sdkVersion) !== null && _b !== void 0 ? _b : 'unknown',
954
958
  $platform: 'web',
955
959
  ...userProperties,
956
960
  };
@@ -1091,8 +1095,10 @@ class PageviewTracker {
1091
1095
  $host: url.host,
1092
1096
  $pathname: url.pathname,
1093
1097
  $search: url.search,
1094
- $title: getPageTitle(),
1098
+ $page_title: getPageTitle(),
1095
1099
  $referrer: getReferrer(),
1100
+ $previous_url: this.lastUrl || '',
1101
+ $previous_pathname: this.lastUrl ? new URL(this.lastUrl).pathname : '',
1096
1102
  ...customProperties,
1097
1103
  };
1098
1104
  this.client.track('$pageview', properties);
@@ -1167,6 +1173,8 @@ class AutocaptureTracker {
1167
1173
  ignoreClasses: ['journium-ignore'],
1168
1174
  ignoreElements: ['script', 'style', 'noscript'],
1169
1175
  captureContentText: true,
1176
+ dataAttributePrefixes: ['jrnm-'],
1177
+ dataAttributeNames: ['data-testid', 'data-track'],
1170
1178
  ...options,
1171
1179
  };
1172
1180
  }
@@ -1188,6 +1196,8 @@ class AutocaptureTracker {
1188
1196
  ignoreClasses: ['journium-ignore'],
1189
1197
  ignoreElements: ['script', 'style', 'noscript'],
1190
1198
  captureContentText: true,
1199
+ dataAttributePrefixes: ['jrnm-'],
1200
+ dataAttributeNames: ['data-testid', 'data-track'],
1191
1201
  ...options,
1192
1202
  };
1193
1203
  // Restart if it was active before
@@ -1225,15 +1235,14 @@ class AutocaptureTracker {
1225
1235
  }
1226
1236
  addClickListener() {
1227
1237
  const clickListener = (event) => {
1228
- const target = event.target;
1238
+ var _a;
1239
+ const rawTarget = event.target;
1240
+ const target = (_a = this.findInteractiveAncestor(rawTarget)) !== null && _a !== void 0 ? _a : rawTarget;
1229
1241
  if (this.shouldIgnoreElement(target)) {
1230
1242
  return;
1231
1243
  }
1232
1244
  const properties = this.getElementProperties(target, 'click');
1233
- this.client.track('$autocapture', {
1234
- $event_type: 'click',
1235
- ...properties,
1236
- });
1245
+ this.client.track('$autocapture', properties);
1237
1246
  };
1238
1247
  document.addEventListener('click', clickListener, true);
1239
1248
  this.listeners.set('click', clickListener);
@@ -1245,10 +1254,7 @@ class AutocaptureTracker {
1245
1254
  return;
1246
1255
  }
1247
1256
  const properties = this.getFormProperties(target, 'submit');
1248
- this.client.track('$autocapture', {
1249
- $event_type: 'submit',
1250
- ...properties,
1251
- });
1257
+ this.client.track('$autocapture', properties);
1252
1258
  };
1253
1259
  document.addEventListener('submit', submitListener, true);
1254
1260
  this.listeners.set('submit', submitListener);
@@ -1260,10 +1266,7 @@ class AutocaptureTracker {
1260
1266
  return;
1261
1267
  }
1262
1268
  const properties = this.getInputProperties(target, 'change');
1263
- this.client.track('$autocapture', {
1264
- $event_type: 'change',
1265
- ...properties,
1266
- });
1269
+ this.client.track('$autocapture', properties);
1267
1270
  };
1268
1271
  document.addEventListener('change', changeListener, true);
1269
1272
  this.listeners.set('change', changeListener);
@@ -1282,6 +1285,12 @@ class AutocaptureTracker {
1282
1285
  $event_type: 'text_selection',
1283
1286
  $selected_text: selectedText.substring(0, 200), // Limit text length
1284
1287
  $selection_length: selectedText.length,
1288
+ $current_url: window.location.href,
1289
+ $host: window.location.host,
1290
+ $pathname: window.location.pathname,
1291
+ $search: window.location.search,
1292
+ $page_title: document.title,
1293
+ $referrer: document.referrer,
1285
1294
  });
1286
1295
  };
1287
1296
  document.addEventListener('mouseup', selectionListener);
@@ -1316,6 +1325,7 @@ class AutocaptureTracker {
1316
1325
  }
1317
1326
  getElementProperties(element, eventType) {
1318
1327
  const properties = {
1328
+ $event_type: eventType,
1319
1329
  $element_tag: element.tagName.toLowerCase(),
1320
1330
  $element_type: this.getElementType(element),
1321
1331
  };
@@ -1325,6 +1335,7 @@ class AutocaptureTracker {
1325
1335
  }
1326
1336
  if (element.className) {
1327
1337
  properties.$element_classes = Array.from(element.classList);
1338
+ properties.$element_semantic_classes = this.extractSemanticClasses(element.classList);
1328
1339
  }
1329
1340
  // Element attributes
1330
1341
  const relevantAttributes = ['name', 'role', 'aria-label', 'data-testid', 'data-track'];
@@ -1334,11 +1345,39 @@ class AutocaptureTracker {
1334
1345
  properties[`$element_${attr.replace('-', '_')}`] = value;
1335
1346
  }
1336
1347
  });
1348
+ // Configurable data-* attribute capture
1349
+ const prefixes = this.options.dataAttributePrefixes || ['jrnm-'];
1350
+ const exactNames = new Set(this.options.dataAttributeNames || ['data-testid', 'data-track']);
1351
+ const relevantSet = new Set(relevantAttributes);
1352
+ let dataAttrCount = 0;
1353
+ for (let i = 0; i < element.attributes.length && dataAttrCount < 10; i++) {
1354
+ const attr = element.attributes.item(i);
1355
+ if (!attr || !attr.name.startsWith('data-'))
1356
+ continue;
1357
+ if (relevantSet.has(attr.name))
1358
+ continue;
1359
+ const suffix = attr.name.slice(5); // strip 'data-'
1360
+ const matchesPrefix = prefixes.some(p => suffix.startsWith(p));
1361
+ const matchesName = exactNames.has(attr.name);
1362
+ if (matchesPrefix || matchesName) {
1363
+ const propName = `$attr_${attr.name.replace(/-/g, '_')}`;
1364
+ properties[propName] = attr.value;
1365
+ dataAttrCount++;
1366
+ }
1367
+ }
1368
+ // Link href as first-class property
1369
+ if (element.tagName.toLowerCase() === 'a') {
1370
+ const href = element.getAttribute('href');
1371
+ if (href) {
1372
+ properties.$element_href = href;
1373
+ }
1374
+ }
1337
1375
  // Element content
1338
1376
  if (this.options.captureContentText) {
1339
- const text = this.getElementText(element);
1340
- if (text) {
1341
- properties.$element_text = text.substring(0, 200); // Limit text length
1377
+ const result = this.getElementText(element);
1378
+ if (result && result.source) {
1379
+ properties.$element_text = result.text.substring(0, 200); // Limit text length
1380
+ properties.$element_text_source = result.source;
1342
1381
  }
1343
1382
  }
1344
1383
  // Elements chain data
@@ -1348,6 +1387,11 @@ class AutocaptureTracker {
1348
1387
  properties.$elements_chain_elements = elementsChain.elements;
1349
1388
  properties.$elements_chain_texts = elementsChain.texts;
1350
1389
  properties.$elements_chain_ids = elementsChain.ids;
1390
+ // Element state
1391
+ const elementState = this.getElementState(element);
1392
+ if (elementState) {
1393
+ properties.$element_state = elementState;
1394
+ }
1351
1395
  // Position information
1352
1396
  const rect = element.getBoundingClientRect();
1353
1397
  properties.$element_position = {
@@ -1363,10 +1407,13 @@ class AutocaptureTracker {
1363
1407
  properties.$parent_id = element.parentElement.id;
1364
1408
  }
1365
1409
  }
1366
- // URL information
1410
+ // URL and page context
1367
1411
  properties.$current_url = window.location.href;
1368
1412
  properties.$host = window.location.host;
1369
1413
  properties.$pathname = window.location.pathname;
1414
+ properties.$search = window.location.search;
1415
+ properties.$page_title = document.title;
1416
+ properties.$referrer = document.referrer;
1370
1417
  return properties;
1371
1418
  }
1372
1419
  getFormProperties(form, eventType) {
@@ -1429,19 +1476,50 @@ class AutocaptureTracker {
1429
1476
  return tag;
1430
1477
  }
1431
1478
  getElementText(element) {
1432
- var _a, _b;
1433
- // For buttons and links, get the visible text
1434
- if (['button', 'a'].includes(element.tagName.toLowerCase())) {
1435
- return ((_a = element.textContent) === null || _a === void 0 ? void 0 : _a.trim()) || '';
1436
- }
1479
+ var _a, _b, _c, _d, _e;
1480
+ const tag = element.tagName.toLowerCase();
1437
1481
  // For inputs, get placeholder or label
1438
- if (element.tagName.toLowerCase() === 'input') {
1482
+ if (tag === 'input') {
1439
1483
  const input = element;
1440
- return input.placeholder || input.value || '';
1484
+ const text = input.placeholder || input.value || '';
1485
+ return text ? { text, source: 'content' } : null;
1486
+ }
1487
+ // For buttons and links, use fallback chain
1488
+ if (['button', 'a'].includes(tag)) {
1489
+ // 1. Visible text content (excluding SVG title/desc which aren't rendered)
1490
+ const visibleText = this.getVisibleTextContent(element);
1491
+ if (visibleText) {
1492
+ return { text: visibleText, source: 'content' };
1493
+ }
1494
+ // 2. aria-label
1495
+ const ariaLabel = (_a = element.getAttribute('aria-label')) === null || _a === void 0 ? void 0 : _a.trim();
1496
+ if (ariaLabel) {
1497
+ return { text: ariaLabel, source: 'aria-label' };
1498
+ }
1499
+ // 3. title
1500
+ const title = (_b = element.getAttribute('title')) === null || _b === void 0 ? void 0 : _b.trim();
1501
+ if (title) {
1502
+ return { text: title, source: 'title' };
1503
+ }
1504
+ // 4. First <img> child's alt
1505
+ const img = element.querySelector('img');
1506
+ if ((_c = img === null || img === void 0 ? void 0 : img.alt) === null || _c === void 0 ? void 0 : _c.trim()) {
1507
+ return { text: img.alt.trim(), source: 'alt' };
1508
+ }
1509
+ // 5. First <svg> child's <title> element
1510
+ const svg = element.querySelector('svg');
1511
+ const svgTitle = svg === null || svg === void 0 ? void 0 : svg.querySelector('title');
1512
+ if ((_d = svgTitle === null || svgTitle === void 0 ? void 0 : svgTitle.textContent) === null || _d === void 0 ? void 0 : _d.trim()) {
1513
+ return { text: svgTitle.textContent.trim(), source: 'svg-title' };
1514
+ }
1515
+ return null;
1441
1516
  }
1442
1517
  // For other elements, get text content but limit it
1443
- const text = ((_b = element.textContent) === null || _b === void 0 ? void 0 : _b.trim()) || '';
1444
- return text.length > 50 ? text.substring(0, 47) + '...' : text;
1518
+ const text = ((_e = element.textContent) === null || _e === void 0 ? void 0 : _e.trim()) || '';
1519
+ if (!text)
1520
+ return null;
1521
+ const truncated = text.length > 50 ? text.substring(0, 47) + '...' : text;
1522
+ return { text: truncated, source: 'content' };
1445
1523
  }
1446
1524
  getElementsChain(element) {
1447
1525
  var _a;
@@ -1515,6 +1593,92 @@ class AutocaptureTracker {
1515
1593
  ids: ids.reverse()
1516
1594
  };
1517
1595
  }
1596
+ extractSemanticClasses(classList) {
1597
+ const results = new Set();
1598
+ for (let i = 0; i < classList.length; i++) {
1599
+ const cls = classList.item(i);
1600
+ if (!cls)
1601
+ continue;
1602
+ const parts = cls.split('__');
1603
+ if (parts.length >= 3) {
1604
+ // CSS module pattern: Module__hash__name → take last segment
1605
+ const last = parts[parts.length - 1];
1606
+ if (last)
1607
+ results.add(last);
1608
+ }
1609
+ else if (parts.length === 2) {
1610
+ // 2-part __ class (e.g., Module__hash) → drop, no semantic name
1611
+ continue;
1612
+ }
1613
+ else {
1614
+ // Single-part class — keep unless it looks like a hash
1615
+ if (!this.isHashLike(cls)) {
1616
+ results.add(cls);
1617
+ }
1618
+ }
1619
+ }
1620
+ return Array.from(results);
1621
+ }
1622
+ isHashLike(value) {
1623
+ // Hash-like: alphanumeric, 5-10 chars, contains both letters and digits
1624
+ return /^[a-zA-Z0-9]{5,10}$/.test(value)
1625
+ && /[a-zA-Z]/.test(value)
1626
+ && /[0-9]/.test(value);
1627
+ }
1628
+ getVisibleTextContent(element) {
1629
+ let text = '';
1630
+ for (let i = 0; i < element.childNodes.length; i++) {
1631
+ const child = element.childNodes.item(i);
1632
+ if (!child)
1633
+ continue;
1634
+ if (child.nodeType === Node.TEXT_NODE) {
1635
+ text += child.textContent || '';
1636
+ }
1637
+ else if (child.nodeType === Node.ELEMENT_NODE) {
1638
+ const el = child;
1639
+ if (el.tagName.toLowerCase() !== 'svg') {
1640
+ text += this.getVisibleTextContent(el);
1641
+ }
1642
+ }
1643
+ }
1644
+ return text.trim();
1645
+ }
1646
+ getElementState(element) {
1647
+ const state = {};
1648
+ // DOM properties
1649
+ if (element.disabled === true) {
1650
+ state.disabled = true;
1651
+ }
1652
+ else if (element.getAttribute('aria-disabled') === 'true') {
1653
+ state.disabled = true;
1654
+ }
1655
+ if (element.checked === true) {
1656
+ state.checked = true;
1657
+ }
1658
+ else if (element.getAttribute('aria-checked') === 'true') {
1659
+ state.checked = true;
1660
+ }
1661
+ if (element.getAttribute('aria-selected') === 'true') {
1662
+ state.selected = true;
1663
+ }
1664
+ if (element.getAttribute('aria-expanded') === 'true') {
1665
+ state.expanded = true;
1666
+ }
1667
+ return Object.keys(state).length > 0 ? state : null;
1668
+ }
1669
+ findInteractiveAncestor(element) {
1670
+ const interactiveTags = ['button', 'a', 'input', 'select', 'textarea'];
1671
+ let current = element;
1672
+ while (current && current !== document.body) {
1673
+ if (interactiveTags.includes(current.tagName.toLowerCase()) ||
1674
+ current.getAttribute('role') === 'button' ||
1675
+ current.getAttribute('role') === 'link') {
1676
+ return current;
1677
+ }
1678
+ current = current.parentElement;
1679
+ }
1680
+ return null;
1681
+ }
1518
1682
  isSafeInputType(type) {
1519
1683
  // Don't capture values for sensitive input types
1520
1684
  const sensitiveTypes = ['password', 'email', 'tel', 'credit-card-number'];
@@ -1701,6 +1865,14 @@ class JourniumAnalytics {
1701
1865
  }
1702
1866
  /** Create and return a new JourniumAnalytics instance for the given config. */
1703
1867
  const init = (config) => {
1868
+ var _a;
1869
+ // Set SDK version if not already set by a framework SDK (React, Next.js, Angular)
1870
+ if (!((_a = config.options) === null || _a === void 0 ? void 0 : _a._sdkVersion)) {
1871
+ config = {
1872
+ ...config,
1873
+ options: { ...config.options, _sdkVersion: SDK_VERSION },
1874
+ };
1875
+ }
1704
1876
  return new JourniumAnalytics(config);
1705
1877
  };
1706
1878