@coralogix/browser 3.9.0 → 3.15.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,60 @@
1
+ ## 3.15.1 (2026-06-23)
2
+
3
+ ### 🩹 Fixes
4
+
5
+ - Improve user-interaction tracking accuracy
6
+
7
+ ## 3.15.0 (2026-06-22)
8
+
9
+ ### 🚀 Features
10
+
11
+ - Improved user-interaction tracking: smarter element fingerprinting and more accurate screenshot capture on clicks and navigation.
12
+
13
+
14
+ ## 3.14.0 (2026-06-14)
15
+
16
+ ### 🚀 Features
17
+
18
+ - Flush telemetry data on tab close with fetch keepalive support
19
+
20
+ ## 3.13.0 (2026-06-11)
21
+
22
+ ### 🚀 Features
23
+
24
+ - Improve user interaction with click and scroll coordinates, and viewport context
25
+
26
+
27
+ ## 3.12.0 (2026-06-09)
28
+
29
+ ### 🚀 Features
30
+
31
+ - Improve: capture screenshot on each unique view navigation
32
+
33
+ ## 3.11.1 (2026-06-08)
34
+
35
+ ### 🩹 Fixes
36
+
37
+ - SVG element support in session recording
38
+ - session recording after refreshing the page
39
+
40
+ ## 3.11.0 (2026-06-04)
41
+
42
+ ### 🚀 Features
43
+
44
+ - Add view number tracking for product analytics support
45
+
46
+ ## 3.10.1 (2026-06-02)
47
+
48
+ ### 🩹 Fixes
49
+
50
+ - Improve beforeSend to correctly reflect modifications in OpenTelemetry span attributes
51
+
52
+ ## 3.10.0 (2026-05-25)
53
+
54
+ ### 🚀 Features
55
+
56
+ - Improve user interaction instrumentation with richer element metadata
57
+
1
58
  ## 3.9.0 (2026-05-19)
2
59
 
3
60
  ### 🚀 Features
package/README.md CHANGED
@@ -559,6 +559,28 @@ Examples of masked elements:
559
559
 
