@journium/js 1.2.2 → 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.
@@ -27,6 +27,8 @@ export declare class AutocaptureTracker {
27
27
  private getElementType;
28
28
  private getElementText;
29
29
  private getElementsChain;
30
+ private extractSemanticClasses;
31
+ private isHashLike;
30
32
  private isSafeInputType;
31
33
  }
32
34
  //# 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;IAgBxB,OAAO,CAAC,qBAAqB;IAgB7B,OAAO,CAAC,qBAAqB;IAgB7B,OAAO,CAAC,wBAAwB;IAuBhC,OAAO,CAAC,mBAAmB;IA2B3B,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,oBAAoB;IAoG5B,OAAO,CAAC,iBAAiB;IAsBzB,OAAO,CAAC,kBAAkB;IAuC1B,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,cAAc;IAiBtB,OAAO,CAAC,gBAAgB;IAqFxB,OAAO,CAAC,sBAAsB;IA0B9B,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,eAAe;CAKxB"}
@@ -7,12 +7,23 @@ export declare class JourniumAnalytics {
7
7
  private autocaptureStarted;
8
8
  private unsubscribeOptionsChange?;
9
9
  constructor(config: JourniumConfig);
10
+ private resolvePageviewOptions;
10
11
  private resolveAutocaptureOptions;
12
+ /** Track a custom event with optional properties. */
11
13
  track(event: string, properties?: Record<string, unknown>): void;
14
+ /** Associate the current session with a known user identity and optional attributes. */
12
15
  identify(distinctId: string, attributes?: Record<string, unknown>): void;
16
+ /** Clear the current identity, starting a new anonymous session. */
13
17
  reset(): void;
18
+ /** Manually capture a $pageview event with optional custom properties. */
14
19
  capturePageview(properties?: Record<string, unknown>): void;
20
+ /**
21
+ * Manually start autocapture (pageview tracking + DOM event capture).
22
+ * Under normal usage this is not needed — the SDK starts automatically on init.
23
+ * Useful only if autocapture was explicitly stopped and needs to be restarted.
24
+ */
15
25
  startAutocapture(): void;
26
+ /** Stop autocapture — pauses pageview tracking and DOM event capture. */
16
27
  stopAutocapture(): void;
17
28
  /**
18
29
  * Automatically start autocapture if enabled in options
@@ -23,14 +34,18 @@ export declare class JourniumAnalytics {
23
34
  * Handle effective options change (e.g., when remote options are fetched)
24
35
  */
25
36
  private handleOptionsChange;
37
+ /** Flush all queued events to the ingestion endpoint immediately. */
26
38
  flush(): Promise<void>;
39
+ /** Return the currently active options (merged local + remote config). */
27
40
  getEffectiveOptions(): JourniumLocalOptions;
28
41
  /**
29
42
  * Register a callback to be notified when effective options change
30
43
  */
31
44
  onOptionsChange(callback: (options: JourniumLocalOptions) => void): () => void;
45
+ /** Tear down the analytics instance: stop all tracking, flush pending events, and release resources. */
32
46
  destroy(): void;
33
47
  }
48
+ /** Create and return a new JourniumAnalytics instance for the given config. */
34
49
  export declare const init: (config: JourniumConfig) => JourniumAnalytics;
