@coralogix/browser 3.16.0 → 3.18.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/CHANGELOG.md CHANGED
@@ -1,3 +1,34 @@
1
+ ## 3.18.0 (2026-07-08)
2
+
3
+ ### 🚀 Features
4
+
5
+ - Add product analytics support for richer product-level insights
6
+
7
+ ## 3.17.1 (2026-07-07)
8
+
9
+ ### 🩹 Fixes
10
+
11
+ - Persist snapshot context across page reloads when `keepSessionAfterReload` is enabled, so session-level counters (views, errors, actions) no longer reset on refresh
12
+
13
+ ## 3.17.0 (2026-07-06)
14
+
15
+ ### 🚀 Features
16
+
17
+ - add configurable OpenTelemetry batch/flush via otelConfig
18
+
19
+ ## 3.16.2 (2026-07-06)
20
+
21
+ ### 🩹 Fixes
22
+
23
+ - Fix PII masking for password input field changes
24
+ - The default `maskInputTypes` is narrowed from `['password', 'email', 'tel']` to `['password']`, to match session-recording default. `email` and `tel` inputs are no longer masked by default in user-interaction events — set `maskInputTypes: ['password', 'email', 'tel']` to restore the previous behavior.
25
+
26
+ ## 3.16.1 (2026-06-29)
27
+
28
+ ### 🩹 Fixes
29
+
30
+ - Improve user-interaction accuracy: capture SVG icon clicks and resolve role-based/custom controls.
31
+
1
32
  ## 3.16.0 (2026-06-24)
2
33
 
3
34
  ### 🚀 Features
package/README.md CHANGED
@@ -58,15 +58,16 @@
58
58
 