560
560
  ```
561
561
 
562
+ ### Action Attributes
563
+
564
+ The SDK uses various strategies to name click actions. For more control, define a `data-cx-action-name` attribute on clickable elements (or any of their parents) to set the action name.
565
+
566
+ ```html
567
+ <button data-cx-action-name="add-to-cart">
568
+ Add to Cart
569
+ </button>
570
+
571
+ <form data-cx-action-name="checkout-form">
572
+ <input type="text" placeholder="Card number" />
573
+ <button type="submit">Complete Purchase</button>
574
+ </form>
575
+
576
+ <nav data-cx-action-name="main-navigation">
577
+ <a href="/products">Products</a>
578
+ <a href="/pricing">Pricing</a>
579
+ </nav>
580
+ ```
581
+
582
+ > **Note:** The `data-cx-action-name` attribute is never masked, even when the element has a mask class applied. This ensures your custom action names are always captured for tracking purposes.
583
+
562
584
  ### Label Providers
563
585
 
564
586
  Provide labels based on url or event
package/index.esm2.js CHANGED
@@ -227,6 +227,7 @@ var SESSION_EXPIRATION_TIME = MILLISECONDS_PER_HOUR;
227
227
  var SESSION_MANAGER_KEY = 'rumSessionManager';
228
228
  var SESSION_RECORDER_KEY = 'rumSessionRecorder';
229
229
  var SESSION_RECORDER_SEGMENTS_MAP = 'rumSessionRecorderSegmentsMap';
230
+ var VIEW_NUMBER_KEY = 'rum_view_number';
230
231
 
231
232
  var SNAPSHOT_MANAGER_KEY = 'rumSnapshotManager';
232
233
  var INITIAL_SNAPSHOT_CONTEXT = {
@@ -264,6 +265,8 @@ function getCxGlobal() {
264
265
  }
265
266
  var CxGlobal = getCxGlobal();
266
267
 
268
+ var CLICK_SCREENSHOT_MANAGER_KEY = 'rumClickScreenshotManager';
269
+
267
270
  function getSnapshotManager() {
268
271
  return CxGlobal[SNAPSHOT_MANAGER_KEY];
269
272
  }
@@ -273,12 +276,28 @@ function getSessionManager() {
273
276
  function getSessionRecorder() {
274
277
  return CxGlobal[SESSION_RECORDER_KEY];
275
278
  }
279
+ function getClickScreenshotManager() {
280
+ return CxGlobal[CLICK_SCREENSHOT_MANAGER_KEY];
281
+ }
276
282
  function getSdkConfig() {
277
283
  return CxGlobal[SDK_CONFIG_KEY];
278
284
  }
279
285
  function getUserAgentData() {
280
286
  return CxGlobal[USER_AGENT_KEY];
281
287
  }
288
+ var TRACER_PROVIDER_KEY = '__cx_tracer_provider__';
289
+ function setTracerProvider(provider) {
290
+ CxGlobal[TRACER_PROVIDER_KEY] = provider;
291
+ }
292
+ function getTracerProvider() {
293
+ return CxGlobal[TRACER_PROVIDER_KEY];
294
+ }
295
+ function flush() {
296
+ var tracerProvider = getTracerProvider();
297
+ if (!tracerProvider)
298
+ return;
299
+ tracerProvider.forceFlush();
300
+ }
282
301
 
283
302
  var GLOBAL_SPAN_KEY = '__globalSpan__';
284
303
  var GLOBAL_SPAN_MAP_KEY = '__globalSpanMap__';
@@ -2122,8 +2141,55 @@ function addEventListeners(eventTarget, eventNames, listener, _a) {
2122
2141
  };
2123
2142
  }
2124
2143
 
2144
+ var CX_ACTION_NAME_ATTRIBUTE = 'data-cx-action-name';
2145
+ var DATA_TEST_ATTRIBUTE = 'data-test';
2146
+ var DATA_TESTID_ATTRIBUTE = 'data-testid';
2147
+ var DATA_TEST_ID_ATTRIBUTE = 'data-test-id';
2148
+
2125
2149
  var PARENT_SEARCH_DEPTH = 5;
2126
2150
  var CLICKABLE_ELEMENTS = ['BUTTON', 'LABEL', 'A', 'INPUT', 'OPTION'];
2151
+ function getAttributeFromAncestors(element, attr, depth) {
2152
+ if (depth === void 0) { depth = PARENT_SEARCH_DEPTH; }
2153
+ if (!element || depth <= 0)
2154
+ return '';
2155
+ var value = element.getAttribute(attr);
2156
+ if (value)
2157
+ return value;
2158
+ return getAttributeFromAncestors(element.parentElement, attr, depth - 1);
2159
+ }
2160
+ function extractActionName(el) {
2161
+ return getAttributeFromAncestors(el, CX_ACTION_NAME_ATTRIBUTE);
2162
+ }
2163
+ function extractAriaLabel(el) {
2164
+ return getAttributeFromAncestors(el, ARIA_LABEL_ATTRIBUTE);
2165
+ }
2166
+ function extractTestId(el) {
2167
+ return (el === null || el === void 0 ? void 0 : el.getAttribute(DATA_TEST_ATTRIBUTE)) || '';
2168
+ }
2169
+ function extractResolvedName(_a) {
2170
+ var element = _a.element, config = _a.config, actionName = _a.actionName, ariaLabel = _a.ariaLabel;
2171
+ if (!element)
2172
+ return '';
2173
+ if (actionName)
2174
+ return actionName;
2175
+ if (isElementMasked(element, config))
2176
+ return MASKED_TEXT;
2177
+ return ariaLabel || getPlaceholder(element) || getInnerText(element) || '';
2178
+ }
2179
+ function getPlaceholder(element) {
2180
+ if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
2181
+ return element.placeholder || '';
2182
+ }
2183
+ return '';
2184
+ }
2185
+ function getInnerText(element) {
2186
+ var clickableElement = findClickableElement(element, PARENT_SEARCH_DEPTH);
2187
+ if (!clickableElement)
2188
+ return '';
2189
+ return clickableElement instanceof HTMLElement
2190
+ ? clickableElement.innerText || ''
2191
+ : '';
2192
+ }
2127
2193
  function extractMaskedOrTextContent(element, config) {
2128
2194
  if (!element)
2129
2195
  return '';
@@ -2132,14 +2198,6 @@ function extractMaskedOrTextContent(element, config) {
2132
2198
  return '';
2133
2199
  return getMaskedOrTextualContent(clickableElement, config);
2134
2200
  }
2135
- function findClickableElement(element, maxDepth) {
2136
- if (!element || maxDepth <= 0) {
2137
- return null;
2138
- }
2139
- if (CLICKABLE_ELEMENTS.includes(element.nodeName))
2140
- return element;
2141
- return findClickableElement(element.parentElement, maxDepth - 1);
2142
- }
2143
2201
  function getMaskedOrTextualContent(element, config) {
2144
2202
  if (shouldMaskElement(element, config.maskInputTypes, config.maskClass) ||
2145
2203
  isParentMasked(element, config.maskClass, PARENT_SEARCH_DEPTH)) {
@@ -2151,22 +2209,15 @@ function getMaskedOrTextualContent(element, config) {
2151
2209
  }
2152
2210
  return getTextualContent(element);
2153
2211
  }
2154
- function isParentMasked(element, maskClass, maxDepth) {
2155
- if (maxDepth === void 0) { maxDepth = PARENT_SEARCH_DEPTH; }
2156
- if (!element || maxDepth <= 0) {
2157
- return false;
2158
- }
2159
- if (isMaskedByClass(element.className, maskClass)) {
2160
- return true;
2212
+ function getTextualContent(element) {
2213
+ if (element instanceof HTMLInputElement) {
2214
+ return element.value || '';
2161
2215
  }
2162
- return isParentMasked(element.parentElement, maskClass, maxDepth - 1);
2216
+ return 'innerText' in element ? element.innerText : '';
2163
2217
  }
2164
- function findMaskedChildren(element, config) {
2165
- if (!element.children)
2166
- return null;
2167
- return Array.from(element.children).find(function (child) {
2168
- return shouldMaskElement(child, config.maskInputTypes, config.maskClass);
2169
- });
2218
+ function isElementMasked(element, config) {
2219
+ return (shouldMaskElement(element, config.maskInputTypes, config.maskClass) ||
2220
+ isParentMasked(element, config.maskClass, PARENT_SEARCH_DEPTH));
2170
2221
  }
2171
2222
  function shouldMaskElement(element, maskInputTypes, maskClass) {
2172
2223
  if (!element)
@@ -2190,11 +2241,201 @@ function isMaskedByClass(className, maskClass) {
2190
2241
  }
2191
2242
  return className.includes(maskClass);
2192
2243
  }
2193
- function getTextualContent(element) {
2194
- if (element instanceof HTMLInputElement) {
2195
- return element.value || '';
2244
+ function isParentMasked(element, maskClass, maxDepth) {
2245
+ if (maxDepth === void 0) { maxDepth = PARENT_SEARCH_DEPTH; }
2246
+ if (!element || maxDepth <= 0) {
2247
+ return false;
2196
2248
  }
2197
- return 'innerText' in element ? element.innerText : '';
2249
+ if (isMaskedByClass(element.className, maskClass)) {
2250
+ return true;
2251
+ }
2252
+ return isParentMasked(element.parentElement, maskClass, maxDepth - 1);
2253
+ }
2254
+ function findMaskedChildren(element, config) {
2255
+ if (!element.children)
2256
+ return null;
2257
+ return Array.from(element.children).find(function (child) {
2258
+ return shouldMaskElement(child, config.maskInputTypes, config.maskClass);
2259
+ });
2260
+ }
2261
+ function findClickableElement(element, maxDepth) {
2262
+ if (!element || maxDepth <= 0) {
2263
+ return null;
2264
+ }
2265
+ if (CLICKABLE_ELEMENTS.includes(element.nodeName))
2266
+ return element;
2267
+ return findClickableElement(element.parentElement, maxDepth - 1);
2268
+ }
2269
+
2270
+ var SHADOW_DOM_MARKER = '::shadow ';
2271
+ var STABLE_ATTRIBUTES = [
2272
+ CX_ACTION_NAME_ATTRIBUTE,
2273
+ DATA_TEST_ATTRIBUTE,
2274
+ DATA_TESTID_ATTRIBUTE,
2275
+ DATA_TEST_ID_ATTRIBUTE,
2276
+ ];
2277
+ var ESCAPE_FREE_CLASS_NAME = /^[a-zA-Z_-][a-zA-Z0-9_-]*$/;
2278
+ var GENERATED_VALUE_PATTERNS = [
2279
+ /^\d/,
2280
+ /\d{3,}/,
2281
+ /__[a-zA-Z0-9]/,
2282
+ /(?:[a-z]\d|\d[a-z]){3,}/i,
2283
+ ];
2284
+ function getElementFingerprint(target) {
2285
+ try {
2286
+ if (!target.isConnected) {
2287
+ return undefined;
2288
+ }
2289
+ var selectors = [];
2290
+ var element = target;
2291
+ while (element) {
2292
+ var root = element.getRootNode();
2293
+ var selector = getSubtreeSelector(element, root);
2294
+ if (!selector) {
2295
+ return undefined;
2296
+ }
2297
+ selectors.unshift(selector);
2298
+ element = isShadowRoot(root) ? root.host : null;
2299
+ }
2300
+ return selectors.join(SHADOW_DOM_MARKER);
2301
+ }
2302
+ catch (_a) {
2303
+ return undefined;
2304
+ }
2305
+ }
2306
+ function isShadowRoot(node) {
2307
+ return (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE && !!node.host);
2308
+ }
2309
+ function getSubtreeSelector(target, root) {
2310
+ var selector = '';
2311
+ for (var element = target; element && element.nodeName !== 'HTML'; element = element.parentElement) {
2312
+ var unique = getUniqueSegment(element, root, selector);
2313
+ if (unique) {
2314
+ return joinWithChild(unique, selector);
2315
+ }
2316
+ selector = joinWithChild(getLevelSegment(element, selector), selector);
2317
+ }
2318
+ return selector;
2319
+ }
2320
+ function getUniqueSegment(element, root, childSelector) {
2321
+ var e_1, _a;
2322
+ try {
2323
+ for (var _b = __values$1([getAttributeSegment(element), getIdSegment(element)]), _c = _b.next(); !_c.done; _c = _b.next()) {
2324
+ var segment = _c.value;
2325
+ if (segment && isUnique(root, joinWithChild(segment, childSelector))) {
2326
+ return segment;
2327
+ }
2328
+ }
2329
+ }
2330
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
2331
+ finally {
2332
+ try {
2333
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
2334
+ }
2335
+ finally { if (e_1) throw e_1.error; }
2336
+ }
2337
+ return undefined;
2338
+ }
2339
+ function getLevelSegment(element, childSelector) {
2340
+ var e_2, _a;
2341
+ var candidates = [
2342
+ getAttributeSegment(element),
2343
+ getStableClassSegment(element),
2344
+ element.tagName,
2345
+ ];
2346
+ try {
2347
+ for (var candidates_1 = __values$1(candidates), candidates_1_1 = candidates_1.next(); !candidates_1_1.done; candidates_1_1 = candidates_1.next()) {
2348
+ var segment = candidates_1_1.value;
2349
+ if (segment && isUniqueAmongSiblings(element, segment, childSelector)) {
2350
+ return segment;
2351
+ }
2352
+ }
2353
+ }
2354
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
2355
+ finally {
2356
+ try {
2357
+ if (candidates_1_1 && !candidates_1_1.done && (_a = candidates_1.return)) _a.call(candidates_1);
2358
+ }
2359
+ finally { if (e_2) throw e_2.error; }
2360
+ }
2361
+ return "".concat(element.tagName, ":nth-of-type(").concat(nthOfTypeIndex(element), ")");
2362
+ }
2363
+ function getAttributeSegment(element) {
2364
+ var e_3, _a;
2365
+ try {
2366
+ for (var STABLE_ATTRIBUTES_1 = __values$1(STABLE_ATTRIBUTES), STABLE_ATTRIBUTES_1_1 = STABLE_ATTRIBUTES_1.next(); !STABLE_ATTRIBUTES_1_1.done; STABLE_ATTRIBUTES_1_1 = STABLE_ATTRIBUTES_1.next()) {
2367
+ var attribute = STABLE_ATTRIBUTES_1_1.value;
2368
+ var value = element.getAttribute(attribute);
2369
+ if (value) {
2370
+ return "".concat(element.tagName, "[").concat(attribute, "=\"").concat(CSS.escape(value), "\"]");
2371
+ }
2372
+ }
2373
+ }
2374
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
2375
+ finally {
2376
+ try {
2377
+ if (STABLE_ATTRIBUTES_1_1 && !STABLE_ATTRIBUTES_1_1.done && (_a = STABLE_ATTRIBUTES_1.return)) _a.call(STABLE_ATTRIBUTES_1);
2378
+ }
2379
+ finally { if (e_3) throw e_3.error; }
2380
+ }
2381
+ return undefined;
2382
+ }
2383
+ function getIdSegment(element) {
2384
+ return element.id && !isUnstableValue(element.id)
2385
+ ? "#".concat(CSS.escape(element.id))
2386
+ : undefined;
2387
+ }
2388
+ function getStableClassSegment(element) {
2389
+ var _a, _b;
2390
+ if (element.tagName === 'BODY') {
2391
+ return undefined;
2392
+ }
2393
+ var classNames = (_b = (_a = element.getAttribute('class')) === null || _a === void 0 ? void 0 : _a.split(/\s+/)) !== null && _b !== void 0 ? _b : [];
2394
+ var stable = classNames.find(function (name) { return name && !isUnstableValue(name) && ESCAPE_FREE_CLASS_NAME.test(name); });
2395
+ return stable ? "".concat(element.tagName, ".").concat(stable) : undefined;
2396
+ }
2397
+ function isUnstableValue(value) {
2398
+ return GENERATED_VALUE_PATTERNS.some(function (pattern) { return pattern.test(value); });
2399
+ }
2400
+ function isUnique(root, selector) {
2401
+ return root.querySelectorAll(selector).length === 1;
2402
+ }
2403
+ function isUniqueAmongSiblings(element, segment, childSelector) {
2404
+ var e_4, _a;
2405
+ var _b, _c;
2406
+ var siblings = (_c = (_b = element.parentElement) === null || _b === void 0 ? void 0 : _b.children) !== null && _c !== void 0 ? _c : [];
2407
+ try {
2408
+ for (var siblings_1 = __values$1(siblings), siblings_1_1 = siblings_1.next(); !siblings_1_1.done; siblings_1_1 = siblings_1.next()) {
2409
+ var sibling = siblings_1_1.value;
2410
+ if (sibling === element) {
2411
+ continue;
2412
+ }
2413
+ if (sibling.matches(segment) &&
2414
+ (!childSelector || sibling.querySelector(childSelector) !== null)) {
2415
+ return false;
2416
+ }
2417
+ }
2418
+ }
2419
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
2420
+ finally {
2421
+ try {
2422
+ if (siblings_1_1 && !siblings_1_1.done && (_a = siblings_1.return)) _a.call(siblings_1);
2423
+ }
2424
+ finally { if (e_4) throw e_4.error; }
2425
+ }
2426
+ return true;
2427
+ }
2428
+ function nthOfTypeIndex(element) {
2429
+ var index = 1;
2430
+ for (var s = element.previousElementSibling; s; s = s.previousElementSibling) {
2431
+ if (s.tagName === element.tagName) {
2432
+ index += 1;
2433
+ }
2434
+ }
2435
+ return index;
2436
+ }
2437
+ function joinWithChild(parent, child) {
2438
+ return child ? "".concat(parent, ">").concat(child) : parent;
2198
2439
  }
2199
2440
 
2200
2441
  var _a$3;
@@ -2215,6 +2456,7 @@ var CoralogixUserInteractionInstrumentation = (function (_super) {
2215
2456
  var _this = this;
2216
2457
  var _a;
2217
2458
  this.handler = function (e) {
2459
+ var _a;
2218
2460
  var span;
2219
2461
  if (shouldAttachSpanToGlobalSpan(CoralogixEventType.USER_INTERACTION)) {
2220
2462
  span = attachChildSpanToGlobalSpan(CoralogixEventType.USER_INTERACTION);
@@ -2225,10 +2467,34 @@ var CoralogixUserInteractionInstrumentation = (function (_super) {
2225
2467
  var eventTarget = e.target;
2226
2468
  var config = getSdkConfig();
2227
2469
  var id = eventTarget.id, type = eventTarget.type, className = eventTarget.className, nodeName = eventTarget.nodeName;
2228
- var elementText = extractMaskedOrTextContent(eventTarget, config);
2470
+ var clickKey = generateUUID();
2229
2471
  span.setAttribute(CoralogixAttributes.EVENT_TYPE, CoralogixEventType.USER_INTERACTION);
2230
2472
  span.setAttribute(CoralogixAttributes.INTERACTION_EVENT_NAME, e.type);
2473
+ span.setAttribute(CoralogixAttributes.CX_ID, clickKey);
2474
+ if (e instanceof MouseEvent) {
2475
+ span.setAttribute(CoralogixAttributes.CLICK_X, e.clientX);
2476
+ span.setAttribute(CoralogixAttributes.CLICK_Y, e.clientY);
2477
+ span.setAttribute(CoralogixAttributes.ELEMENT_RELATIVE_X, e.offsetX);
2478
+ span.setAttribute(CoralogixAttributes.ELEMENT_RELATIVE_Y, e.offsetY);
2479
+ }
2231
2480
  if (eventTarget && eventTarget instanceof HTMLElement) {
2481
+ var elementText = extractMaskedOrTextContent(eventTarget, config);
2482
+ var cxActionName = extractActionName(eventTarget);
2483
+ var ariaLabel = extractAriaLabel(eventTarget);
2484
+ var testId = extractTestId(eventTarget);
2485
+ var resolvedName = extractResolvedName({
2486
+ element: eventTarget,
2487
+ config: config,
2488
+ actionName: cxActionName,
2489
+ ariaLabel: ariaLabel,
2490
+ });
2491
+ var _b = eventTarget.getBoundingClientRect(), width = _b.width, height = _b.height;
2492
+ span.setAttribute(CoralogixAttributes.ELEMENT_WIDTH, width);
2493
+ span.setAttribute(CoralogixAttributes.ELEMENT_HEIGHT, height);
2494
+ var fingerprint = getElementFingerprint(eventTarget);
2495
+ if (fingerprint) {
2496
+ span.setAttribute(CoralogixAttributes.ELEMENT_FINGERPRINT, fingerprint);
2497
+ }
2232
2498
  [
2233
2499
  [CoralogixAttributes.ELEMENT_ID, id],
2234
2500
  [CoralogixAttributes.ELEMENT_CLASSES, className],
@@ -2238,12 +2504,20 @@ var CoralogixUserInteractionInstrumentation = (function (_super) {
2238
2504
  elementText === null || elementText === void 0 ? void 0 : elementText.slice(0, MAX_INTERACTION_ELEMENT_SIZE),
2239
2505
  ],
2240
2506
  [CoralogixAttributes.TARGET_ELEMENT, nodeName],
2507
+ [
2508
+ CoralogixAttributes.RESOLVED_NAME,
2509
+ resolvedName === null || resolvedName === void 0 ? void 0 : resolvedName.slice(0, MAX_INTERACTION_ELEMENT_SIZE),
2510
+ ],
2511
+ [CoralogixAttributes.CX_ACTION_NAME, cxActionName],
2512
+ [CoralogixAttributes.ARIA_LABEL, ariaLabel],
2513
+ [CoralogixAttributes.TEST_ID, testId],
2241
2514
  ].forEach(function (_a) {
2242
2515
  var _b = __read$1(_a, 2), key = _b[0], value = _b[1];
2243
2516
  span.setAttribute(key, value);
2244
2517
  });
2245
2518
  }
2246
2519
  span.end();
2520
+ (_a = getClickScreenshotManager()) === null || _a === void 0 ? void 0 : _a.handleClick();
2247
2521
  };
2248
2522
  var eventsMap = __assign(__assign({}, DEFAULT_INSTRUMENTED_EVENTS), (_a = this._config) === null || _a === void 0 ? void 0 : _a['events']);
2249
2523
  var eventNames = Object.entries(eventsMap)
@@ -2541,13 +2815,20 @@ var CoralogixDOMInstrumentation = (function (_super) {
2541
2815
  var _this = _super.call(this, DOM_INSTRUMENTATION_NAME, DOM_INSTRUMENTATION_VERSION, config) || this;
2542
2816
  _this.visibilityChangeHandler = function () {
2543
2817
  if (document.hidden) {
2544
- var domSpan = _this.tracer.startSpan(DOM_INSTRUMENTATION_NAME);
2545
- domSpan.setAttribute(CoralogixAttributes.EVENT_TYPE, CoralogixEventType.DOM);
2546
- domSpan.end();
2818
+ _this.createDOMSpan();
2819
+ flush();
2547
2820
  }
2548
2821
  };
2549
2822
  return _this;
2550
2823
  }
2824
+ CoralogixDOMInstrumentation.prototype.createDOMSpan = function () {
2825
+ var domSpan = this.tracer.startSpan(DOM_INSTRUMENTATION_NAME);
2826
+ domSpan.setAttribute(CoralogixAttributes.EVENT_TYPE, CoralogixEventType.DOM);
2827
+ domSpan[CoralogixAttributes.DOM_CONTEXT] = {
2828
+ visibility_state: document.visibilityState,
2829
+ };
2830
+ domSpan.end();
2831
+ };
2551
2832
  CoralogixDOMInstrumentation.prototype.registerToDOMEvents = function () {
2552
2833
  var originalAddEventListener = getZoneJsOriginalDom(document, 'addEventListener');
2553
2834
  originalAddEventListener.call(document, 'visibilitychange', this.visibilityChangeHandler);
@@ -2656,6 +2937,8 @@ var NETWORK_URL_LABEL_PROVIDERS_KEY = 'NETWORK_URL_LABEL_PROVIDERS';
2656
2937
  var RUM_INTERNAL_DATA_KEY = 'rumInternalData';
2657
2938
  var MASKED_TEXT = '***';
2658
2939
  var MASK_CLASS_DEFAULT = 'cx-mask';
2940
+ var CX_PREFIX = 'cx';
2941
+ var ARIA_LABEL_ATTRIBUTE = 'aria-label';
2659
2942
  var MASK_INPUT_TYPES_DEFAULT = [
2660
2943
  'password',
2661
2944
  'email',
@@ -2796,11 +3079,24 @@ var CoralogixAttributes = {
2796
3079
  ELEMENT_CLASSES: 'element_classes',
2797
3080
  TARGET_ELEMENT: 'target_element',
2798
3081
  TARGET_ELEMENT_TYPE: 'target_element_type',
3082
+ CX_ACTION_NAME: 'cx_action_name',
3083
+ CX_ID: 'cx_id',
3084
+ ARIA_LABEL: 'element_aria_label',
3085
+ TEST_ID: 'element_test_id',
3086
+ RESOLVED_NAME: 'element_resolved_name',
3087
+ CLICK_X: 'click_x',
3088
+ CLICK_Y: 'click_y',
3089
+ ELEMENT_RELATIVE_X: 'element_relative_x',
3090
+ ELEMENT_RELATIVE_Y: 'element_relative_y',
3091
+ ELEMENT_WIDTH: 'element_width',
3092
+ ELEMENT_HEIGHT: 'element_height',
3093
+ ELEMENT_FINGERPRINT: 'element_fingerprint',
2799
3094
  TIMESTAMP: 'timestamp',
2800
3095
  INTERNAL: 'internal',
2801
3096
  PAGE_CONTEXT: 'page_context',
2802
3097
  IS_NAVIGATION_EVENT: 'is_navigation_event',
2803
3098
  SCREENSHOT_CONTEXT: 'screenshot_context',
3099
+ DOM_CONTEXT: 'dom_context',
2804
3100
  };
2805
3101
  var CoralogixDomainsApiUrlMap = {
2806
3102
  EU1: 'https://ingress.eu1.rum-ingress-coralogix.com',
@@ -3456,6 +3752,8 @@ var DEFAULT_MS_RECORD_TIME = 10000;
3456
3752
  _a$1),
3457
3753
  });
3458
3754
 
3755
+ var KEEPALIVE_MAX_BYTES = 65536;
3756
+ var encoder = new TextEncoder();
3459
3757
  var Request = (function () {
3460
3758
  function Request(requestConfig) {
3461
3759
  this.requestConfig = requestConfig;
@@ -3486,14 +3784,19 @@ var Request = (function () {
3486
3784
  this.resolvedHeaders = headers;
3487
3785
  };
3488
3786
  Request.prototype.send = function (body) {
3787
+ var useKeepalive = document.hidden && this.isWithinKeepaliveQuota(body);
3489
3788
  return fetch(this.resolvedUrl, {
3490
3789
  method: 'POST',
3491
3790
  headers: this.resolvedHeaders,
3492
3791
  body: body,
3792
+ keepalive: useKeepalive,
3493
3793
  }).catch(function (e) {
3494
3794
  return e;
3495
3795
  });
3496
3796
  };
3797
+ Request.prototype.isWithinKeepaliveQuota = function (body) {
3798
+ return typeof body === 'string' && encoder.encode(body).length <= KEEPALIVE_MAX_BYTES;
3799
+ };
3497
3800
  return Request;
3498
3801
  }());
3499
3802
 
@@ -3969,7 +4272,7 @@ function isInstrumentationCompatible(confKey) {
3969
4272
  var SessionManager = (function (_super) {
3970
4273
  __extends(SessionManager, _super);
3971
4274
  function SessionManager(recordConfig) {
3972
- var _a;
4275
+ var _a, _b;
3973
4276
  var _this = _super.call(this, {
3974
4277
  timeoutDelay: SESSION_IDLE_TIME,
3975
4278
  onIdle: function () { return _this.clearSessionWhenIdle(); },
@@ -3979,6 +4282,7 @@ var SessionManager = (function (_super) {
3979
4282
  _this._sessionHasError = false;
3980
4283
  _this._cachedLogsSent = false;
3981
4284
  _this._currentPageTimestamp = getNowTime();
4285
+ _this._viewNumber = 0;
3982
4286
  _this.debugMode = !!((_a = getSdkConfig()) === null || _a === void 0 ? void 0 : _a.debug);
3983
4287
  _this.getPrevSession = function () {
3984
4288
  var _a;
@@ -4022,6 +4326,9 @@ var SessionManager = (function (_super) {
4022
4326
  return _this.activeSession;
4023
4327
  };
4024
4328
  _this.initializeSession(recordConfig);
4329
+ if ((_b = _this._sessionConfig) === null || _b === void 0 ? void 0 : _b.keepSessionAfterReload) {
4330
+ _this.loadViewNumber();
4331
+ }
4025
4332
  return _this;
4026
4333
  }
4027
4334
  Object.defineProperty(SessionManager.prototype, "currentPageTimestamp", {
@@ -4100,6 +4407,13 @@ var SessionManager = (function (_super) {
4100
4407
  enumerable: false,
4101
4408
  configurable: true
4102
4409
  });
4410
+ Object.defineProperty(SessionManager.prototype, "viewNumber", {
4411
+ get: function () {
4412
+ return this._viewNumber;
4413
+ },
4414
+ enumerable: false,
4415
+ configurable: true
4416
+ });
4103
4417
  SessionManager.prototype.updateCurrentPage = function (fragment) {
4104
4418
  if (this.isIdleActive) {
4105
4419
  this._currentPageFragment = undefined;
@@ -4108,6 +4422,26 @@ var SessionManager = (function (_super) {
4108
4422
  this._currentPageFragment = fragment;
4109
4423
  this._currentPageTimestamp = getNowTime();
4110
4424
  };
4425
+ SessionManager.prototype.incrementViewNumber = function () {
4426
+ this._viewNumber++;
4427
+ this.persistViewNumber();
4428
+ };
4429
+ SessionManager.prototype.persistViewNumber = function () {
4430
+ var _a, _b;
4431
+ if ((_a = this._sessionConfig) === null || _a === void 0 ? void 0 : _a.keepSessionAfterReload) {
4432
+ (_b = CxGlobal.sessionStorage) === null || _b === void 0 ? void 0 : _b.setItem(VIEW_NUMBER_KEY, String(this._viewNumber));
4433
+ }
4434
+ };
4435
+ SessionManager.prototype.loadViewNumber = function () {
4436
+ var _a;
4437
+ var storedViewNumber = (_a = CxGlobal.sessionStorage) === null || _a === void 0 ? void 0 : _a.getItem(VIEW_NUMBER_KEY);
4438
+ this._viewNumber = Number(storedViewNumber) || 0;
4439
+ };
4440
+ SessionManager.prototype.resetViewNumber = function () {
4441
+ var _a;
4442
+ this._viewNumber = 0;
4443
+ (_a = CxGlobal.sessionStorage) === null || _a === void 0 ? void 0 : _a.removeItem(VIEW_NUMBER_KEY);
4444
+ };
4111
4445
  SessionManager.prototype.getSessionKey = function () {
4112
4446
  return SESSION_KEY;
4113
4447
  };
@@ -4162,7 +4496,7 @@ var SessionManager = (function (_super) {
4162
4496
  (_a = CxGlobal.sessionStorage) === null || _a === void 0 ? void 0 : _a.removeItem(PREV_SESSION_KEY);
4163
4497
  };
4164
4498
  SessionManager.prototype.clearSession = function () {
4165
- var _a, _b, _c, _d, _e, _f;
4499
+ var _a, _b, _c, _d, _e, _f, _g;
4166
4500
  if (this.debugMode) {
4167
4501
  console.debug('Coralogix Browser SDK - Session expired, clearing session');
4168
4502
  }
@@ -4170,9 +4504,11 @@ var SessionManager = (function (_super) {
4170
4504
  this.clearGlobalSpans();
4171
4505
  this.clearSessionWithErrorMode();
4172
4506
  (_d = getSnapshotManager()) === null || _d === void 0 ? void 0 : _d.resetSnapshot();
4507
+ (_e = getClickScreenshotManager()) === null || _e === void 0 ? void 0 : _e.reset();
4173
4508
  this._currentPageFragment = undefined;
4174
- (_e = this.sessionRecorder) === null || _e === void 0 ? void 0 : _e.stopRecording();
4175
- (_f = CxGlobal.sessionStorage) === null || _f === void 0 ? void 0 : _f.removeItem(SESSION_KEY);
4509
+ this.resetViewNumber();
4510
+ (_f = this.sessionRecorder) === null || _f === void 0 ? void 0 : _f.stopRecording();
4511
+ (_g = CxGlobal.sessionStorage) === null || _g === void 0 ? void 0 : _g.removeItem(SESSION_KEY);
4176
4512
  };
4177
4513
  SessionManager.prototype.clearGlobalSpans = function () {
4178
4514
  var _a;
@@ -4185,13 +4521,8 @@ var SessionManager = (function (_super) {
4185
4521
  this.cachedLogsSent = false;
4186
4522
  };
4187
4523
  SessionManager.prototype.handleRefreshedSessions = function () {
4188
- var _a, _b;
4189
4524
  this.activeSession = this.getSession();
4190
- var recordingSegmentMapFromStorage = JSON.parse(((_a = CxGlobal.sessionStorage) === null || _a === void 0 ? void 0 : _a.getItem(SESSION_RECORDER_SEGMENTS_MAP)) || '{}');
4191
- if (this.activeSession) {
4192
- (_b = getSessionRecorder()) === null || _b === void 0 ? void 0 : _b.updateSegmentIndexCounter(recordingSegmentMapFromStorage);
4193
- }
4194
- else {
4525
+ if (!this.activeSession) {
4195
4526
  this.createNewSession();
4196
4527
  }
4197
4528
  };
@@ -4376,7 +4707,7 @@ function resolveUrlBlueprinters(urlBlueprinters) {
4376
4707
  return resolvedUrlBlueprinters;
4377
4708
  }
4378
4709
 
4379
- var SDK_VERSION = '3.9.0';
4710
+ var SDK_VERSION = '3.15.1';
4380
4711
 
4381
4712
  function shouldDropEvent(cxRumEvent, options) {
4382
4713
  if (isDocumentErrorWithoutMessage(cxRumEvent)) {
@@ -4514,6 +4845,9 @@ var CoralogixSpanMapProcessor = (function () {
4514
4845
  getSessionManager().sessionHasError = true;
4515
4846
  resolvedCxSpan.text.cx_rum.session_context.hasError = true;
4516
4847
  }
4848
+ if (shouldAddOtelAttr(span)) {
4849
+ this.addOtelInstrumentationData(span, resolvedCxSpan);
4850
+ }
4517
4851
  span[CX_MAPPED_SPAN] = resolvedCxSpan;
4518
4852
  }
4519
4853
  }
@@ -4527,21 +4861,19 @@ var CoralogixSpanMapProcessor = (function () {
4527
4861
  return Promise.resolve(undefined);
4528
4862
  };
4529
4863
  CoralogixSpanMapProcessor.prototype._mapToCxSpan = function (span, session, prevSession, sessionHasRecording, sessionHasScreenshot, onlySessionWithErrorMode) {
4530
- var _a, _b;
4531
- var _c = session || {}, sessionId = _c.sessionId, sessionCreationDate = _c.sessionCreationDate;
4532
- var _d = prevSession || {}, prevSessionId = _d.sessionId, prevSessionCreationDate = _d.sessionCreationDate, prevSessionHasRecording = _d.hasRecording, prevSessionHasScreenshot = _d.hasScreenshot;
4533
- var attributes = span.attributes, startTime = span.startTime, parentSpanId = span.parentSpanId, name = span.name, endTime = span.endTime, status = span.status, duration = span.duration, kind = span.kind;
4864
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
4865
+ var _l = session || {}, sessionId = _l.sessionId, sessionCreationDate = _l.sessionCreationDate;
4866
+ var _m = prevSession || {}, prevSessionId = _m.sessionId, prevSessionCreationDate = _m.sessionCreationDate, prevSessionHasRecording = _m.hasRecording, prevSessionHasScreenshot = _m.hasScreenshot;
4867
+ var attributes = span.attributes;
4534
4868
  var user_context = JSON.parse(attributes[CoralogixAttributes.USER_CONTEXT]);
4535
4869
  var application_context = JSON.parse(attributes[CoralogixAttributes.APPLICATION_CONTEXT]);
4536
4870
  var application = application_context.application, version = application_context.version;
4537
4871
  var eventType = attributes[CoralogixAttributes.EVENT_TYPE] ||
4538
4872
  span[CoralogixAttributes.EVENT_TYPE];
4539
4873
  var eventTypeContext = this._getEventTypeContext(attributes, eventType, span);
4540
- var _e = span.spanContext(), spanId = _e.spanId, traceId = _e.traceId;
4541
- var resourceAttributes = __assign(__assign({}, (_a = span.resource) === null || _a === void 0 ? void 0 : _a.attributes), { 'service.name': application });
4542
4874
  var fingerPrint = getSessionManager().fingerPrint;
4543
4875
  var labels = JSON.parse(attributes[CoralogixAttributes.CUSTOM_LABELS]);
4544
- var isErrorWithStacktrace = !!((_b = eventTypeContext === null || eventTypeContext === void 0 ? void 0 : eventTypeContext.error_context) === null || _b === void 0 ? void 0 : _b.original_stacktrace);
4876
+ var isErrorWithStacktrace = !!((_a = eventTypeContext === null || eventTypeContext === void 0 ? void 0 : eventTypeContext.error_context) === null || _a === void 0 ? void 0 : _a.original_stacktrace);
4545
4877
  var version_metadata = {
4546
4878
  app_name: application,
4547
4879
  app_version: version,
@@ -4573,34 +4905,18 @@ var CoralogixSpanMapProcessor = (function () {
4573
4905
  type: eventType,
4574
4906
  source: attributes[CoralogixAttributes.SOURCE],
4575
4907
  severity: severity,
4576
- }, labels: labels, environment: attributes[CoralogixAttributes.ENVIRONMENT] || '' }),
4908
+ }, labels: labels, environment: attributes[CoralogixAttributes.ENVIRONMENT] || '', view_number: getSessionManager().viewNumber, layout_context: {
4909
+ viewport_width: (_b = window === null || window === void 0 ? void 0 : window.innerWidth) !== null && _b !== void 0 ? _b : 0,
4910
+ viewport_height: (_c = window === null || window === void 0 ? void 0 : window.innerHeight) !== null && _c !== void 0 ? _c : 0,
4911
+ view_width: (_e = (_d = document === null || document === void 0 ? void 0 : document.documentElement) === null || _d === void 0 ? void 0 : _d.scrollWidth) !== null && _e !== void 0 ? _e : 0,
4912
+ view_height: (_g = (_f = document === null || document === void 0 ? void 0 : document.documentElement) === null || _f === void 0 ? void 0 : _f.scrollHeight) !== null && _g !== void 0 ? _g : 0,
4913
+ device_pixel_ratio: (_h = window === null || window === void 0 ? void 0 : window.devicePixelRatio) !== null && _h !== void 0 ? _h : 1,
4914
+ scroll_x: (_j = window === null || window === void 0 ? void 0 : window.scrollX) !== null && _j !== void 0 ? _j : 0,
4915
+ scroll_y: (_k = window === null || window === void 0 ? void 0 : window.scrollY) !== null && _k !== void 0 ? _k : 0,
4916
+ } }),
4577
4917
  },
4578
4918
  };
4579
4919
  var resolvedLabels = this.resolveLabels(cxSpan.text.cx_rum);
4580
- if (shouldAddOtelAttr(span)) {
4581
- cxSpan.text.cx_rum.spanId = spanId;
4582
- cxSpan.text.cx_rum.traceId = traceId;
4583
- cxSpan.text.cx_rum.parentSpanId = parentSpanId;
4584
- cxSpan.instrumentation_data = {
4585
- otelSpan: {
4586
- spanId: spanId,
4587
- traceId: traceId,
4588
- parentSpanId: parentSpanId,
4589
- startTime: startTime,
4590
- endTime: endTime,
4591
- status: severity === CoralogixLogSeverity.Error
4592
- ? __assign(__assign({}, status), { code: SpanStatusCode.ERROR }) : status,
4593
- kind: kind,
4594
- duration: duration,
4595
- sessionId: sessionId,
4596
- name: name,
4597
- attributes: buildRumContextAttributes(cxSpan.text.cx_rum, resolvedLabels),
4598
- },
4599
- otelResource: {
4600
- attributes: resourceAttributes,
4601
- },
4602
- };
4603
- }
4604
4920
  this.resolveContextFromSpan(cxSpan, span, eventType);
4605
4921
  cxSpan.text.cx_rum.labels = resolvedLabels;
4606
4922
  return cxSpan;
@@ -4622,8 +4938,42 @@ var CoralogixSpanMapProcessor = (function () {
4622
4938
  span[CoralogixAttributes.SCREENSHOT_CONTEXT];
4623
4939
  break;
4624
4940
  }
4941
+ case CoralogixEventType.DOM: {
4942
+ cxSpan.text.cx_rum.dom_context = span[CoralogixAttributes.DOM_CONTEXT];
4943
+ break;
4944
+ }
4625
4945
  }
4626
4946
  };
4947
+ CoralogixSpanMapProcessor.prototype.addOtelInstrumentationData = function (span, cxSpan) {
4948
+ var _a;
4949
+ var _b = span.spanContext(), spanId = _b.spanId, traceId = _b.traceId;
4950
+ var parentSpanId = span.parentSpanId, startTime = span.startTime, endTime = span.endTime, status = span.status, kind = span.kind, duration = span.duration, name = span.name;
4951
+ var cxRum = cxSpan.text.cx_rum;
4952
+ var sessionId = cxRum.session_context.session_id;
4953
+ cxRum.spanId = spanId;
4954
+ cxRum.traceId = traceId;
4955
+ cxRum.parentSpanId = parentSpanId;
4956
+ var resourceAttributes = __assign(__assign({}, (_a = span.resource) === null || _a === void 0 ? void 0 : _a.attributes), { 'service.name': cxSpan.applicationName });
4957
+ cxSpan.instrumentation_data = {
4958
+ otelSpan: {
4959
+ spanId: spanId,
4960
+ traceId: traceId,
4961
+ parentSpanId: parentSpanId,
4962
+ startTime: startTime,
4963
+ endTime: endTime,
4964
+ status: cxSpan.severity === CoralogixLogSeverity.Error
4965
+ ? __assign(__assign({}, status), { code: SpanStatusCode.ERROR }) : status,
4966
+ kind: kind,
4967
+ duration: duration,
4968
+ sessionId: sessionId,
4969
+ name: name,
4970
+ attributes: buildRumContextAttributes(cxRum, cxRum.labels),
4971
+ },
4972
+ otelResource: {
4973
+ attributes: resourceAttributes,
4974
+ },
4975
+ };
4976
+ };
4627
4977
  CoralogixSpanMapProcessor.prototype._getEventTypeContext = function (spanAttributes, eventType, span) {
4628
4978
  var _a;
4629
4979
  switch (eventType) {
@@ -4697,10 +5047,22 @@ var CoralogixSpanMapProcessor = (function () {
4697
5047
  interaction_context: {
4698
5048
  target_element: spanAttributes[CoralogixAttributes.TARGET_ELEMENT],
4699
5049
  event_name: spanAttributes[CoralogixAttributes.INTERACTION_EVENT_NAME],
5050
+ cx_id: spanAttributes[CoralogixAttributes.CX_ID],
4700
5051
  target_element_inner_text: spanAttributes[CoralogixAttributes.ELEMENT_INNER_TEXT],
4701
5052
  element_id: spanAttributes[CoralogixAttributes.ELEMENT_ID],
4702
5053
  element_classes: spanAttributes[CoralogixAttributes.ELEMENT_CLASSES],
4703
5054
  target_element_type: spanAttributes[CoralogixAttributes.TARGET_ELEMENT_TYPE],
5055
+ resolved_name: spanAttributes[CoralogixAttributes.RESOLVED_NAME],
5056
+ cx_action_name: spanAttributes[CoralogixAttributes.CX_ACTION_NAME],
5057
+ element_aria_label: spanAttributes[CoralogixAttributes.ARIA_LABEL],
5058
+ element_test_id: spanAttributes[CoralogixAttributes.TEST_ID],
5059
+ click_x: spanAttributes[CoralogixAttributes.CLICK_X],
5060
+ click_y: spanAttributes[CoralogixAttributes.CLICK_Y],
5061
+ element_relative_x: spanAttributes[CoralogixAttributes.ELEMENT_RELATIVE_X],
5062
+ element_relative_y: spanAttributes[CoralogixAttributes.ELEMENT_RELATIVE_Y],
5063
+ element_width: spanAttributes[CoralogixAttributes.ELEMENT_WIDTH],
5064
+ element_height: spanAttributes[CoralogixAttributes.ELEMENT_HEIGHT],
5065
+ element_fingerprint: spanAttributes[CoralogixAttributes.ELEMENT_FINGERPRINT],
4704
5066
  },
4705
5067
  };
4706
5068
  }
@@ -4908,6 +5270,7 @@ var CoralogixNavigationProcessor = (function () {
4908
5270
  };
4909
5271
  CoralogixNavigationProcessor.prototype.onEnd = function (span) { };
4910
5272
  CoralogixNavigationProcessor.prototype.onStart = function (span) {
5273
+ var _a;
4911
5274
  if (this.isResolving) {
4912
5275
  return;
4913
5276
  }
@@ -4921,6 +5284,8 @@ var CoralogixNavigationProcessor = (function () {
4921
5284
  if (currentPageFragment !== page_fragments) {
4922
5285
  getSessionManager().updateCurrentPage(page_fragments);
4923
5286
  span[CoralogixAttributes.IS_NAVIGATION_EVENT] = true;
5287
+ this.handlePageNavigation(currentPageFragment);
5288
+ (_a = getClickScreenshotManager()) === null || _a === void 0 ? void 0 : _a.onNavigation();
4924
5289
  }
4925
5290
  }
4926
5291
  }
@@ -4928,6 +5293,11 @@ var CoralogixNavigationProcessor = (function () {
4928
5293
  this.isResolving = false;
4929
5294
  }
4930
5295
  };
5296
+ CoralogixNavigationProcessor.prototype.handlePageNavigation = function (currentPageFragment) {
5297
+ if (currentPageFragment) {
5298
+ getSessionManager().incrementViewNumber();
5299
+ }
5300
+ };
4931
5301
  CoralogixNavigationProcessor.prototype.shutdown = function () {
4932
5302
  return Promise.resolve();
4933
5303
  };
@@ -4941,6 +5311,42 @@ function getTiming(duration) {
4941
5311
  return getNowTime() - getSessionManager().currentPageTimestamp;
4942
5312
  }
4943
5313
 
5314
+ var FIRST_CAPTURE_CLICK = 1;
5315
+ var MIN_SECOND_CAPTURE_CLICK = 2;
5316
+ var TOTAL_CAPTURE_OPTIONS = 9;
5317
+ function sampleSecondCaptureClick() {
5318
+ return (MIN_SECOND_CAPTURE_CLICK + Math.floor(Math.random() * TOTAL_CAPTURE_OPTIONS));
5319
+ }
5320
+ var ClickScreenshotManager = (function () {
5321
+ function ClickScreenshotManager() {
5322
+ var _this = this;
5323
+ this.secondCaptureClick = sampleSecondCaptureClick();
5324
+ this.clickCount = 0;
5325
+ this.reset = function () {
5326
+ _this.secondCaptureClick = sampleSecondCaptureClick();
5327
+ _this.clickCount = 0;
5328
+ };
5329
+ this.onNavigation = function () {
5330
+ _this.clickCount = 0;
5331
+ };
5332
+ this.handleClick = function () {
5333
+ if (!getSessionRecorder()) {
5334
+ return;
5335
+ }
5336
+ _this.clickCount += 1;
5337
+ if (_this.clickCount === FIRST_CAPTURE_CLICK ||
5338
+ _this.clickCount === _this.secondCaptureClick) {
5339
+ CoralogixRum.screenshot(CX_PREFIX);
5340
+ }
5341
+ };
5342
+ CxGlobal[CLICK_SCREENSHOT_MANAGER_KEY] = this;
5343
+ }
5344
+ ClickScreenshotManager.unregister = function () {
5345
+ CxGlobal[CLICK_SCREENSHOT_MANAGER_KEY] = undefined;
5346
+ };
5347
+ return ClickScreenshotManager;
5348
+ }());
5349
+
4944
5350
  if (supportedPerformanceTypes === null || supportedPerformanceTypes === void 0 ? void 0 : supportedPerformanceTypes.has(PerformanceTypes.LongTask)) {
4945
5351
  var ttiHandler_1 = (CxGlobal.__tti = {
4946
5352
  e: [],
@@ -4971,6 +5377,7 @@ var CoralogixRum = {
4971
5377
  init: function (options) {
4972
5378
  var _a, _b;
4973
5379
  var _this = this;
5380
+ var _c;
4974
5381
  try {
4975
5382
  if (isInited) {
4976
5383
  if (options === null || options === void 0 ? void 0 : options.debug) {
@@ -5002,6 +5409,7 @@ var CoralogixRum = {
5002
5409
  tracerProvider = new CoralogixWebTracerProvider({
5003
5410
  sampler: sampler,
5004
5411
  });
5412
+ setTracerProvider(tracerProvider);
5005
5413
  var pluginDefaults_1 = {};
5006
5414
  var instrumentations = INSTRUMENTATIONS.map(function (_a) {
5007
5415
  var _b, _c;
@@ -5087,6 +5495,9 @@ var CoralogixRum = {
5087
5495
  spanMapProcessor = new CoralogixSpanMapProcessor();
5088
5496
  tracerProvider.addSpanProcessor(spanMapProcessor);
5089
5497
  new SnapshotManager();
5498
+ if ((_c = resolvedOptions_1.sessionRecordingConfig) === null || _c === void 0 ? void 0 : _c.enable) {
5499
+ new ClickScreenshotManager();
5500
+ }
5090
5501
  snapshotProcessor = new CoralogixSnapshotSpanProcessor();
5091
5502
  tracerProvider.addSpanProcessor(snapshotProcessor);
5092
5503
  tracerProvider.addSpanProcessor(new BatchSpanProcessor((exporter = new CoralogixExporter()), {
@@ -5098,10 +5509,10 @@ var CoralogixRum = {
5098
5509
  tracerProvider: tracerProvider,
5099
5510
  instrumentations: instrumentations,
5100
5511
  });
5101
- var _c = __read$1(partition(resolvedOptions_1.labelProviders || [], function (_a) {
5512
+ var _d = __read$1(partition(resolvedOptions_1.labelProviders || [], function (_a) {
5102
5513
  var urlType = _a.urlType;
5103
5514
  return urlType === UrlType.PAGE || !urlType;
5104
- }), 2), pageUrlLabelProviders = _c[0], networkUrlLabelProviders = _c[1];
5515
+ }), 2), pageUrlLabelProviders = _d[0], networkUrlLabelProviders = _d[1];
5105
5516
  saveInternalRumData(PAGE_URL_LABEL_PROVIDERS_KEY, pageUrlLabelProviders);
5106
5517
  saveInternalRumData(NETWORK_URL_LABEL_PROVIDERS_KEY, networkUrlLabelProviders);
5107
5518
  isInited = true;
@@ -5187,6 +5598,7 @@ var CoralogixRum = {
5187
5598
  _deregisterInstrumentations = undefined;
5188
5599
  this.stopSessionRecording();
5189
5600
  (_a = getSessionManager()) === null || _a === void 0 ? void 0 : _a.stop();
5601
+ ClickScreenshotManager.unregister();
5190
5602
  attributesProcessor === null || attributesProcessor === void 0 ? void 0 : attributesProcessor.shutdown();
5191
5603
  navigationProcessor === null || navigationProcessor === void 0 ? void 0 : navigationProcessor.shutdown();
5192
5604
  spanMapProcessor === null || spanMapProcessor === void 0 ? void 0 : spanMapProcessor.shutdown();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coralogix/browser",
3
- "version": "3.9.0",
3
+ "version": "3.15.1",
4
4
  "description": "Official Coralogix SDK for browsers",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Coralogix",
@@ -1,5 +1,5 @@
1
1
  import { __values, __spreadArray, __read, __assign, __awaiter, __generator, __rest } from 'tslib';
2
- import { c as cxSetTimeout, a as cxClearTimeout, g as getZoneJsOriginalDom, b as createCxMutationObserver, d as cxRequestAnimationFrame, e as cxCancelAnimationFrame, C as CxGlobal, f as getSdkConfig, h as cxClearInterval, S as SESSION_RECORDER_SEGMENTS_MAP, i as getNowTime, j as SESSION_RECORDING_NETWORK_ERR0R_MESSAGE, k as cxSetInterval, R as Request, l as SESSION_RECORDING_DEFAULT_HEADERS, m as SESSION_RECORDING_POSTFIX_URL, B as BATCH_TIME_DELAY, n as SESSION_RECORDER_KEY, o as SESSION_RECORDING_DEFAULT_ERROR_MESSAGE, M as MAX_BATCH_TIME_MS } from './index.esm2.js';
2
+ import { c as cxSetTimeout, a as cxClearTimeout, g as getZoneJsOriginalDom, b as createCxMutationObserver, d as cxRequestAnimationFrame, e as cxCancelAnimationFrame, C as CxGlobal, S as SESSION_RECORDER_SEGMENTS_MAP, f as getSdkConfig, h as cxClearInterval, i as getNowTime, j as SESSION_RECORDING_NETWORK_ERR0R_MESSAGE, k as cxSetInterval, R as Request, l as SESSION_RECORDING_DEFAULT_HEADERS, m as SESSION_RECORDING_POSTFIX_URL, B as BATCH_TIME_DELAY, n as SESSION_RECORDER_KEY, o as SESSION_RECORDING_DEFAULT_ERROR_MESSAGE, M as MAX_BATCH_TIME_MS } from './index.esm2.js';
3
3
  import '@opentelemetry/sdk-trace-base';
4
4
  import '@opentelemetry/sdk-trace-web';
5
5
  import '@opentelemetry/instrumentation';
@@ -492,6 +492,9 @@ function absolutifyURLs(cssText, href) {
492
492
  if (!filePath) {
493
493
  return origin;
494
494
  }
495
+ if (filePath[0] === '#') {
496
+ return "url(".concat(maybeQuote).concat(filePath).concat(maybeQuote, ")");
497
+ }
495
498
  if (URL_PROTOCOL_MATCH.test(filePath) || URL_WWW_MATCH.test(filePath)) {
496
499
  return "url(".concat(maybeQuote).concat(filePath).concat(maybeQuote, ")");
497
500
  }
@@ -712,8 +715,11 @@ function absoluteToDoc(doc, attributeValue) {
712
715
  }
713
716
  return getHref(doc, attributeValue);
714
717
  }
718
+ var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
715
719
  function isSVGElement(el) {
716
- return Boolean(el.tagName === 'svg' || el.ownerSVGElement);
720
+ return Boolean(el.namespaceURI === SVG_NAMESPACE ||
721
+ el.tagName === 'svg' ||
722
+ el.ownerSVGElement);
717
723
  }
718
724
  function getHref(doc, customHref) {
719
725
  var a = cachedDocument.get(doc);
@@ -1166,12 +1172,13 @@ function serializeElementNode(n, options) {
1166
1172
  }
1167
1173
  catch (e) {
1168
1174
  }
1175
+ var isSVG = isSVGElement(n);
1169
1176
  return {
1170
1177
  type: NodeType.Element,
1171
- tagName: tagName,
1178
+ tagName: isSVG ? n.tagName : tagName,
1172
1179
  attributes: attributes,
1173
1180
  childNodes: [],
1174
- isSVG: isSVGElement(n) || undefined,
1181
+ isSVG: isSVG || undefined,
1175
1182
  needBlock: needBlock,
1176
1183
  rootId: rootId,
1177
1184
  isCustom: isCustomElement,
@@ -5710,7 +5717,7 @@ var WorkerManager = (function () {
5710
5717
  var SessionRecorder = (function () {
5711
5718
  function SessionRecorder(sessionManager, recordConfig) {
5712
5719
  var _this = this;
5713
- var _a;
5720
+ var _a, _b;
5714
5721
  this.isAutoStartRecording = false;
5715
5722
  this.onlySessionWithErrorMode = false;
5716
5723
  this.recordEvents = [];
@@ -5788,6 +5795,9 @@ var SessionRecorder = (function () {
5788
5795
  };
5789
5796
  CxGlobal[SESSION_RECORDER_KEY] = this;
5790
5797
  this.sessionManager = sessionManager;
5798
+ if ((_b = getSdkConfig().sessionConfig) === null || _b === void 0 ? void 0 : _b.keepSessionAfterReload) {
5799
+ this.restoreSegmentIndexCounter();
5800
+ }
5791
5801
  var onlySessionWithErrorMode = sessionManager.onlySessionWithErrorMode, maxRecordTimeForSessionWithError = sessionManager.maxRecordTimeForSessionWithError;
5792
5802
  var autoStartSessionRecording = recordConfig.autoStartSessionRecording, workerUrl = recordConfig.workerUrl;
5793
5803
  this.onlySessionWithErrorMode = onlySessionWithErrorMode;
@@ -5812,15 +5822,22 @@ var SessionRecorder = (function () {
5812
5822
  return (this.hasRecording &&
5813
5823
  !!this.segmentIndexCounter[(_a = this.sessionManager.getActiveSession()) === null || _a === void 0 ? void 0 : _a.sessionId]);
5814
5824
  };
5815
- SessionRecorder.prototype.updateSegmentIndexCounter = function (segmentIndexCounter) {
5816
- this.segmentIndexCounter = segmentIndexCounter;
5825
+ SessionRecorder.prototype.getSegmentIndexCounter = function () {
5826
+ return this.segmentIndexCounter;
5827
+ };
5828
+ SessionRecorder.prototype.restoreSegmentIndexCounter = function () {
5829
+ var stored = CxGlobal.sessionStorage.getItem(SESSION_RECORDER_SEGMENTS_MAP);
5830
+ if (stored) {
5831
+ this.segmentIndexCounter = JSON.parse(stored);
5832
+ }
5817
5833
  };
5818
5834
  SessionRecorder.prototype.getIsAutoStartRecording = function () {
5819
5835
  return this.isAutoStartRecording;
5820
5836
  };
5821
5837
  SessionRecorder.prototype.isConsoleRecordingActive = function () {
5822
5838
  var _a;
5823
- return !!this.recordRef && ((_a = getSdkConfig().sessionRecordingConfig) === null || _a === void 0 ? void 0 : _a.recordConsoleEvents) === true;
5839
+ return (!!this.recordRef &&
5840
+ ((_a = getSdkConfig().sessionRecordingConfig) === null || _a === void 0 ? void 0 : _a.recordConsoleEvents) === true);
5824
5841
  };
5825
5842
  Object.defineProperty(SessionRecorder.prototype, "recordingStopDueToTimeout", {
5826
5843
  get: function () {
package/src/Request.d.ts CHANGED
@@ -10,5 +10,6 @@ export declare class Request {
10
10
  private getResolvedUrl;
11
11
  private init;
12
12
  send(body: BodyInit): Promise<Response>;
13
+ private isWithinKeepaliveQuota;
13
14
  }
14
15
  export {};
@@ -16,6 +16,8 @@ export declare const NETWORK_URL_LABEL_PROVIDERS_KEY = "NETWORK_URL_LABEL_PROVID
16
16
  export declare const RUM_INTERNAL_DATA_KEY = "rumInternalData";
17
17
  export declare const MASKED_TEXT = "***";
18
18
  export declare const MASK_CLASS_DEFAULT = "cx-mask";
19
+ export declare const CX_PREFIX = "cx";
20
+ export declare const ARIA_LABEL_ATTRIBUTE = "aria-label";
19
21
  export declare const MASK_INPUT_TYPES_DEFAULT: InputType[];
20
22
  export declare const FINGER_PRINT_KEY = "cx-fingerprint";
21
23
  export declare const OPTIONS_DEFAULTS: Partial<CoralogixBrowserSdkConfig>;
@@ -43,11 +45,24 @@ export declare const CoralogixAttributes: {
43
45
  ELEMENT_CLASSES: string;
44
46
  TARGET_ELEMENT: string;
45
47
  TARGET_ELEMENT_TYPE: string;
48
+ CX_ACTION_NAME: string;
49
+ CX_ID: string;
50
+ ARIA_LABEL: string;
51
+ TEST_ID: string;
52
+ RESOLVED_NAME: string;
53
+ CLICK_X: string;
54
+ CLICK_Y: string;
55
+ ELEMENT_RELATIVE_X: string;
56
+ ELEMENT_RELATIVE_Y: string;
57
+ ELEMENT_WIDTH: string;
58
+ ELEMENT_HEIGHT: string;
59
+ ELEMENT_FINGERPRINT: string;
46
60
  TIMESTAMP: string;
47
61
  INTERNAL: string;
48
62
  PAGE_CONTEXT: string;
49
63
  IS_NAVIGATION_EVENT: string;
50
64
  SCREENSHOT_CONTEXT: string;
65
+ DOM_CONTEXT: string;
51
66
  };
52
67
  export declare const CoralogixDomainsApiUrlMap: {
53
68
  EU1: string;
@@ -0,0 +1,4 @@
1
+ export declare const CX_ACTION_NAME_ATTRIBUTE = "data-cx-action-name";
2
+ export declare const DATA_TEST_ATTRIBUTE = "data-test";
3
+ export declare const DATA_TESTID_ATTRIBUTE = "data-testid";
4
+ export declare const DATA_TEST_ID_ATTRIBUTE = "data-test-id";
package/src/helpers.d.ts CHANGED
@@ -2,9 +2,15 @@ import { SessionManager } from './session/sessionManager';
2
2
  import { SessionRecorder } from './session/sessionRecorder';
3
3
  import { CoralogixBrowserSdkConfig, UserAgentData } from './types';
4
4
  import { SnapshotManager } from './snapshot/snapshotManager';
5
+ import { WebTracerProvider } from '@opentelemetry/sdk-trace-web';
6
+ import type { ClickScreenshotManager } from './instrumentations/screenshot/click-screenshot-manager';
5
7
  export declare function getSnapshotManager(): SnapshotManager;
6
8
  export declare function getSessionManager(): SessionManager;
7
9
  export declare function getSessionRecorder(): SessionRecorder | undefined;
10
+ export declare function getClickScreenshotManager(): ClickScreenshotManager | undefined;
8
11
  export declare function getSdkConfig(): CoralogixBrowserSdkConfig;
9
12
  export declare function getUserAgentData(): UserAgentData;
10
13
  export declare function clearMemoryFrom(keys: string[]): void;
14
+ export declare function setTracerProvider(provider: WebTracerProvider): void;
15
+ export declare function getTracerProvider(): WebTracerProvider | undefined;
16
+ export declare function flush(): void;
@@ -1,6 +1,7 @@
1
1
  import { InstrumentationBase, InstrumentationConfig } from '@opentelemetry/instrumentation';
2
2
  export declare class CoralogixDOMInstrumentation extends InstrumentationBase {
3
3
  constructor(config: InstrumentationConfig);
4
+ private createDOMSpan;
4
5
  private visibilityChangeHandler;
5
6
  private registerToDOMEvents;
6
7
  private unregisterFromDOMEvents;
@@ -0,0 +1,9 @@
1
+ export declare class ClickScreenshotManager {
2
+ private secondCaptureClick;
3
+ private clickCount;
4
+ static unregister(): void;
5
+ constructor();
6
+ reset: () => void;
7
+ onNavigation: () => void;
8
+ handleClick: () => void;
9
+ }
@@ -0,0 +1 @@
1
+ export declare const CLICK_SCREENSHOT_MANAGER_KEY = "rumClickScreenshotManager";
@@ -0,0 +1,2 @@
1
+ export declare const SHADOW_DOM_MARKER = "::shadow ";
2
+ export declare function getElementFingerprint(target: Element): string | undefined;
@@ -1,2 +1,11 @@
1
1
  import { CoralogixBrowserSdkConfig } from '../../types';
2
+ export declare function extractActionName(el: Element | HTMLElement | null): string;
3
+ export declare function extractAriaLabel(el: Element | HTMLElement | null): string;
4
+ export declare function extractTestId(el: Element | HTMLElement | null): string;
5
+ export declare function extractResolvedName({ element, config, actionName, ariaLabel, }: {
6
+ element: Element | HTMLElement | null;
7
+ config: CoralogixBrowserSdkConfig;
8
+ actionName: string;
9
+ ariaLabel: string;
10
+ }): string;
2
11
  export declare function extractMaskedOrTextContent(element: Element | HTMLElement, config: CoralogixBrowserSdkConfig): string;
@@ -4,5 +4,6 @@ export declare class CoralogixNavigationProcessor implements SpanProcessor {
4
4
  forceFlush(): Promise<void>;
5
5
  onEnd(span: ReadableSpan): void;
6
6
  onStart(span: Span): void;
7
+ private handlePageNavigation;
7
8
  shutdown(): Promise<void>;
8
9
  }
@@ -9,6 +9,7 @@ export declare class CoralogixSpanMapProcessor implements SpanProcessor, Process
9
9
  forceFlush(): Promise<void>;
10
10
  private _mapToCxSpan;
11
11
  private resolveContextFromSpan;
12
+ private addOtelInstrumentationData;
12
13
  private _getEventTypeContext;
13
14
  private resolveLabels;
14
15
  private getLabelsByLabelProviders;
@@ -16,3 +16,4 @@ export declare const SESSION_EXPIRATION_TIME: number;
16
16
  export declare const SESSION_MANAGER_KEY = "rumSessionManager";
17
17
  export declare const SESSION_RECORDER_KEY = "rumSessionRecorder";
18
18
  export declare const SESSION_RECORDER_SEGMENTS_MAP = "rumSessionRecorderSegmentsMap";
19
+ export declare const VIEW_NUMBER_KEY = "rum_view_number";
@@ -11,6 +11,7 @@ export declare class SessionManager extends SessionIdle {
11
11
  private _currentPageFragment;
12
12
  private _currentPageTimestamp;
13
13
  private _fingerPrint;
14
+ private _viewNumber;
14
15
  private debugMode;
15
16
  constructor(recordConfig?: SessionRecordingConfig);
16
17
  get currentPageTimestamp(): number;
@@ -23,9 +24,14 @@ export declare class SessionManager extends SessionIdle {
23
24
  get cachedLogsSent(): boolean;
24
25
  get sessionHasError(): boolean;
25
26
  get fingerPrint(): string | undefined;
27
+ get viewNumber(): number;
26
28
  set sessionHasError(value: boolean);
27
29
  set cachedLogsSent(val: boolean);
28
30
  updateCurrentPage(fragment: string): void;
31
+ incrementViewNumber(): void;
32
+ private persistViewNumber;
33
+ private loadViewNumber;
34
+ private resetViewNumber;
29
35
  getSessionKey(): string;
30
36
  getActiveSession(): Session;
31
37
  start(): void;
@@ -26,7 +26,8 @@ export declare class SessionRecorder {
26
26
  constructor(sessionManager: SessionManager, recordConfig: SessionRecordingConfig);
27
27
  getSessionHasScreenshot(): boolean;
28
28
  getSessionHasRecording(): boolean;
29
- updateSegmentIndexCounter(segmentIndexCounter: Record<string, number>): void;
29
+ getSegmentIndexCounter(): Record<string, number>;
30
+ private restoreSegmentIndexCounter;
30
31
  getIsAutoStartRecording(): boolean;
31
32
  isConsoleRecordingActive(): boolean;
32
33
  set recordingStopDueToTimeout(value: boolean);
package/src/types.d.ts CHANGED
@@ -75,6 +75,9 @@ export interface ScreenshotContext {
75
75
  id: string;
76
76
  description?: string;
77
77
  }
78
+ export interface DomContext {
79
+ visibility_state: DocumentVisibilityState;
80
+ }
78
81
  export interface ApplicationContextConfig {
79
82
  application: string;
80
83
  version: string;
@@ -221,8 +224,29 @@ export interface InteractionContext {
221
224
  target_element_inner_text: string;
222
225
  target_element_type: string;
223
226
  event_name: string;
227
+ cx_id: string;
224
228
  element_id: string;
225
229
  element_classes: string;
230
+ cx_action_name?: string;
231
+ element_aria_label?: string;
232
+ element_test_id?: string;
233
+ resolved_name: string;
234
+ click_x?: number;
235
+ click_y?: number;
236
+ element_relative_x?: number;
237
+ element_relative_y?: number;
238
+ element_width?: number;
239
+ element_height?: number;
240
+ element_fingerprint?: string;
241
+ }
242
+ export interface LayoutContext {
243
+ viewport_width: number;
244
+ viewport_height: number;
245
+ view_width: number;
246
+ view_height: number;
247
+ device_pixel_ratio: number;
248
+ scroll_x: number;
249
+ scroll_y: number;
226
250
  }
227
251
  export interface LongTaskContext extends Omit<PerformanceEntry, 'toJSON'> {
228
252
  id: string;
@@ -254,6 +278,7 @@ export interface EventTypeContext {
254
278
  custom_measurement_context?: CustomMeasurementContext;
255
279
  screenshot_context?: ScreenshotContext;
256
280
  memory_usage_context?: MemoryUsageContext;
281
+ dom_context?: DomContext;
257
282
  }
258
283
  export interface UserMetadata {
259
284
  user_id: string;
@@ -331,6 +356,8 @@ export interface CxRumEvent extends EventTypeContext {
331
356
  screenshot_context?: ScreenshotContext;
332
357
  screenshotId?: string;
333
358
  fingerPrint: string;
359
+ view_number: number;
360
+ layout_context: LayoutContext;
334
361
  }
335
362
  export interface CxSpan {
336
363
  version_metadata: VersionMetaData;
package/src/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const SDK_VERSION = "3.9.0";
1
+ export declare const SDK_VERSION = "3.15.1";