35
50
  declare const _default: {
36
51
  init: (config: JourniumConfig) => JourniumAnalytics;
@@ -1 +1 @@
1
- {"version":3,"file":"JourniumAnalytics.d.ts","sourceRoot":"","sources":["../src/JourniumAnalytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAsB,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAK1F,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,yBAAyB;IAiBjC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIhE,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIxE,KAAK,IAAI,IAAI;IAIb,eAAe,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI3D,gBAAgB,IAAI,IAAI;IA4BxB,eAAe,IAAI,IAAI;IAMvB;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAkCjC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA+BrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,mBAAmB;IAInB;;OAEG;IACH,eAAe,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,GAAG,MAAM,IAAI;IAI9E,OAAO,IAAI,IAAI;CAQhB;AAED,eAAO,MAAM,IAAI,WAAY,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,13 +7,15 @@ 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).
13
14
  * Pass false when restarting after a remote options update to avoid a spurious pageview.
15
+ * @param patchHistory - whether to monkey-patch pushState/replaceState/popstate (default: true).
16
+ * Pass false when a framework-native router tracker (e.g. Next.js) owns SPA pageviews.
14
17
  */
15
- startAutoPageviewTracking(captureInitialPageview?: boolean): void;
18
+ startAutoPageviewTracking(captureInitialPageview?: boolean, patchHistory?: boolean): void;
16
19
  /**
17
20
  * Stop automatic autocapture for pageviews
18
21
  * @returns void
@@ -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;;;;OAIG;IACH,yBAAyB,CAAC,sBAAsB,GAAE,OAAc,GAAG,IAAI;IA4BvE;;;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;IAkBhE;;;;;;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.0 is replaced at build time by @rollup/plugin-replace
4
+ const SDK_VERSION = '@journium/js@1.3.0';
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,7 +1095,7 @@ 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(),
1096
1100
  ...customProperties,
1097
1101
  };
@@ -1102,28 +1106,31 @@ class PageviewTracker {
1102
1106
  * Start automatic autocapture for pageviews
1103
1107
  * @param captureInitialPageview - whether to fire a $pageview immediately on start (default: true).
1104
1108
  * Pass false when restarting after a remote options update to avoid a spurious pageview.
1109
+ * @param patchHistory - whether to monkey-patch pushState/replaceState/popstate (default: true).
1110
+ * Pass false when a framework-native router tracker (e.g. Next.js) owns SPA pageviews.
1105
1111
  */
1106
- startAutoPageviewTracking(captureInitialPageview = true) {
1112
+ startAutoPageviewTracking(captureInitialPageview = true, patchHistory = true) {
1107
1113
  if (captureInitialPageview) {
1108
1114
  this.capturePageview();
1109
1115
  }
1110
- if (typeof window !== 'undefined') {
1111
- // Store original methods for cleanup
1112
- this.originalPushState = window.history.pushState;
1113
- this.originalReplaceState = window.history.replaceState;
1114
- window.history.pushState = (...args) => {
1115
- this.originalPushState.apply(window.history, args);
1116
- setTimeout(() => this.capturePageview(), 0);
1117
- };
1118
- window.history.replaceState = (...args) => {
1119
- this.originalReplaceState.apply(window.history, args);
1120
- setTimeout(() => this.capturePageview(), 0);
1121
- };
1122
- this.popStateHandler = () => {
1123
- setTimeout(() => this.capturePageview(), 0);
1124
- };
1125
- window.addEventListener('popstate', this.popStateHandler);
1116
+ if (!patchHistory || typeof window === 'undefined') {
1117
+ return;
1126
1118
  }
1119
+ // Store original methods for cleanup
1120
+ this.originalPushState = window.history.pushState;
1121
+ this.originalReplaceState = window.history.replaceState;
1122
+ window.history.pushState = (...args) => {
1123
+ this.originalPushState.apply(window.history, args);
1124
+ setTimeout(() => this.capturePageview(), 0);
1125
+ };
1126
+ window.history.replaceState = (...args) => {
1127
+ this.originalReplaceState.apply(window.history, args);
1128
+ setTimeout(() => this.capturePageview(), 0);
1129
+ };
1130
+ this.popStateHandler = () => {
1131
+ setTimeout(() => this.capturePageview(), 0);
1132
+ };
1133
+ window.addEventListener('popstate', this.popStateHandler);
1127
1134
  }
1128
1135
  /**
1129
1136
  * Stop automatic autocapture for pageviews
@@ -1164,6 +1171,8 @@ class AutocaptureTracker {
1164
1171
  ignoreClasses: ['journium-ignore'],
1165
1172
  ignoreElements: ['script', 'style', 'noscript'],
1166
1173
  captureContentText: true,
1174
+ dataAttributePrefixes: ['jrnm-'],
1175
+ dataAttributeNames: ['data-testid', 'data-track'],
1167
1176
  ...options,
1168
1177
  };
1169
1178
  }
@@ -1185,6 +1194,8 @@ class AutocaptureTracker {
1185
1194
  ignoreClasses: ['journium-ignore'],
1186
1195
  ignoreElements: ['script', 'style', 'noscript'],
1187
1196
  captureContentText: true,
1197
+ dataAttributePrefixes: ['jrnm-'],
1198
+ dataAttributeNames: ['data-testid', 'data-track'],
1188
1199
  ...options,
1189
1200
  };
1190
1201
  // Restart if it was active before
@@ -1227,10 +1238,7 @@ class AutocaptureTracker {
1227
1238
  return;
1228
1239
  }
1229
1240
  const properties = this.getElementProperties(target, 'click');
1230
- this.client.track('$autocapture', {
1231
- $event_type: 'click',
1232
- ...properties,
1233
- });
1241
+ this.client.track('$autocapture', properties);
1234
1242
  };
1235
1243
  document.addEventListener('click', clickListener, true);
1236
1244
  this.listeners.set('click', clickListener);
@@ -1242,10 +1250,7 @@ class AutocaptureTracker {
1242
1250
  return;
1243
1251
  }
1244
1252
  const properties = this.getFormProperties(target, 'submit');
1245
- this.client.track('$autocapture', {
1246
- $event_type: 'submit',
1247
- ...properties,
1248
- });
1253
+ this.client.track('$autocapture', properties);
1249
1254
  };
1250
1255
  document.addEventListener('submit', submitListener, true);
1251
1256
  this.listeners.set('submit', submitListener);
@@ -1257,10 +1262,7 @@ class AutocaptureTracker {
1257
1262
  return;
1258
1263
  }
1259
1264
  const properties = this.getInputProperties(target, 'change');
1260
- this.client.track('$autocapture', {
1261
- $event_type: 'change',
1262
- ...properties,
1263
- });
1265
+ this.client.track('$autocapture', properties);
1264
1266
  };
1265
1267
  document.addEventListener('change', changeListener, true);
1266
1268
  this.listeners.set('change', changeListener);
@@ -1313,6 +1315,7 @@ class AutocaptureTracker {
1313
1315
  }
1314
1316
  getElementProperties(element, eventType) {
1315
1317
  const properties = {
1318
+ $event_type: eventType,
1316
1319
  $element_tag: element.tagName.toLowerCase(),
1317
1320
  $element_type: this.getElementType(element),
1318
1321
  };
@@ -1322,6 +1325,7 @@ class AutocaptureTracker {
1322
1325
  }
1323
1326
  if (element.className) {
1324
1327
  properties.$element_classes = Array.from(element.classList);
1328
+ properties.$element_semantic_classes = this.extractSemanticClasses(element.classList);
1325
1329
  }
1326
1330
  // Element attributes
1327
1331
  const relevantAttributes = ['name', 'role', 'aria-label', 'data-testid', 'data-track'];
@@ -1331,6 +1335,33 @@ class AutocaptureTracker {
1331
1335
  properties[`$element_${attr.replace('-', '_')}`] = value;
1332
1336
  }
1333
1337
  });
1338
+ // Configurable data-* attribute capture
1339
+ const prefixes = this.options.dataAttributePrefixes || ['jrnm-'];
1340
+ const exactNames = new Set(this.options.dataAttributeNames || ['data-testid', 'data-track']);
1341
+ const relevantSet = new Set(relevantAttributes);
1342
+ let dataAttrCount = 0;
1343
+ for (let i = 0; i < element.attributes.length && dataAttrCount < 10; i++) {
1344
+ const attr = element.attributes.item(i);
1345
+ if (!attr || !attr.name.startsWith('data-'))
1346
+ continue;
1347
+ if (relevantSet.has(attr.name))
1348
+ continue;
1349
+ const suffix = attr.name.slice(5); // strip 'data-'
1350
+ const matchesPrefix = prefixes.some(p => suffix.startsWith(p));
1351
+ const matchesName = exactNames.has(attr.name);
1352
+ if (matchesPrefix || matchesName) {
1353
+ const propName = `$attr_${attr.name.replace(/-/g, '_')}`;
1354
+ properties[propName] = attr.value;
1355
+ dataAttrCount++;
1356
+ }
1357
+ }
1358
+ // Link href as first-class property
1359
+ if (element.tagName.toLowerCase() === 'a') {
1360
+ const href = element.getAttribute('href');
1361
+ if (href) {
1362
+ properties.$element_href = href;
1363
+ }
1364
+ }
1334
1365
  // Element content
1335
1366
  if (this.options.captureContentText) {
1336
1367
  const text = this.getElementText(element);
@@ -1360,10 +1391,13 @@ class AutocaptureTracker {
1360
1391
  properties.$parent_id = element.parentElement.id;
1361
1392
  }
1362
1393
  }
1363
- // URL information
1394
+ // URL and page context
1364
1395
  properties.$current_url = window.location.href;
1365
1396
  properties.$host = window.location.host;
1366
1397
  properties.$pathname = window.location.pathname;
1398
+ properties.$search = window.location.search;
1399
+ properties.$page_title = document.title;
1400
+ properties.$referrer = document.referrer;
1367
1401
  return properties;
1368
1402
  }
1369
1403
  getFormProperties(form, eventType) {
@@ -1512,6 +1546,38 @@ class AutocaptureTracker {
1512
1546
  ids: ids.reverse()
1513
1547
  };
1514
1548
  }
1549
+ extractSemanticClasses(classList) {
1550
+ const results = new Set();
1551
+ for (let i = 0; i < classList.length; i++) {
1552
+ const cls = classList.item(i);
1553
+ if (!cls)
1554
+ continue;
1555
+ const parts = cls.split('__');
1556
+ if (parts.length >= 3) {
1557
+ // CSS module pattern: Module__hash__name → take last segment
1558
+ const last = parts[parts.length - 1];
1559
+ if (last)
1560
+ results.add(last);
1561
+ }
1562
+ else if (parts.length === 2) {
1563
+ // 2-part __ class (e.g., Module__hash) → drop, no semantic name
1564
+ continue;
1565
+ }
1566
+ else {
1567
+ // Single-part class — keep unless it looks like a hash
1568
+ if (!this.isHashLike(cls)) {
1569
+ results.add(cls);
1570
+ }
1571
+ }
1572
+ }
1573
+ return Array.from(results);
1574
+ }
1575
+ isHashLike(value) {
1576
+ // Hash-like: alphanumeric, 5-10 chars, contains both letters and digits
1577
+ return /^[a-zA-Z0-9]{5,10}$/.test(value)
1578
+ && /[a-zA-Z]/.test(value)
1579
+ && /[0-9]/.test(value);
1580
+ }
1515
1581
  isSafeInputType(type) {
1516
1582
  // Don't capture values for sensitive input types
1517
1583
  const sensitiveTypes = ['password', 'email', 'tel', 'credit-card-number'];
@@ -1538,6 +1604,20 @@ class JourniumAnalytics {
1538
1604
  // This handles cached remote options or local options with autocapture enabled
1539
1605
  this.startAutocaptureIfEnabled(initialEffectiveOptions);
1540
1606
  }
1607
+ resolvePageviewOptions(autoTrackPageviews, frameworkHandlesPageviews) {
1608
+ if (autoTrackPageviews === false || frameworkHandlesPageviews) {
1609
+ return { enabled: false, trackSpaPageviews: false, captureInitialPageview: false };
1610
+ }
1611
+ if (autoTrackPageviews === true || autoTrackPageviews === undefined) {
1612
+ return { enabled: true, trackSpaPageviews: true, captureInitialPageview: true };
1613
+ }
1614
+ // object form implies enabled
1615
+ return {
1616
+ enabled: true,
1617
+ trackSpaPageviews: autoTrackPageviews.trackSpaPageviews !== false,
1618
+ captureInitialPageview: autoTrackPageviews.trackInitialPageview !== false,
1619
+ };
1620
+ }
1541
1621
  resolveAutocaptureOptions(autocapture) {
1542
1622
  if (autocapture === false) {
1543
1623
  return {
@@ -1552,39 +1632,50 @@ class JourniumAnalytics {
1552
1632
  }
1553
1633
  return autocapture;
1554
1634
  }
1635
+ /** Track a custom event with optional properties. */
1555
1636
  track(event, properties) {
1556
1637
  this.client.track(event, properties);
1557
1638
  }
1639
+ /** Associate the current session with a known user identity and optional attributes. */
1558
1640
  identify(distinctId, attributes) {
1559
1641
  this.client.identify(distinctId, attributes);
1560
1642
  }
1643
+ /** Clear the current identity, starting a new anonymous session. */
1561
1644
  reset() {
1562
1645
  this.client.reset();
1563
1646
  }
1647
+ /** Manually capture a $pageview event with optional custom properties. */
1564
1648
  capturePageview(properties) {
1565
1649
  this.pageviewTracker.capturePageview(properties);
1566
1650
  }
1651
+ /**
1652
+ * Manually start autocapture (pageview tracking + DOM event capture).
1653
+ * Under normal usage this is not needed — the SDK starts automatically on init.
1654
+ * Useful only if autocapture was explicitly stopped and needs to be restarted.
1655
+ */
1567
1656
  startAutocapture() {
1568
1657
  // Always check effective options (which may include remote options)
1569
1658
  const effectiveOptions = this.client.getEffectiveOptions();
1570
- // Only enable if effectiveOptions are loaded and autoTrackPageviews is not explicitly false
1571
- const autoTrackPageviews = effectiveOptions && Object.keys(effectiveOptions).length > 0
1572
- ? effectiveOptions.autoTrackPageviews !== false
1573
- : false;
1574
- const autocaptureEnabled = effectiveOptions && Object.keys(effectiveOptions).length > 0
1659
+ // Only start if effectiveOptions are actually loaded (non-empty)
1660
+ const hasOptions = effectiveOptions && Object.keys(effectiveOptions).length > 0;
1661
+ const { enabled: autoTrackPageviews, trackSpaPageviews, captureInitialPageview } = hasOptions
1662
+ ? this.resolvePageviewOptions(effectiveOptions.autoTrackPageviews, effectiveOptions._frameworkHandlesPageviews)
1663
+ : { enabled: false, trackSpaPageviews: false, captureInitialPageview: false };
1664
+ const autocaptureEnabled = hasOptions
1575
1665
  ? effectiveOptions.autocapture !== false
1576
1666
  : false;
1577
1667
  // Update autocapture tracker options if they've changed
1578
1668
  const autocaptureOptions = this.resolveAutocaptureOptions(effectiveOptions.autocapture);
1579
1669
  this.autocaptureTracker.updateOptions(autocaptureOptions);
1580
1670
  if (autoTrackPageviews) {
1581
- this.pageviewTracker.startAutoPageviewTracking();
1671
+ this.pageviewTracker.startAutoPageviewTracking(captureInitialPageview, trackSpaPageviews);
1582
1672
  }
1583
1673
  if (autocaptureEnabled) {
1584
1674
  this.autocaptureTracker.start();
1585
1675
  }
1586
1676
  this.autocaptureStarted = true;
1587
1677
  }
1678
+ /** Stop autocapture — pauses pageview tracking and DOM event capture. */
1588
1679
  stopAutocapture() {
1589
1680
  this.pageviewTracker.stopAutocapture();
1590
1681
  this.autocaptureTracker.stop();
@@ -1604,13 +1695,13 @@ class JourniumAnalytics {
1604
1695
  const hasActualOptions = effectiveOptions && Object.keys(effectiveOptions).length > 0;
1605
1696
  if (hasActualOptions) {
1606
1697
  // Use same logic as manual startAutocapture() but only start automatically
1607
- const autoTrackPageviews = effectiveOptions.autoTrackPageviews !== false;
1698
+ const { enabled: autoTrackPageviews, trackSpaPageviews, captureInitialPageview } = this.resolvePageviewOptions(effectiveOptions.autoTrackPageviews, effectiveOptions._frameworkHandlesPageviews);
1608
1699
  const autocaptureEnabled = effectiveOptions.autocapture !== false;
1609
1700
  // Update autocapture tracker options
1610
1701
  const autocaptureOptions = this.resolveAutocaptureOptions(effectiveOptions.autocapture);
1611
1702
  this.autocaptureTracker.updateOptions(autocaptureOptions);
1612
1703
  if (autoTrackPageviews) {
1613
- this.pageviewTracker.startAutoPageviewTracking();
1704
+ this.pageviewTracker.startAutoPageviewTracking(captureInitialPageview, trackSpaPageviews);
1614
1705
  }
1615
1706
  if (autocaptureEnabled) {
1616
1707
  this.autocaptureTracker.start();
@@ -1635,21 +1726,23 @@ class JourniumAnalytics {
1635
1726
  this.autocaptureTracker.stop();
1636
1727
  this.autocaptureStarted = false;
1637
1728
  }
1638
- const autoTrackPageviews = effectiveOptions.autoTrackPageviews !== false;
1729
+ const { enabled: autoTrackPageviews, trackSpaPageviews, captureInitialPageview } = this.resolvePageviewOptions(effectiveOptions.autoTrackPageviews, effectiveOptions._frameworkHandlesPageviews);
1639
1730
  const autocaptureEnabled = effectiveOptions.autocapture !== false;
1640
1731
  const autocaptureOptions = this.resolveAutocaptureOptions(effectiveOptions.autocapture);
1641
1732
  this.autocaptureTracker.updateOptions(autocaptureOptions);
1642
1733
  if (autoTrackPageviews) {
1643
- this.pageviewTracker.startAutoPageviewTracking(isFirstStart);
1734
+ this.pageviewTracker.startAutoPageviewTracking(isFirstStart && captureInitialPageview, trackSpaPageviews);
1644
1735
  }
1645
1736
  if (autocaptureEnabled) {
1646
1737
  this.autocaptureTracker.start();
1647
1738
  }
1648
1739
  this.autocaptureStarted = autoTrackPageviews || autocaptureEnabled;
1649
1740
  }
1741
+ /** Flush all queued events to the ingestion endpoint immediately. */
1650
1742
  async flush() {
1651
1743
  return this.client.flush();
1652
1744
  }
1745
+ /** Return the currently active options (merged local + remote config). */
1653
1746
  getEffectiveOptions() {
1654
1747
  return this.client.getEffectiveOptions();
1655
1748
  }
@@ -1659,6 +1752,7 @@ class JourniumAnalytics {
1659
1752
  onOptionsChange(callback) {
1660
1753
  return this.client.onOptionsChange(callback);
1661
1754
  }
1755
+ /** Tear down the analytics instance: stop all tracking, flush pending events, and release resources. */
1662
1756
  destroy() {
1663
1757
  this.pageviewTracker.stopAutocapture();
1664
1758
  this.autocaptureTracker.stop();
@@ -1668,7 +1762,16 @@ class JourniumAnalytics {
1668
1762
  this.client.destroy();
1669
1763
  }
1670
1764
  }
1765
+ /** Create and return a new JourniumAnalytics instance for the given config. */
1671
1766
  const init = (config) => {
1767
+ var _a;
1768
+ // Set SDK version if not already set by a framework SDK (React, Next.js, Angular)
1769
+ if (!((_a = config.options) === null || _a === void 0 ? void 0 : _a._sdkVersion)) {
1770
+ config = {
1771
+ ...config,
1772
+ options: { ...config.options, _sdkVersion: SDK_VERSION },
1773
+ };
1774
+ }
1672
1775
  return new JourniumAnalytics(config);
1673
1776
  };
1674
1777