59
59
  - [Ignored Instruments](#ignored-instruments)
60
60
 
61
- 30. [Soft Navigations (Experimental)](#soft-navigations--experimental)
62
- 31. [Memory Usage (Experimental)](#memory-usage---experimental)
63
- 32. [Web Worker Support](#web-worker-support)
61
+ 30. [OpenTelemetry Batch Configuration](#opentelemetry-batch-configuration)
62
+ 31. [Soft Navigations (Experimental)](#soft-navigations--experimental)
63
+ 32. [Memory Usage (Experimental)](#memory-usage---experimental)
64
+ 33. [Web Worker Support](#web-worker-support)
64
65
 
65
66
  - [Enabling Web Worker Support](#enabling-web-worker-support)
66
67
  - [Examples](#examples)
67
68
 
68
- 33. [Angular Zone.js Configuration](#angular-zonejs-configuration)
69
- 34. [CDN](#cdn)
69
+ 34. [Angular Zone.js Configuration](#angular-zonejs-configuration)
70
+ 35. [CDN](#cdn)
70
71
 
71
72
  - [Specific Version](#specific-version-recommended)
72
73
  - [ES5](#es5)
@@ -75,7 +76,7 @@
75
76
  - [Via JS File](#via-js-file)
76
77
  - [Via TS File](#via-ts-file)
77
78
 
78
- 35. [Flutter Web](#flutter-web)
79
+ 36. [Flutter Web](#flutter-web)
79
80
 
80
81
  ---
81
82
 
@@ -545,7 +546,7 @@ CoralogixRum.init({
545
546
 
546
547
  User interactions capture text from clickable elements only (button, label, link, input, option).
547
548
  Elements text can be masked to prevent sensitive data exposure.
548
- <br>use `maskInputTypes` to specify the types of inputs to mask. defaults to: `['password', 'email', 'tel']`
549
+ <br>use `maskInputTypes` to specify the types of inputs to mask. defaults to: `['password']`
549
550
  <br>use `maskClass` to specify the class name that will be used to mask any clickable element. Default masking class is `cx-mask`.
550
551
 
551
552
  ```javascript
@@ -1006,6 +1007,23 @@ CoralogixRum.init({
1006
1007
  });
1007
1008
  ```
1008
1009
 
1010
+ ### OpenTelemetry Batch Configuration
1011
+
1012
+ The SDK batches logs and traces through an OpenTelemetry `BatchSpanProcessor` before sending them to Coralogix. Use `otelConfig` to tune that batching — for example, to flush less frequently and reduce the number of network requests your app makes.
1013
+
1014
+ All fields are optional. Omitting `otelConfig` keeps the SDK defaults, and any out-of-range value is clamped to the documented bounds.
1015
+
1016
+ ```javascript
1017
+ CoralogixRum.init({
1018
+ // ...
1019
+ otelConfig: {
1020
+ maxExportBatchSize: 50, // Max spans per export; reaching it triggers an early flush. Defaults to 50, min 1, max 256
1021
+ scheduledDelayMillis: 2000, // Delay in ms between two consecutive exports. Defaults to 2000(2s), min 2000(2s), max 30000(30s)
1022
+ maxQueueSize: 2048, // Max buffered spans before new spans are dropped. Defaults to 2048, min 512, max 4096
1023
+ },
1024
+ });
1025
+ ```
1026
+
1009
1027
  ### Soft Navigations — Experimental
1010
1028
 
1011
1029
  Soft navigations are navigations that do not trigger a full page reload, such as SPA navigations. Defaults to false.
package/index.esm2.js CHANGED
@@ -230,6 +230,7 @@ var SESSION_RECORDER_SEGMENTS_MAP = 'rumSessionRecorderSegmentsMap';
230
230
  var VIEW_NUMBER_KEY = 'rum_view_number';
231
231
 
232
232
  var SNAPSHOT_MANAGER_KEY = 'rumSnapshotManager';
233
+ var SNAPSHOT_KEY = 'rum_snapshot';
233
234
  var INITIAL_SNAPSHOT_CONTEXT = {
234
235
  errorCount: 0,
235
236
  viewCount: 0,
@@ -2145,9 +2146,64 @@ var CX_ACTION_NAME_ATTRIBUTE = 'data-cx-action-name';
2145
2146
  var DATA_TEST_ATTRIBUTE = 'data-test';
2146
2147
  var DATA_TESTID_ATTRIBUTE = 'data-testid';
2147
2148
  var DATA_TEST_ID_ATTRIBUTE = 'data-test-id';
2149
+ var RR_IS_PASSWORD_ATTRIBUTE = 'data-rr-is-password';
2150
+
2151
+ var knownPasswordInputs = new WeakSet();
2152
+ var TYPE_ATTRIBUTE = 'type';
2153
+ var observer;
2154
+ function isKnownPasswordInput(element) {
2155
+ return (element instanceof HTMLInputElement && knownPasswordInputs.has(element));
2156
+ }
2157
+ function startPasswordInputObserver() {
2158
+ var doc = CxGlobal.document;
2159
+ if (observer || !doc) {
2160
+ return;
2161
+ }
2162
+ try {
2163
+ observer = createCxMutationObserver(handleMutations);
2164
+ observer.observe(doc.documentElement, {
2165
+ subtree: true,
2166
+ attributes: true,
2167
+ attributeOldValue: true,
2168
+ attributeFilter: [TYPE_ATTRIBUTE],
2169
+ });
2170
+ }
2171
+ catch (_a) {
2172
+ observer = undefined;
2173
+ }
2174
+ }
2175
+ function stopPasswordInputObserver() {
2176
+ observer === null || observer === void 0 ? void 0 : observer.disconnect();
2177
+ observer = undefined;
2178
+ }
2179
+ function handleMutations(mutations) {
2180
+ var e_1, _a;
2181
+ try {
2182
+ for (var mutations_1 = __values$1(mutations), mutations_1_1 = mutations_1.next(); !mutations_1_1.done; mutations_1_1 = mutations_1.next()) {
2183
+ var mutation = mutations_1_1.value;
2184
+ var target = mutation.target;
2185
+ if (target instanceof HTMLInputElement &&
2186
+ (mutation.oldValue || '').toLowerCase() === PASSWORD_INPUT_TYPE) {
2187
+ knownPasswordInputs.add(target);
2188
+ }
2189
+ }
2190
+ }
2191
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
2192
+ finally {
2193
+ try {
2194
+ if (mutations_1_1 && !mutations_1_1.done && (_a = mutations_1.return)) _a.call(mutations_1);
2195
+ }
2196
+ finally { if (e_1) throw e_1.error; }
2197
+ }
2198
+ }
2148
2199
 
2149
2200
  var PARENT_SEARCH_DEPTH = 5;
2150
- var CLICKABLE_ELEMENTS = ['BUTTON', 'LABEL', 'A', 'INPUT', 'OPTION', 'LI'];
2201
+ var POINTER_CURSOR = 'pointer';
2202
+ var CLICKABLE_SELECTOR = 'a, button, input, select, textarea, label, summary, option, li, ' +
2203
+ '[role="button"], [role="link"], [role="tab"], ' +
2204
+ '[role="menuitem"], [role="menuitemcheckbox"], [role="menuitemradio"], ' +
2205
+ '[role="checkbox"], [role="radio"], [role="switch"], ' +
2206
+ '[role="option"], [role="combobox"]';
2151
2207
  function getAttributeFromAncestors(element, attr, depth) {
2152
2208
  if (depth === void 0) { depth = PARENT_SEARCH_DEPTH; }
2153
2209
  if (!element || depth <= 0)
@@ -2167,14 +2223,14 @@ function extractTestId(el) {
2167
2223
  return (el === null || el === void 0 ? void 0 : el.getAttribute(DATA_TEST_ATTRIBUTE)) || '';
2168
2224
  }
2169
2225
  function extractResolvedName(_a) {
2170
- var element = _a.element, config = _a.config, actionName = _a.actionName, ariaLabel = _a.ariaLabel;
2226
+ var element = _a.element, clickableElement = _a.clickableElement, config = _a.config, actionName = _a.actionName, ariaLabel = _a.ariaLabel;
2171
2227
  if (!element)
2172
2228
  return '';
2173
2229
  if (actionName)
2174
2230
  return actionName;
2175
2231
  if (isElementMasked(element, config))
2176
2232
  return MASKED_TEXT;
2177
- return ariaLabel || getPlaceholder(element) || getInnerText(element) || '';
2233
+ return (ariaLabel || getPlaceholder(element) || getInnerText(clickableElement) || '');
2178
2234
  }
2179
2235
  function getPlaceholder(element) {
2180
2236
  if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
@@ -2182,18 +2238,14 @@ function getPlaceholder(element) {
2182
2238
  }
2183
2239
  return '';
2184
2240
  }
2185
- function getInnerText(element) {
2186
- var clickableElement = findClickableElement(element, PARENT_SEARCH_DEPTH);
2241
+ function getInnerText(clickableElement) {
2187
2242
  if (!clickableElement)
2188
2243
  return '';
2189
2244
  return clickableElement instanceof HTMLElement
2190
2245
  ? clickableElement.innerText || ''
2191
2246
  : '';
2192
2247
  }
2193
- function extractMaskedOrTextContent(element, config) {
2194
- if (!element)
2195
- return '';
2196
- var clickableElement = findClickableElement(element, PARENT_SEARCH_DEPTH);
2248
+ function extractMaskedOrTextContent(clickableElement, config) {
2197
2249
  if (!clickableElement)
2198
2250
  return '';
2199
2251
  return getMaskedOrTextualContent(clickableElement, config);
@@ -2223,22 +2275,30 @@ function shouldMaskElement(element, maskInputTypes, maskClass) {
2223
2275
  if (!element)
2224
2276
  return false;
2225
2277
  return (isMaskedInput(element, maskInputTypes) ||
2226
- isMaskedByClass(element.className, maskClass));
2278
+ isMaskedByClass(getClassName(element), maskClass));
2279
+ }
2280
+ function getClassName(element) {
2281
+ var _a;
2282
+ return (_a = element.getAttribute('class')) !== null && _a !== void 0 ? _a : '';
2227
2283
  }
2228
2284
  function isMaskedInput(element, maskInputTypes) {
2229
- if (element instanceof HTMLInputElement) {
2230
- var inputType = element.type || 'text';
2231
- return maskInputTypes.includes(inputType);
2285
+ if (!(element instanceof HTMLInputElement)) {
2286
+ return false;
2232
2287
  }
2233
- return false;
2288
+ var inputType = element.type || 'text';
2289
+ if (maskInputTypes.includes(inputType)) {
2290
+ return true;
2291
+ }
2292
+ return (maskInputTypes.includes(PASSWORD_INPUT_TYPE) && wasPasswordInput(element));
2293
+ }
2294
+ function wasPasswordInput(element) {
2295
+ return (element.hasAttribute(RR_IS_PASSWORD_ATTRIBUTE) ||
2296
+ isKnownPasswordInput(element));
2234
2297
  }
2235
2298
  function isMaskedByClass(className, maskClass) {
2236
2299
  if (maskClass instanceof RegExp) {
2237
2300
  return maskClass.test(className);
2238
2301
  }
2239
- if (typeof className !== 'string') {
2240
- return false;
2241
- }
2242
2302
  return className.includes(maskClass);
2243
2303
  }
2244
2304
  function isParentMasked(element, maskClass, maxDepth) {
@@ -2246,7 +2306,7 @@ function isParentMasked(element, maskClass, maxDepth) {
2246
2306
  if (!element || maxDepth <= 0) {
2247
2307
  return false;
2248
2308
  }
2249
- if (isMaskedByClass(element.className, maskClass)) {
2309
+ if (isMaskedByClass(getClassName(element), maskClass)) {
2250
2310
  return true;
2251
2311
  }
2252
2312
  return isParentMasked(element.parentElement, maskClass, maxDepth - 1);
@@ -2258,15 +2318,64 @@ function findMaskedChildren(element, config) {
2258
2318
  return shouldMaskElement(child, config.maskInputTypes, config.maskClass);
2259
2319
  });
2260
2320
  }
2261
- function findClickableElement(element, maxDepth) {
2262
- if (!element || maxDepth <= 0) {
2321
+ function findSemanticClickable(element, maxDepth) {
2322
+ if (!element || element === document.body || maxDepth <= 0)
2263
2323
  return null;
2264
- }
2265
- if (CLICKABLE_ELEMENTS.includes(element.nodeName))
2324
+ if (element.matches(CLICKABLE_SELECTOR))
2266
2325
  return element;
2267
- return findClickableElement(element.parentElement, maxDepth - 1);
2326
+ return findSemanticClickable(element.parentElement, maxDepth - 1);
2327
+ }
2328
+ function getClickableElement(element) {
2329
+ var _a;
2330
+ if (!element)
2331
+ return null;
2332
+ return ((_a = getComputedStyle(element)) === null || _a === void 0 ? void 0 : _a.cursor) === POINTER_CURSOR ? element : null;
2333
+ }
2334
+ function findClickableElement(element, maxDepth) {
2335
+ var _a;
2336
+ if (maxDepth === void 0) { maxDepth = PARENT_SEARCH_DEPTH; }
2337
+ return ((_a = findSemanticClickable(element, maxDepth)) !== null && _a !== void 0 ? _a : getClickableElement(element));
2268
2338
  }
2269
2339
 
2340
+ var RAGE_CLICK_THRESHOLD = 3;
2341
+ var RAGE_CLICK_WINDOW_MS = 1000;
2342
+ var RageClickTracker = (function () {
2343
+ function RageClickTracker() {
2344
+ this.clickHistory = new Map();
2345
+ }
2346
+ RageClickTracker.prototype.recordClick = function (fingerprint, now) {
2347
+ var _a;
2348
+ this.prune(now - RAGE_CLICK_WINDOW_MS);
2349
+ var recentClicks = (_a = this.clickHistory.get(fingerprint)) !== null && _a !== void 0 ? _a : [];
2350
+ recentClicks.push(now);
2351
+ this.clickHistory.set(fingerprint, recentClicks);
2352
+ return recentClicks.length >= RAGE_CLICK_THRESHOLD;
2353
+ };
2354
+ RageClickTracker.prototype.clear = function () {
2355
+ this.clickHistory.clear();
2356
+ };
2357
+ RageClickTracker.prototype.prune = function (windowStart) {
2358
+ var e_1, _a;
2359
+ try {
2360
+ for (var _b = __values$1(this.clickHistory), _c = _b.next(); !_c.done; _c = _b.next()) {
2361
+ var _d = __read$1(_c.value, 2), fingerprint = _d[0], timestamps = _d[1];
2362
+ var recentClicks = timestamps.filter(function (time) { return time >= windowStart; });
2363
+ recentClicks.length === 0
2364
+ ? this.clickHistory.delete(fingerprint)
2365
+ : this.clickHistory.set(fingerprint, recentClicks);
2366
+ }
2367
+ }
2368
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
2369
+ finally {
2370
+ try {
2371
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
2372
+ }
2373
+ finally { if (e_1) throw e_1.error; }
2374
+ }
2375
+ };
2376
+ return RageClickTracker;
2377
+ }());
2378
+
2270
2379
  var SHADOW_DOM_MARKER = '::shadow ';
2271
2380
  var STABLE_ATTRIBUTES = [
2272
2381
  CX_ACTION_NAME_ATTRIBUTE,
@@ -2444,18 +2553,18 @@ var USER_INTERACTION_INSTRUMENTATION_VERSION = '1';
2444
2553
  var DEFAULT_INSTRUMENTED_EVENTS = (_a$3 = {},
2445
2554
  _a$3["click"] = true,
2446
2555
  _a$3);
2556
+ var stopListeners = function () { };
2447
2557
  var CoralogixUserInteractionInstrumentation = (function (_super) {
2448
2558
  __extends(CoralogixUserInteractionInstrumentation, _super);
2449
2559
  function CoralogixUserInteractionInstrumentation(config) {
2450
2560
  var _this = _super.call(this, USER_INTERACTION_INSTRUMENTATION_NAME, USER_INTERACTION_INSTRUMENTATION_VERSION, config) || this;
2451
- _this.handler = function (_) { };
2452
- _this.stop = function () { };
2561
+ _this.rageClicksTracker = new RageClickTracker();
2453
2562
  return _this;
2454
2563
  }
2455
2564
  CoralogixUserInteractionInstrumentation.prototype.enable = function () {
2456
2565
  var _this = this;
2457
- var _a;
2458
- this.handler = function (e) {
2566
+ stopListeners();
2567
+ var handler = function (e) {
2459
2568
  var _a;
2460
2569
  var span;
2461
2570
  if (shouldAttachSpanToGlobalSpan(CoralogixEventType.USER_INTERACTION)) {
@@ -2466,7 +2575,7 @@ var CoralogixUserInteractionInstrumentation = (function (_super) {
2466
2575
  }
2467
2576
  var eventTarget = e.target;
2468
2577
  var config = getSdkConfig();
2469
- var id = eventTarget.id, type = eventTarget.type, className = eventTarget.className, nodeName = eventTarget.nodeName;
2578
+ var id = eventTarget.id, type = eventTarget.type, nodeName = eventTarget.nodeName;
2470
2579
  var clickKey = generateUUID();
2471
2580
  span.setAttribute(CoralogixAttributes.EVENT_TYPE, CoralogixEventType.USER_INTERACTION);
2472
2581
  span.setAttribute(CoralogixAttributes.INTERACTION_EVENT_NAME, e.type);
@@ -2477,27 +2586,34 @@ var CoralogixUserInteractionInstrumentation = (function (_super) {
2477
2586
  span.setAttribute(CoralogixAttributes.ELEMENT_RELATIVE_X, e.offsetX);
2478
2587
  span.setAttribute(CoralogixAttributes.ELEMENT_RELATIVE_Y, e.offsetY);
2479
2588
  }
2480
- if (eventTarget && eventTarget instanceof HTMLElement) {
2481
- var elementText = extractMaskedOrTextContent(eventTarget, config);
2589
+ if (eventTarget instanceof Element) {
2590
+ var clickableElement = findClickableElement(eventTarget);
2591
+ var elementText = extractMaskedOrTextContent(clickableElement, config);
2482
2592
  var cxActionName = extractActionName(eventTarget);
2483
2593
  var ariaLabel = extractAriaLabel(eventTarget);
2484
2594
  var testId = extractTestId(eventTarget);
2485
2595
  var resolvedName = extractResolvedName({
2486
2596
  element: eventTarget,
2597
+ clickableElement: clickableElement,
2487
2598
  config: config,
2488
2599
  actionName: cxActionName,
2489
2600
  ariaLabel: ariaLabel,
2490
2601
  });
2602
+ span.setAttribute(CoralogixAttributes.IS_DEAD_CLICK, clickableElement === null);
2491
2603
  var _b = eventTarget.getBoundingClientRect(), width = _b.width, height = _b.height;
2492
2604
  span.setAttribute(CoralogixAttributes.ELEMENT_WIDTH, width);
2493
2605
  span.setAttribute(CoralogixAttributes.ELEMENT_HEIGHT, height);
2494
2606
  var fingerprint = getElementFingerprint(eventTarget);
2495
2607
  if (fingerprint) {
2496
2608
  span.setAttribute(CoralogixAttributes.ELEMENT_FINGERPRINT, fingerprint);
2609
+ var isRageClick = clickableElement
2610
+ ? _this.rageClicksTracker.recordClick(fingerprint, Date.now())
2611
+ : false;
2612
+ span.setAttribute(CoralogixAttributes.IS_RAGE_CLICK, isRageClick);
2497
2613
  }
2498
2614
  [
2499
2615
  [CoralogixAttributes.ELEMENT_ID, id],
2500
- [CoralogixAttributes.ELEMENT_CLASSES, className],
2616
+ [CoralogixAttributes.ELEMENT_CLASSES, getClassName(eventTarget)],
2501
2617
  [CoralogixAttributes.TARGET_ELEMENT_TYPE, type],
2502
2618
  [
2503
2619
  CoralogixAttributes.ELEMENT_INNER_TEXT,
@@ -2519,7 +2635,7 @@ var CoralogixUserInteractionInstrumentation = (function (_super) {
2519
2635
  span.end();
2520
2636
  (_a = getClickScreenshotManager()) === null || _a === void 0 ? void 0 : _a.handleClick();
2521
2637
  };
2522
- var eventsMap = __assign(__assign({}, DEFAULT_INSTRUMENTED_EVENTS), (_a = this._config) === null || _a === void 0 ? void 0 : _a['events']);
2638
+ var eventsMap = __assign(__assign({}, DEFAULT_INSTRUMENTED_EVENTS), this.getConfig().events);
2523
2639
  var eventNames = Object.entries(eventsMap)
2524
2640
  .filter(function (_a) {
2525
2641
  var _b = __read$1(_a, 2); _b[0]; var enabled = _b[1];
@@ -2529,13 +2645,17 @@ var CoralogixUserInteractionInstrumentation = (function (_super) {
2529
2645
  var _b = __read$1(_a, 1), eventName = _b[0];
2530
2646
  return eventName;
2531
2647
  });
2532
- this.stop = addEventListeners(document, eventNames, this.handler, {
2648
+ stopListeners = addEventListeners(document, eventNames, handler, {
2533
2649
  capture: true,
2534
2650
  passive: true,
2535
2651
  }).stop;
2652
+ startPasswordInputObserver();
2536
2653
  };
2537
2654
  CoralogixUserInteractionInstrumentation.prototype.disable = function () {
2538
- this.stop();
2655
+ stopListeners();
2656
+ stopListeners = function () { };
2657
+ this.rageClicksTracker.clear();
2658
+ stopPasswordInputObserver();
2539
2659
  };
2540
2660
  CoralogixUserInteractionInstrumentation.prototype.init = function () { };
2541
2661
  return CoralogixUserInteractionInstrumentation;
@@ -2920,10 +3040,8 @@ var CoralogixWorkerInstrumentation = (function (_super) {
2920
3040
 
2921
3041
  var CORALOGIX_LOGS_URL_SUFFIX = '/browser/v1beta/logs';
2922
3042
  var CORALOGIX_RECORDING_URL_SUFFIX = '/sessionrecording';
2923
- var MAX_EXPORT_BATCH_SIZE = 50;
2924
3043
  var MAX_INTERACTION_ELEMENT_SIZE = 1024;
2925
3044
  var MAX_CHARACTERS = 1024;
2926
- var SCHEDULE_DELAY_MILLIS = 2 * millisecondsPerSecond;
2927
3045
  var REQUIRED_CONFIG_KEYS = [
2928
3046
  'application',
2929
3047
  'version',
@@ -2939,11 +3057,8 @@ var MASKED_TEXT = '***';
2939
3057
  var MASK_CLASS_DEFAULT = 'cx-mask';
2940
3058
  var CX_PREFIX = 'cx';
2941
3059
  var ARIA_LABEL_ATTRIBUTE = 'aria-label';
2942
- var MASK_INPUT_TYPES_DEFAULT = [
2943
- 'password',
2944
- 'email',
2945
- 'tel',
2946
- ];
3060
+ var PASSWORD_INPUT_TYPE = 'password';
3061
+ var MASK_INPUT_TYPES_DEFAULT = [PASSWORD_INPUT_TYPE];
2947
3062
  var FINGER_PRINT_KEY = 'cx-fingerprint';
2948
3063
  var idPatterns = [
2949
3064
  {
@@ -3095,6 +3210,8 @@ var CoralogixAttributes = {
3095
3210
  INTERNAL: 'internal',
3096
3211
  PAGE_CONTEXT: 'page_context',
3097
3212
  IS_NAVIGATION_EVENT: 'is_navigation_event',
3213
+ IS_DEAD_CLICK: 'is_dead_click',
3214
+ IS_RAGE_CLICK: 'is_rage_click',
3098
3215
  SCREENSHOT_CONTEXT: 'screenshot_context',
3099
3216
  DOM_CONTEXT: 'dom_context',
3100
3217
  };
@@ -3115,6 +3232,11 @@ var BASE_PATH = '/';
3115
3232
  var HASH_SEPARATOR = '#';
3116
3233
  var PARAMS_SEPARATOR = '?';
3117
3234
  var PROTOCOL_SEPARATOR = '://';
3235
+ var DOT = '.';
3236
+ var COLON = ':';
3237
+ var REGISTRABLE_DOMAIN_LABEL_COUNT = 2;
3238
+ var PAGE_URL_PARTS_KEY = 'rum_page_url_parts';
3239
+ var REFERRER_URL_PARTS_KEY = 'rum_referrer_url_parts';
3118
3240
 
3119
3241
  function saveInternalRumData(key, value) {
3120
3242
  if (!CxGlobal[RUM_INTERNAL_DATA_KEY]) {
@@ -3177,7 +3299,7 @@ var getUrlFragments = function (url) {
3177
3299
  if (url.startsWith('blob:')) {
3178
3300
  return url;
3179
3301
  }
3180
- return decodeURIComponent(new URL(url).pathname.substring(1)) || BASE_PATH;
3302
+ return (decodeURIComponent(new URL(url).pathname.substring(1)) || BASE_PATH);
3181
3303
  }
3182
3304
  catch (err) {
3183
3305
  console.warn('Coralogix Browser SDK - Error parsing URL', err);
@@ -3185,6 +3307,45 @@ var getUrlFragments = function (url) {
3185
3307
  }
3186
3308
  }
3187
3309
  };
3310
+ var getUrlParts = function (url) {
3311
+ if (!url) {
3312
+ return undefined;
3313
+ }
3314
+ try {
3315
+ var _a = new URL(url), protocol = _a.protocol, host = _a.host, hostname = _a.hostname;
3316
+ var labels = hostname.split(DOT);
3317
+ return {
3318
+ schema: protocol.replace(COLON, ''),
3319
+ host: host,
3320
+ subdomain: labels.slice(0, -REGISTRABLE_DOMAIN_LABEL_COUNT).join(DOT),
3321
+ domain: labels.slice(-REGISTRABLE_DOMAIN_LABEL_COUNT).join(DOT),
3322
+ };
3323
+ }
3324
+ catch (_b) {
3325
+ return undefined;
3326
+ }
3327
+ };
3328
+ var getCachedUrlParts = function (cacheKey, url) {
3329
+ var _a, _b;
3330
+ try {
3331
+ var stored = (_a = CxGlobal.sessionStorage) === null || _a === void 0 ? void 0 : _a.getItem(cacheKey);
3332
+ if (stored) {
3333
+ var cached = JSON.parse(stored);
3334
+ if (cached.url === url) {
3335
+ return cached.parts;
3336
+ }
3337
+ }
3338
+ }
3339
+ catch (_c) {
3340
+ }
3341
+ var parts = getUrlParts(url);
3342
+ try {
3343
+ (_b = CxGlobal.sessionStorage) === null || _b === void 0 ? void 0 : _b.setItem(cacheKey, JSON.stringify({ url: url, parts: parts }));
3344
+ }
3345
+ catch (_d) {
3346
+ }
3347
+ return parts;
3348
+ };
3188
3349
  function parseUserAgent(userAgent) {
3189
3350
  var e_1, _a, e_2, _b, e_3, _c;
3190
3351
  var _d, _e, _f;
@@ -3333,11 +3494,21 @@ function resolvePageContext(url) {
3333
3494
  blueprinters: (_a = getSdkConfig().urlBlueprinters) === null || _a === void 0 ? void 0 : _a.pageUrlBlueprinters,
3334
3495
  });
3335
3496
  var page_fragments = getUrlFragments(page_url_blueprint);
3497
+ var urlParts = getCachedUrlParts(PAGE_URL_PARTS_KEY, url);
3498
+ var referrerParts = getCachedUrlParts(REFERRER_URL_PARTS_KEY, document === null || document === void 0 ? void 0 : document.referrer);
3336
3499
  return {
3337
3500
  page_url: url.slice(0, MAX_CHARACTERS),
3338
3501
  page_url_blueprint: page_url_blueprint,
3339
3502
  page_fragments: page_fragments,
3503
+ schema: urlParts === null || urlParts === void 0 ? void 0 : urlParts.schema,
3504
+ subdomain: urlParts === null || urlParts === void 0 ? void 0 : urlParts.subdomain,
3505
+ domain: urlParts === null || urlParts === void 0 ? void 0 : urlParts.domain,
3506
+ host: urlParts === null || urlParts === void 0 ? void 0 : urlParts.host,
3340
3507
  referrer: document.referrer,
3508
+ referrer_schema: referrerParts === null || referrerParts === void 0 ? void 0 : referrerParts.schema,
3509
+ referrer_subdomain: referrerParts === null || referrerParts === void 0 ? void 0 : referrerParts.subdomain,
3510
+ referrer_domain: referrerParts === null || referrerParts === void 0 ? void 0 : referrerParts.domain,
3511
+ referrer_host: referrerParts === null || referrerParts === void 0 ? void 0 : referrerParts.host,
3341
3512
  };
3342
3513
  }
3343
3514
  function deepClone(obj) {
@@ -4246,6 +4417,114 @@ var SessionIdle = (function () {
4246
4417
  return SessionIdle;
4247
4418
  }());
4248
4419
 
4420
+ function clearStoredSnapshotState() {
4421
+ var _a;
4422
+ try {
4423
+ (_a = CxGlobal.sessionStorage) === null || _a === void 0 ? void 0 : _a.removeItem(SNAPSHOT_KEY);
4424
+ }
4425
+ catch (_b) {
4426
+ }
4427
+ }
4428
+ var SnapshotManager = (function () {
4429
+ function SnapshotManager() {
4430
+ var _this = this;
4431
+ this._shouldTriggerSnapshotContext = false;
4432
+ this.updateSnapshot = function (overrides) {
4433
+ _this._currentSnapshot = __assign(__assign({}, _this._currentSnapshot), overrides);
4434
+ _this.persistSnapshot();
4435
+ };
4436
+ this.resetSnapshot = function () {
4437
+ _this._currentSnapshot = __assign(__assign({}, INITIAL_SNAPSHOT_CONTEXT), { timestamp: getNowTime() });
4438
+ _this._fragmentsState = new Set();
4439
+ _this._isSnapshotSentDueToRecording = false;
4440
+ clearStoredSnapshotState();
4441
+ };
4442
+ CxGlobal[SNAPSHOT_MANAGER_KEY] = this;
4443
+ if (!this.restoreSnapshot()) {
4444
+ this.resetSnapshot();
4445
+ }
4446
+ }
4447
+ Object.defineProperty(SnapshotManager.prototype, "fragmentsState", {
4448
+ get: function () {
4449
+ return this._fragmentsState;
4450
+ },
4451
+ enumerable: false,
4452
+ configurable: true
4453
+ });
4454
+ Object.defineProperty(SnapshotManager.prototype, "currentSnapshot", {
4455
+ get: function () {
4456
+ return this._currentSnapshot;
4457
+ },
4458
+ enumerable: false,
4459
+ configurable: true
4460
+ });
4461
+ Object.defineProperty(SnapshotManager.prototype, "isSnapshotSentDueToRecording", {
4462
+ get: function () {
4463
+ return this._isSnapshotSentDueToRecording;
4464
+ },
4465
+ set: function (value) {
4466
+ this._isSnapshotSentDueToRecording = value;
4467
+ this.persistSnapshot();
4468
+ },
4469
+ enumerable: false,
4470
+ configurable: true
4471
+ });
4472
+ Object.defineProperty(SnapshotManager.prototype, "shouldTriggerSnapshotContext", {
4473
+ get: function () {
4474
+ return this._shouldTriggerSnapshotContext;
4475
+ },
4476
+ set: function (value) {
4477
+ this._shouldTriggerSnapshotContext = value;
4478
+ },
4479
+ enumerable: false,
4480
+ configurable: true
4481
+ });
4482
+ SnapshotManager.prototype.shouldPersistSnapshot = function () {
4483
+ var _a, _b;
4484
+ return !!((_b = (_a = getSdkConfig()) === null || _a === void 0 ? void 0 : _a.sessionConfig) === null || _b === void 0 ? void 0 : _b.keepSessionAfterReload);
4485
+ };
4486
+ SnapshotManager.prototype.persistSnapshot = function () {
4487
+ var _a;
4488
+ if (!this.shouldPersistSnapshot()) {
4489
+ return;
4490
+ }
4491
+ try {
4492
+ var state = {
4493
+ snapshot: this._currentSnapshot,
4494
+ fragments: Array.from(this._fragmentsState),
4495
+ isSnapshotSentDueToRecording: this._isSnapshotSentDueToRecording,
4496
+ };
4497
+ (_a = CxGlobal.sessionStorage) === null || _a === void 0 ? void 0 : _a.setItem(SNAPSHOT_KEY, JSON.stringify(state));
4498
+ }
4499
+ catch (_b) {
4500
+ }
4501
+ };
4502
+ SnapshotManager.prototype.restoreSnapshot = function () {
4503
+ var _a;
4504
+ if (!this.shouldPersistSnapshot()) {
4505
+ return false;
4506
+ }
4507
+ try {
4508
+ var storedState = (_a = CxGlobal.sessionStorage) === null || _a === void 0 ? void 0 : _a.getItem(SNAPSHOT_KEY);
4509
+ if (!storedState) {
4510
+ return false;
4511
+ }
4512
+ var _b = JSON.parse(storedState), snapshot = _b.snapshot, fragments = _b.fragments, isSnapshotSentDueToRecording = _b.isSnapshotSentDueToRecording;
4513
+ if (!snapshot || !Array.isArray(fragments)) {
4514
+ return false;
4515
+ }
4516
+ this._currentSnapshot = __assign(__assign(__assign({}, INITIAL_SNAPSHOT_CONTEXT), { timestamp: getNowTime() }), snapshot);
4517
+ this._fragmentsState = new Set(fragments);
4518
+ this._isSnapshotSentDueToRecording = !!isSnapshotSentDueToRecording;
4519
+ return true;
4520
+ }
4521
+ catch (_c) {
4522
+ return false;
4523
+ }
4524
+ };
4525
+ return SnapshotManager;
4526
+ }());
4527
+
4249
4528
  var _a;
4250
4529
  var instrumentationsCompatibility = (_a = {},
4251
4530
  _a[XHR_INSTRUMENTATION_NAME] = {
@@ -4509,6 +4788,7 @@ var SessionManager = (function (_super) {
4509
4788
  this.clearGlobalSpans();
4510
4789
  this.clearSessionWithErrorMode();
4511
4790
  (_d = getSnapshotManager()) === null || _d === void 0 ? void 0 : _d.resetSnapshot();
4791
+ clearStoredSnapshotState();
4512
4792
  (_e = getClickScreenshotManager()) === null || _e === void 0 ? void 0 : _e.reset();
4513
4793
  this._currentPageFragment = undefined;
4514
4794
  this.resetViewNumber();
@@ -4639,6 +4919,49 @@ var CxPropagator = (function () {
4639
4919
  return CxPropagator;
4640
4920
  }());
4641
4921
 
4922
+ var SCHEDULED_DELAY_MILLIS_BOUND = {
4923
+ default: 2 * millisecondsPerSecond,
4924
+ min: 2 * millisecondsPerSecond,
4925
+ max: 30 * millisecondsPerSecond,
4926
+ };
4927
+ var MAX_EXPORT_BATCH_SIZE_BOUND = {
4928
+ default: 50,
4929
+ min: 1,
4930
+ max: 256,
4931
+ };
4932
+ var MAX_QUEUE_SIZE_BOUND = {
4933
+ default: 2048,
4934
+ min: 512,
4935
+ max: 4096,
4936
+ };
4937
+
4938
+ function resolveBoundedValue(value, range, optionName) {
4939
+ var defaultValue = range.default, min = range.min, max = range.max;
4940
+ if (value == null) {
4941
+ return defaultValue;
4942
+ }
4943
+ if (!Number.isFinite(value)) {
4944
+ console.warn("CoralogixRum: otelConfig.".concat(optionName, " value \"").concat(value, "\" is not a valid number; using the default (").concat(defaultValue, ") instead."));
4945
+ return defaultValue;
4946
+ }
4947
+ if (value < min || value > max) {
4948
+ var clamped = Math.min(Math.max(value, min), max);
4949
+ console.warn("CoralogixRum: otelConfig.".concat(optionName, " value ").concat(value, " is out of range [").concat(min, ", ").concat(max, "]; using ").concat(clamped, " instead."));
4950
+ return clamped;
4951
+ }
4952
+ return value;
4953
+ }
4954
+ function resolveOtelConfig(config) {
4955
+ var scheduledDelayMillis = resolveBoundedValue(config === null || config === void 0 ? void 0 : config.scheduledDelayMillis, SCHEDULED_DELAY_MILLIS_BOUND, 'scheduledDelayMillis');
4956
+ var maxQueueSize = resolveBoundedValue(config === null || config === void 0 ? void 0 : config.maxQueueSize, MAX_QUEUE_SIZE_BOUND, 'maxQueueSize');
4957
+ var maxExportBatchSize = Math.min(resolveBoundedValue(config === null || config === void 0 ? void 0 : config.maxExportBatchSize, MAX_EXPORT_BATCH_SIZE_BOUND, 'maxExportBatchSize'), maxQueueSize);
4958
+ return {
4959
+ maxExportBatchSize: maxExportBatchSize,
4960
+ scheduledDelayMillis: scheduledDelayMillis,
4961
+ maxQueueSize: maxQueueSize,
4962
+ };
4963
+ }
4964
+
4642
4965
  function isInitialConfigValid(initConfig) {
4643
4966
  var e_1, _a;
4644
4967
  if (!initConfig) {
@@ -4678,7 +5001,7 @@ function validateAndResolveInitConfig(config) {
4678
5001
  if (proxyUrl)
4679
5002
  resolvedIgnoreUrls.push(new RegExp(proxyUrl));
4680
5003
  OPTIONS_DEFAULTS.ignoreUrls && resolvedIgnoreUrls.push.apply(resolvedIgnoreUrls, __spreadArray([], __read$1(OPTIONS_DEFAULTS.ignoreUrls), false));
4681
- return __assign(__assign(__assign({}, OPTIONS_DEFAULTS), config), { maskInputTypes: (_a = config.maskInputTypes) !== null && _a !== void 0 ? _a : MASK_INPUT_TYPES_DEFAULT, maskClass: (_b = config.maskClass) !== null && _b !== void 0 ? _b : MASK_CLASS_DEFAULT, ignoreUrls: resolvedIgnoreUrls, urlBlueprinters: resolveUrlBlueprinters(urlBlueprinters), sessionSampleRate: (_c = config.sessionSampleRate) !== null && _c !== void 0 ? _c : 100, sessionConfig: resolveSessionConfig(config.sessionConfig), sessionRecordingConfig: resolveSessionRecordingConfig(config.sessionRecordingConfig), memoryUsageConfig: resolveMemoryUsageConfig(config.memoryUsageConfig), trackSoftNavigations: !!config.trackSoftNavigations, supportMfe: !!config.supportMfe, runOutsideAngularZone: (_d = config.runOutsideAngularZone) !== null && _d !== void 0 ? _d : true });
5004
+ return __assign(__assign(__assign({}, OPTIONS_DEFAULTS), config), { maskInputTypes: (_a = config.maskInputTypes) !== null && _a !== void 0 ? _a : MASK_INPUT_TYPES_DEFAULT, maskClass: (_b = config.maskClass) !== null && _b !== void 0 ? _b : MASK_CLASS_DEFAULT, ignoreUrls: resolvedIgnoreUrls, urlBlueprinters: resolveUrlBlueprinters(urlBlueprinters), sessionSampleRate: (_c = config.sessionSampleRate) !== null && _c !== void 0 ? _c : 100, sessionConfig: resolveSessionConfig(config.sessionConfig), sessionRecordingConfig: resolveSessionRecordingConfig(config.sessionRecordingConfig), memoryUsageConfig: resolveMemoryUsageConfig(config.memoryUsageConfig), otelConfig: resolveOtelConfig(config.otelConfig), trackSoftNavigations: !!config.trackSoftNavigations, supportMfe: !!config.supportMfe, runOutsideAngularZone: (_d = config.runOutsideAngularZone) !== null && _d !== void 0 ? _d : true });
4682
5005
  }
4683
5006
  function resolveMemoryUsageConfig(memoryUsageConfig) {
4684
5007
  var _a;
@@ -4712,7 +5035,7 @@ function resolveUrlBlueprinters(urlBlueprinters) {
4712
5035
  return resolvedUrlBlueprinters;
4713
5036
  }
4714
5037
 
4715
- var SDK_VERSION = '3.16.0';
5038
+ var SDK_VERSION = '3.18.0';
4716
5039
 
4717
5040
  function shouldDropEvent(cxRumEvent, options) {
4718
5041
  if (isDocumentErrorWithoutMessage(cxRumEvent)) {
@@ -4771,8 +5094,14 @@ function validateBeforeSendResult(beforeSendResult) {
4771
5094
  return beforeSendResult;
4772
5095
  }
4773
5096
  function cxRumEventToEditable(cxRumEvent) {
4774
- var _a = cxRumEvent.session_context, user_id = _a.user_id, user_name = _a.user_name, user_email = _a.user_email, user_metadata = _a.user_metadata; cxRumEvent.browser_sdk; cxRumEvent.timestamp; var rest = __rest(cxRumEvent, ["session_context", "browser_sdk", "timestamp"]);
4775
- return __assign(__assign({}, rest), { session_context: { user_id: user_id, user_email: user_email, user_name: user_name, user_metadata: user_metadata } });
5097
+ var _a = cxRumEvent.session_context, user_id = _a.user_id, user_name = _a.user_name, user_email = _a.user_email, account_id = _a.account_id, user_metadata = _a.user_metadata; cxRumEvent.browser_sdk; cxRumEvent.timestamp; cxRumEvent.isNavigationEvent; cxRumEvent.isSnapshotEvent; cxRumEvent.view_number; var rest = __rest(cxRumEvent, ["session_context", "browser_sdk", "timestamp", "isNavigationEvent", "isSnapshotEvent", "view_number"]);
5098
+ return __assign(__assign({}, rest), { session_context: {
5099
+ user_id: user_id,
5100
+ user_email: user_email,
5101
+ user_name: user_name,
5102
+ account_id: account_id,
5103
+ user_metadata: user_metadata,
5104
+ } });
4776
5105
  }
4777
5106
  function editableToCxRumEvent(editable, cxRumEvent) {
4778
5107
  return __assign(__assign(__assign({}, cxRumEvent), editable), { session_context: __assign(__assign({}, cxRumEvent.session_context), editable.session_context) });
@@ -4823,7 +5152,7 @@ function flattenToAttributes(obj, prefix) {
4823
5152
  function buildRumContextAttributes(cxRumEvent, resolvedLabels) {
4824
5153
  var session_context = cxRumEvent.session_context, page_context = cxRumEvent.page_context, event_context = cxRumEvent.event_context, error_context = cxRumEvent.error_context, network_request_context = cxRumEvent.network_request_context;
4825
5154
  var prefixedLabels = flattenToAttributes(resolvedLabels, 'cx_rum.labels.');
4826
- return buildCxRumSpanAttributes(__assign(__assign({ 'cx_rum.browser_sdk.version': cxRumEvent.browser_sdk.version, 'cx_rum.platform': cxRumEvent.platform, 'cx_rum.environment': cxRumEvent.environment, 'cx_rum.version_metadata.app_name': cxRumEvent.version_metadata.app_name, 'cx_rum.version_metadata.app_version': cxRumEvent.version_metadata.app_version }, prefixedLabels), { 'cx_rum.session_context.session_id': session_context === null || session_context === void 0 ? void 0 : session_context.session_id, 'cx_rum.session_context.session_creation_date': session_context === null || session_context === void 0 ? void 0 : session_context.session_creation_date, 'cx_rum.session_context.hasRecording': session_context === null || session_context === void 0 ? void 0 : session_context.hasRecording, 'cx_rum.session_context.os': session_context === null || session_context === void 0 ? void 0 : session_context.os, 'cx_rum.session_context.osVersion': session_context === null || session_context === void 0 ? void 0 : session_context.osVersion, 'cx_rum.session_context.browser': session_context === null || session_context === void 0 ? void 0 : session_context.browser, 'cx_rum.session_context.browserVersion': session_context === null || session_context === void 0 ? void 0 : session_context.browserVersion, 'cx_rum.session_context.device': session_context === null || session_context === void 0 ? void 0 : session_context.device, 'cx_rum.session_context.user_agent': session_context === null || session_context === void 0 ? void 0 : session_context.user_agent, 'cx_rum.session_context.user_email': session_context === null || session_context === void 0 ? void 0 : session_context.user_email, 'cx_rum.session_context.user_id': session_context === null || session_context === void 0 ? void 0 : session_context.user_id, 'cx_rum.session_context.user_name': session_context === null || session_context === void 0 ? void 0 : session_context.user_name, 'cx_rum.page_context.page_fragments': page_context === null || page_context === void 0 ? void 0 : page_context.page_fragments, 'cx_rum.page_context.page_url_blueprint': page_context === null || page_context === void 0 ? void 0 : page_context.page_url_blueprint, 'cx_rum.event_context.type': event_context === null || event_context === void 0 ? void 0 : event_context.type, 'cx_rum.event_context.severity': event_context === null || event_context === void 0 ? void 0 : event_context.severity, 'cx_rum.error_context.error_type': error_context === null || error_context === void 0 ? void 0 : error_context.error_type, 'cx_rum.error_context.error_message': error_context === null || error_context === void 0 ? void 0 : error_context.error_message, 'cx_rum.network_request_context.fragments': network_request_context === null || network_request_context === void 0 ? void 0 : network_request_context.fragments, 'cx_rum.network_request_context.url': network_request_context === null || network_request_context === void 0 ? void 0 : network_request_context.url, 'cx_rum.network_request_context.status_code': network_request_context === null || network_request_context === void 0 ? void 0 : network_request_context.status_code, 'cx_rum.network_request_context.method': network_request_context === null || network_request_context === void 0 ? void 0 : network_request_context.method }));
5155
+ return buildCxRumSpanAttributes(__assign(__assign({ 'cx_rum.browser_sdk.version': cxRumEvent.browser_sdk.version, 'cx_rum.platform': cxRumEvent.platform, 'cx_rum.environment': cxRumEvent.environment, 'cx_rum.version_metadata.app_name': cxRumEvent.version_metadata.app_name, 'cx_rum.version_metadata.app_version': cxRumEvent.version_metadata.app_version }, prefixedLabels), { 'cx_rum.session_context.session_id': session_context === null || session_context === void 0 ? void 0 : session_context.session_id, 'cx_rum.session_context.session_creation_date': session_context === null || session_context === void 0 ? void 0 : session_context.session_creation_date, 'cx_rum.session_context.hasRecording': session_context === null || session_context === void 0 ? void 0 : session_context.hasRecording, 'cx_rum.session_context.os': session_context === null || session_context === void 0 ? void 0 : session_context.os, 'cx_rum.session_context.osVersion': session_context === null || session_context === void 0 ? void 0 : session_context.osVersion, 'cx_rum.session_context.browser': session_context === null || session_context === void 0 ? void 0 : session_context.browser, 'cx_rum.session_context.browserVersion': session_context === null || session_context === void 0 ? void 0 : session_context.browserVersion, 'cx_rum.session_context.device': session_context === null || session_context === void 0 ? void 0 : session_context.device, 'cx_rum.session_context.user_agent': session_context === null || session_context === void 0 ? void 0 : session_context.user_agent, 'cx_rum.session_context.user_email': session_context === null || session_context === void 0 ? void 0 : session_context.user_email, 'cx_rum.session_context.user_id': session_context === null || session_context === void 0 ? void 0 : session_context.user_id, 'cx_rum.session_context.user_name': session_context === null || session_context === void 0 ? void 0 : session_context.user_name, 'cx_rum.session_context.account_id': session_context === null || session_context === void 0 ? void 0 : session_context.account_id, 'cx_rum.page_context.page_fragments': page_context === null || page_context === void 0 ? void 0 : page_context.page_fragments, 'cx_rum.page_context.page_url_blueprint': page_context === null || page_context === void 0 ? void 0 : page_context.page_url_blueprint, 'cx_rum.event_context.type': event_context === null || event_context === void 0 ? void 0 : event_context.type, 'cx_rum.event_context.severity': event_context === null || event_context === void 0 ? void 0 : event_context.severity, 'cx_rum.error_context.error_type': error_context === null || error_context === void 0 ? void 0 : error_context.error_type, 'cx_rum.error_context.error_message': error_context === null || error_context === void 0 ? void 0 : error_context.error_message, 'cx_rum.network_request_context.fragments': network_request_context === null || network_request_context === void 0 ? void 0 : network_request_context.fragments, 'cx_rum.network_request_context.url': network_request_context === null || network_request_context === void 0 ? void 0 : network_request_context.url, 'cx_rum.network_request_context.status_code': network_request_context === null || network_request_context === void 0 ? void 0 : network_request_context.status_code, 'cx_rum.network_request_context.method': network_request_context === null || network_request_context === void 0 ? void 0 : network_request_context.method }));
4827
5156
  }
4828
5157
 
4829
5158
  var CoralogixSpanMapProcessor = (function () {
@@ -4997,6 +5326,7 @@ var CoralogixSpanMapProcessor = (function () {
4997
5326
  }
4998
5327
  case CoralogixEventType.NETWORK_REQUEST: {
4999
5328
  var url = spanAttributes[OtelNetworkAttrs.URL];
5329
+ var networkUrlParts = getUrlParts(url);
5000
5330
  var url_blueprint = applyUrlBluePrinters({
5001
5331
  url: url,
5002
5332
  blueprinters: (_a = this.sdkConfig.urlBlueprinters) === null || _a === void 0 ? void 0 : _a.networkUrlBlueprinters,
@@ -5010,6 +5340,8 @@ var CoralogixSpanMapProcessor = (function () {
5010
5340
  fragments: getUrlFragments(url_blueprint),
5011
5341
  host: spanAttributes[OtelNetworkAttrs.HOST],
5012
5342
  schema: spanAttributes[OtelNetworkAttrs.SCHEME],
5343
+ subdomain: networkUrlParts === null || networkUrlParts === void 0 ? void 0 : networkUrlParts.subdomain,
5344
+ domain: networkUrlParts === null || networkUrlParts === void 0 ? void 0 : networkUrlParts.domain,
5013
5345
  status_text: spanAttributes[OtelNetworkAttrs.STATUS_TEXT],
5014
5346
  duration: hrTimeToMilliseconds(span === null || span === void 0 ? void 0 : span.duration),
5015
5347
  source: spanAttributes[CoralogixAttributes.SOURCE],
@@ -5068,6 +5400,8 @@ var CoralogixSpanMapProcessor = (function () {
5068
5400
  element_width: spanAttributes[CoralogixAttributes.ELEMENT_WIDTH],
5069
5401
  element_height: spanAttributes[CoralogixAttributes.ELEMENT_HEIGHT],
5070
5402
  element_fingerprint: spanAttributes[CoralogixAttributes.ELEMENT_FINGERPRINT],
5403
+ is_dead_click: spanAttributes[CoralogixAttributes.IS_DEAD_CLICK],
5404
+ is_rage_click: spanAttributes[CoralogixAttributes.IS_RAGE_CLICK],
5071
5405
  },
5072
5406
  };
5073
5407
  }
@@ -5214,58 +5548,6 @@ var CoralogixSnapshotSpanProcessor = (function () {
5214
5548
  return CoralogixSnapshotSpanProcessor;
5215
5549
  }());
5216
5550
 
5217
- var SnapshotManager = (function () {
5218
- function SnapshotManager() {
5219
- var _this = this;
5220
- this._shouldTriggerSnapshotContext = false;
5221
- this.updateSnapshot = function (overrides) {
5222
- _this._currentSnapshot = __assign(__assign({}, _this._currentSnapshot), overrides);
5223
- };
5224
- this.resetSnapshot = function () {
5225
- _this._currentSnapshot = __assign(__assign({}, INITIAL_SNAPSHOT_CONTEXT), { timestamp: getNowTime() });
5226
- _this._fragmentsState = new Set();
5227
- _this._isSnapshotSentDueToRecording = false;
5228
- };
5229
- CxGlobal[SNAPSHOT_MANAGER_KEY] = this;
5230
- this.resetSnapshot();
5231
- }
5232
- Object.defineProperty(SnapshotManager.prototype, "fragmentsState", {
5233
- get: function () {
5234
- return this._fragmentsState;
5235
- },
5236
- enumerable: false,
5237
- configurable: true
5238
- });
5239
- Object.defineProperty(SnapshotManager.prototype, "currentSnapshot", {
5240
- get: function () {
5241
- return this._currentSnapshot;
5242
- },
5243
- enumerable: false,
5244
- configurable: true
5245
- });
5246
- Object.defineProperty(SnapshotManager.prototype, "isSnapshotSentDueToRecording", {
5247
- get: function () {
5248
- return this._isSnapshotSentDueToRecording;
5249
- },
5250
- set: function (value) {
5251
- this._isSnapshotSentDueToRecording = value;
5252
- },
5253
- enumerable: false,
5254
- configurable: true
5255
- });
5256
- Object.defineProperty(SnapshotManager.prototype, "shouldTriggerSnapshotContext", {
5257
- get: function () {
5258
- return this._shouldTriggerSnapshotContext;
5259
- },
5260
- set: function (value) {
5261
- this._shouldTriggerSnapshotContext = value;
5262
- },
5263
- enumerable: false,
5264
- configurable: true
5265
- });
5266
- return SnapshotManager;
5267
- }());
5268
-
5269
5551
  var CoralogixNavigationProcessor = (function () {
5270
5552
  function CoralogixNavigationProcessor() {
5271
5553
  this.isResolving = false;
@@ -5505,10 +5787,7 @@ var CoralogixRum = {
5505
5787
  }
5506
5788
  snapshotProcessor = new CoralogixSnapshotSpanProcessor();
5507
5789
  tracerProvider.addSpanProcessor(snapshotProcessor);
5508
- tracerProvider.addSpanProcessor(new BatchSpanProcessor((exporter = new CoralogixExporter()), {
5509
- maxExportBatchSize: MAX_EXPORT_BATCH_SIZE,
5510
- scheduledDelayMillis: SCHEDULE_DELAY_MILLIS,
5511
- }));
5790
+ tracerProvider.addSpanProcessor(new BatchSpanProcessor((exporter = new CoralogixExporter()), resolvedOptions_1.otelConfig));
5512
5791
  handlePropagators(options, tracerProvider);
5513
5792
  _deregisterInstrumentations = registerInstrumentations({
5514
5793
  tracerProvider: tracerProvider,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coralogix/browser",
3
- "version": "3.16.0",
3
+ "version": "3.18.0",
4
4
  "description": "Official Coralogix SDK for browsers",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Coralogix",
@@ -2,10 +2,8 @@ import { CoralogixBrowserSdkConfig, InputType } from './types';
2
2
  import { InternalInstrumentationConfig } from './instrumentations/instrumentation.model';
3
3
  export declare const CORALOGIX_LOGS_URL_SUFFIX = "/browser/v1beta/logs";
4
4
  export declare const CORALOGIX_RECORDING_URL_SUFFIX = "/sessionrecording";
5
- export declare const MAX_EXPORT_BATCH_SIZE = 50;
6
5
  export declare const MAX_INTERACTION_ELEMENT_SIZE = 1024;
7
6
  export declare const MAX_CHARACTERS = 1024;
8
- export declare const SCHEDULE_DELAY_MILLIS: number;
9
7
  export declare const REQUIRED_CONFIG_KEYS: Array<keyof CoralogixBrowserSdkConfig>;
10
8
  export { SDK_CONFIG_KEY, USER_AGENT_KEY } from './tools/global-keys';
11
9
  export declare const ID_MASK_KEY = "{id}";
@@ -18,6 +16,7 @@ export declare const MASKED_TEXT = "***";
18
16
  export declare const MASK_CLASS_DEFAULT = "cx-mask";
19
17
  export declare const CX_PREFIX = "cx";
20
18
  export declare const ARIA_LABEL_ATTRIBUTE = "aria-label";
19
+ export declare const PASSWORD_INPUT_TYPE: InputType;
21
20
  export declare const MASK_INPUT_TYPES_DEFAULT: InputType[];
22
21
  export declare const FINGER_PRINT_KEY = "cx-fingerprint";
23
22
  export declare const OPTIONS_DEFAULTS: Partial<CoralogixBrowserSdkConfig>;
@@ -61,6 +60,8 @@ export declare const CoralogixAttributes: {
61
60
  INTERNAL: string;
62
61
  PAGE_CONTEXT: string;
63
62
  IS_NAVIGATION_EVENT: string;
63
+ IS_DEAD_CLICK: string;
64
+ IS_RAGE_CLICK: string;
64
65
  SCREENSHOT_CONTEXT: string;
65
66
  DOM_CONTEXT: string;
66
67
  };
@@ -81,3 +82,8 @@ export declare const BASE_PATH = "/";
81
82
  export declare const HASH_SEPARATOR = "#";
82
83
  export declare const PARAMS_SEPARATOR = "?";
83
84
  export declare const PROTOCOL_SEPARATOR = "://";
85
+ export declare const DOT = ".";
86
+ export declare const COLON = ":";
87
+ export declare const REGISTRABLE_DOMAIN_LABEL_COUNT = 2;
88
+ export declare const PAGE_URL_PARTS_KEY = "rum_page_url_parts";
89
+ export declare const REFERRER_URL_PARTS_KEY = "rum_referrer_url_parts";
@@ -2,3 +2,4 @@ export declare const CX_ACTION_NAME_ATTRIBUTE = "data-cx-action-name";
2
2
  export declare const DATA_TEST_ATTRIBUTE = "data-test";
3
3
  export declare const DATA_TESTID_ATTRIBUTE = "data-testid";
4
4
  export declare const DATA_TEST_ID_ATTRIBUTE = "data-test-id";
5
+ export declare const RR_IS_PASSWORD_ATTRIBUTE = "data-rr-is-password";
@@ -7,9 +7,8 @@ export interface CoralogixUserInteractionInstrumentationConfig extends Instrumen
7
7
  events?: UserInteractionEventsConfig;
8
8
  }
9
9
  export declare const DEFAULT_INSTRUMENTED_EVENTS: UserInteractionEventsConfig;
10
- export declare class CoralogixUserInteractionInstrumentation extends InstrumentationBase {
11
- private handler;
12
- private stop;
10
+ export declare class CoralogixUserInteractionInstrumentation extends InstrumentationBase<CoralogixUserInteractionInstrumentationConfig> {
11
+ private readonly rageClicksTracker;
13
12
  constructor(config: CoralogixUserInteractionInstrumentationConfig);
14
13
  enable(): void;
15
14
  disable(): void;
@@ -0,0 +1,3 @@
1
+ export declare function isKnownPasswordInput(element: Element | HTMLElement): boolean;
2
+ export declare function startPasswordInputObserver(): void;
3
+ export declare function stopPasswordInputObserver(): void;
@@ -0,0 +1,6 @@
1
+ export declare class RageClickTracker {
2
+ private readonly clickHistory;
3
+ recordClick(fingerprint: string, now: number): boolean;
4
+ clear(): void;
5
+ private prune;
6
+ }
@@ -2,10 +2,13 @@ import { CoralogixBrowserSdkConfig } from '../../types';
2
2
  export declare function extractActionName(el: Element | HTMLElement | null): string;
3
3
  export declare function extractAriaLabel(el: Element | HTMLElement | null): string;
4
4
  export declare function extractTestId(el: Element | HTMLElement | null): string;
5
- export declare function extractResolvedName({ element, config, actionName, ariaLabel, }: {
5
+ export declare function extractResolvedName({ element, clickableElement, config, actionName, ariaLabel, }: {
6
6
  element: Element | HTMLElement | null;
7
+ clickableElement: Element | HTMLElement | null;
7
8
  config: CoralogixBrowserSdkConfig;
8
9
  actionName: string;
9
10
  ariaLabel: string;
10
11
  }): string;
11
- export declare function extractMaskedOrTextContent(element: Element | HTMLElement, config: CoralogixBrowserSdkConfig): string;
12
+ export declare function extractMaskedOrTextContent(clickableElement: Element | HTMLElement | null, config: CoralogixBrowserSdkConfig): string;
13
+ export declare function getClassName(element: Element | HTMLElement): string;
14
+ export declare function findClickableElement(element: Element | HTMLElement | null, maxDepth?: number): Element | HTMLElement | null;
@@ -0,0 +1,8 @@
1
+ export interface NumericRange {
2
+ default: number;
3
+ min: number;
4
+ max: number;
5
+ }
6
+ export declare const SCHEDULED_DELAY_MILLIS_BOUND: NumericRange;
7
+ export declare const MAX_EXPORT_BATCH_SIZE_BOUND: NumericRange;
8
+ export declare const MAX_QUEUE_SIZE_BOUND: NumericRange;
@@ -0,0 +1,2 @@
1
+ import { OtelConfig } from '../types';
2
+ export declare function resolveOtelConfig(config: OtelConfig | undefined): Required<OtelConfig>;
@@ -18,6 +18,7 @@ export interface CxRumSpanAttributes extends Attributes {
18
18
  'cx_rum.session_context.user_email'?: string;
19
19
  'cx_rum.session_context.user_id'?: string;
20
20
  'cx_rum.session_context.user_name'?: string;
21
+ 'cx_rum.session_context.account_id'?: string;
21
22
  'cx_rum.page_context.page_fragments'?: string;
22
23
  'cx_rum.page_context.page_url_blueprint'?: string;
23
24
  'cx_rum.event_context.type'?: string;
@@ -1,3 +1,4 @@
1
1
  import { SnapshotContext } from './snapshot.model';
2
2
  export declare const SNAPSHOT_MANAGER_KEY: string;
3
+ export declare const SNAPSHOT_KEY: string;
3
4
  export declare const INITIAL_SNAPSHOT_CONTEXT: SnapshotContext;
@@ -6,3 +6,8 @@ export interface SnapshotContext {
6
6
  hasRecording: boolean;
7
7
  hasScreenshot: boolean;
8
8
  }
9
+ export interface StoredSnapshotState {
10
+ snapshot: SnapshotContext;
11
+ fragments: string[];
12
+ isSnapshotSentDueToRecording: boolean;
13
+ }
@@ -1,4 +1,5 @@
1
1
  import { SnapshotContext } from './snapshot.model';
2
+ export declare function clearStoredSnapshotState(): void;
2
3
  export declare class SnapshotManager {
3
4
  private _currentSnapshot;
4
5
  private _fragmentsState;
@@ -13,4 +14,7 @@ export declare class SnapshotManager {
13
14
  set shouldTriggerSnapshotContext(value: boolean);
14
15
  updateSnapshot: (overrides: Partial<SnapshotContext>) => void;
15
16
  resetSnapshot: () => void;
17
+ private shouldPersistSnapshot;
18
+ private persistSnapshot;
19
+ private restoreSnapshot;
16
20
  }
package/src/types.d.ts CHANGED
@@ -63,6 +63,7 @@ export interface UserContextConfig {
63
63
  user_id: string;
64
64
  user_name: string;
65
65
  user_email?: string;
66
+ account_id?: string;
66
67
  user_metadata?: {
67
68
  [key: string]: any;
68
69
  };
@@ -131,6 +132,11 @@ export interface NetworkExtraConfig {
131
132
  collectReqPayload?: boolean;
132
133
  collectResPayload?: boolean;
133
134
  }
135
+ export interface OtelConfig {
136
+ maxExportBatchSize?: number;
137
+ scheduledDelayMillis?: number;
138
+ maxQueueSize?: number;
139
+ }
134
140
  export interface CoralogixBrowserSdkConfig {
135
141
  public_key?: string;
136
142
  application: string;
@@ -163,6 +169,7 @@ export interface CoralogixBrowserSdkConfig {
163
169
  supportMfe?: boolean;
164
170
  workerSupport?: boolean;
165
171
  tracesExporter?: (data: TraceExporterData) => void;
172
+ otelConfig?: OtelConfig;
166
173
  runOutsideAngularZone?: boolean;
167
174
  sdkFetchPriority?: RequestPriority;
168
175
  }
@@ -211,6 +218,8 @@ export interface NetworkRequestContext {
211
218
  fragments: string;
212
219
  host: string;
213
220
  schema: string;
221
+ subdomain?: string;
222
+ domain?: string;
214
223
  status_text: string;
215
224
  response_content_length: string;
216
225
  duration: number;
@@ -239,6 +248,8 @@ export interface InteractionContext {
239
248
  element_width?: number;
240
249
  element_height?: number;
241
250
  element_fingerprint?: string;
251
+ is_dead_click?: boolean;
252
+ is_rage_click?: boolean;
242
253
  }
243
254
  export interface LayoutContext {
244
255
  viewport_width: number;
@@ -285,6 +296,7 @@ export interface UserMetadata {
285
296
  user_id: string;
286
297
  user_name?: string;
287
298
  user_email?: string;
299
+ account_id?: string;
288
300
  user_metadata?: {
289
301
  [key: string]: any;
290
302
  };
@@ -335,7 +347,15 @@ export interface PageContext {
335
347
  page_url: string;
336
348
  page_url_blueprint: string;
337
349
  page_fragments: string;
350
+ schema?: string;
351
+ subdomain?: string;
352
+ domain?: string;
353
+ host?: string;
338
354
  referrer: string;
355
+ referrer_schema?: string;
356
+ referrer_subdomain?: string;
357
+ referrer_domain?: string;
358
+ referrer_host?: string;
339
359
  }
340
360
  export interface CxRumEvent extends EventTypeContext {
341
361
  browser_sdk: {
@@ -416,7 +436,7 @@ export interface GenericLabelProvider {
416
436
  }
417
437
  export type LabelProvider = UrlBasedLabelProvider | GenericLabelProvider;
418
438
  export type InputType = 'button' | 'checkbox' | 'color' | 'date' | 'datetime-local' | 'email' | 'file' | 'hidden' | 'image' | 'month' | 'number' | 'password' | 'radio' | 'range' | 'reset' | 'search' | 'submit' | 'tel' | 'text' | 'time' | 'url' | 'week';
419
- export interface EditableCxRumEvent extends Omit<CxRumEvent, 'session_context' | 'browser_sdk' | 'timestamp'> {
439
+ export interface EditableCxRumEvent extends Omit<CxRumEvent, 'session_context' | 'browser_sdk' | 'timestamp' | 'isNavigationEvent' | 'isSnapshotEvent' | 'view_number'> {
420
440
  session_context: Pick<SessionContext, keyof UserMetadata>;
421
441
  }
422
442
  interface BrowserCompatibility {
@@ -6,6 +6,14 @@ export declare function getInstrumentationConfig<T>(value: T | boolean | undefin
6
6
  export declare const hrTimeToMilliseconds: ([seconds, nanoseconds]: [number, number]) => number;
7
7
  export declare const isNetworkError: (status?: number) => boolean;
8
8
  export declare const getUrlFragments: (url: string) => string;
9
+ type UrlParts = {
10
+ schema: string;
11
+ subdomain: string;
12
+ domain: string;
13
+ host: string;
14
+ };
15
+ export declare const getUrlParts: (url: string) => UrlParts | undefined;
16
+ export declare const getCachedUrlParts: (cacheKey: string, url: string) => UrlParts | undefined;
9
17
  export declare function parseUserAgent(userAgent: string): UserAgentData;
10
18
  export declare function calculateTotalBlockingTime(list: PerformanceEntry[]): number;
11
19
  export declare function generateWebVitalUniqueID(): string;
@@ -23,3 +31,4 @@ export declare function applyUrlBluePrinters({ url, blueprinters, }: {
23
31
  export declare function resolvePageContext(url: string): PageContext;
24
32
  export declare function deepClone<T>(obj: T): T;
25
33
  export declare function partition<T>(array: T[], predicate: (value: T) => boolean): [T[], T[]];
34
+ export {};
package/src/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const SDK_VERSION = "3.16.0";
1
+ export declare const SDK_VERSION = "3.18.0";