@coralogix/browser
Version:
Official Coralogix SDK for browsers
1,505 lines (1,500 loc) • 58 kB
JavaScript
import { __awaiter, __generator, __assign } from 'tslib';
import { C as CxGlobal, r as reportInternalEvent, g as getSdkConfig, S as SESSION_RECORDER_SEGMENTS_MAP, a as getNowTime, b as SESSION_RECORDING_NETWORK_ERR0R_MESSAGE, M as MAX_BATCH_TIME_MS, R as Request, c as SESSION_RECORDING_POSTFIX_URL, d as SESSION_RECORDING_DEFAULT_HEADERS, B as BATCH_TIME_DELAY, e as SESSION_RECORDER_KEY, f as MAX_MUTATIONS_FOR_SESSION_RECORDING, h as SESSION_RECORDING_DEFAULT_ERROR_MESSAGE } from './index.esm2.js';
import { record } from 'rrweb';
import { getRecordConsolePlugin } from '@rrweb/rrweb-plugin-console-record';
import '@opentelemetry/sdk-trace-base';
import '@opentelemetry/sdk-trace-web';
import '@opentelemetry/instrumentation';
import 'error-stack-parser';
import '@opentelemetry/instrumentation-fetch';
import '@opentelemetry/instrumentation-xml-http-request';
import 'web-vitals/attribution';
import '@opentelemetry/api';
import '@opentelemetry/propagator-b3';
import '@opentelemetry/propagator-aws-xray';
var EventType = /* @__PURE__ */ ((EventType2) => {
EventType2[EventType2["DomContentLoaded"] = 0] = "DomContentLoaded";
EventType2[EventType2["Load"] = 1] = "Load";
EventType2[EventType2["FullSnapshot"] = 2] = "FullSnapshot";
EventType2[EventType2["IncrementalSnapshot"] = 3] = "IncrementalSnapshot";
EventType2[EventType2["Meta"] = 4] = "Meta";
EventType2[EventType2["Custom"] = 5] = "Custom";
EventType2[EventType2["Plugin"] = 6] = "Plugin";
return EventType2;
})(EventType || {});
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
var NodeType = /* @__PURE__ */ ((NodeType2) => {
NodeType2[NodeType2["Document"] = 0] = "Document";
NodeType2[NodeType2["DocumentType"] = 1] = "DocumentType";
NodeType2[NodeType2["Element"] = 2] = "Element";
NodeType2[NodeType2["Text"] = 3] = "Text";
NodeType2[NodeType2["CDATA"] = 4] = "CDATA";
NodeType2[NodeType2["Comment"] = 5] = "Comment";
return NodeType2;
})(NodeType || {});
function isElement(n) {
return n.nodeType === n.ELEMENT_NODE;
}
function isShadowRoot(n) {
const host = n == null ? undefined : n.host;
return Boolean((host == null ? undefined : host.shadowRoot) === n);
}
function isNativeShadowDom(shadowRoot) {
return Object.prototype.toString.call(shadowRoot) === "[object ShadowRoot]";
}
function fixBrowserCompatibilityIssuesInCSS(cssText) {
if (cssText.includes(" background-clip: text;") && !cssText.includes(" -webkit-background-clip: text;")) {
cssText = cssText.replace(
/\sbackground-clip:\s*text;/g,
" -webkit-background-clip: text; background-clip: text;"
);
}
return cssText;
}
function escapeImportStatement(rule) {
const { cssText } = rule;
if (cssText.split('"').length < 3)
return cssText;
const statement = ["@import", `url(${JSON.stringify(rule.href)})`];
if (rule.layerName === "") {
statement.push(`layer`);
} else if (rule.layerName) {
statement.push(`layer(${rule.layerName})`);
}
if (rule.supportsText) {
statement.push(`supports(${rule.supportsText})`);
}
if (rule.media.length) {
statement.push(rule.media.mediaText);
}
return statement.join(" ") + ";";
}
function stringifyStylesheet(s) {
try {
const rules = s.rules || s.cssRules;
return rules ? fixBrowserCompatibilityIssuesInCSS(
Array.from(rules, stringifyRule).join("")
) : null;
} catch (error) {
return null;
}
}
function stringifyRule(rule) {
let importStringified;
if (isCSSImportRule(rule)) {
try {
importStringified = // for same-origin stylesheets,
// we can access the imported stylesheet rules directly
stringifyStylesheet(rule.styleSheet) || // work around browser issues with the raw string `@import url(...)` statement
escapeImportStatement(rule);
} catch (error) {
}
} else if (isCSSStyleRule(rule) && rule.selectorText.includes(":")) {
return fixSafariColons(rule.cssText);
}
return importStringified || rule.cssText;
}
function fixSafariColons(cssStringified) {
const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm;
return cssStringified.replace(regex, "$1\\$2");
}
function isCSSImportRule(rule) {
return "styleSheet" in rule;
}
function isCSSStyleRule(rule) {
return "selectorText" in rule;
}
class Mirror {
constructor() {
__publicField(this, "idNodeMap", /* @__PURE__ */ new Map());
__publicField(this, "nodeMetaMap", /* @__PURE__ */ new WeakMap());
}
getId(n) {
var _a;
if (!n)
return -1;
const id = (_a = this.getMeta(n)) == null ? undefined : _a.id;
return id ?? -1;
}
getNode(id) {
return this.idNodeMap.get(id) || null;
}
getIds() {
return Array.from(this.idNodeMap.keys());
}
getMeta(n) {
return this.nodeMetaMap.get(n) || null;
}
// removes the node from idNodeMap
// doesn't remove the node from nodeMetaMap
removeNodeFromMap(n) {
const id = this.getId(n);
this.idNodeMap.delete(id);
if (n.childNodes) {
n.childNodes.forEach(
(childNode) => this.removeNodeFromMap(childNode)
);
}
}
has(id) {
return this.idNodeMap.has(id);
}
hasNode(node) {
return this.nodeMetaMap.has(node);
}
add(n, meta) {
const id = meta.id;
this.idNodeMap.set(id, n);
this.nodeMetaMap.set(n, meta);
}
replace(id, n) {
const oldNode = this.getNode(id);
if (oldNode) {
const meta = this.nodeMetaMap.get(oldNode);
if (meta)
this.nodeMetaMap.set(n, meta);
}
this.idNodeMap.set(id, n);
}
reset() {
this.idNodeMap = /* @__PURE__ */ new Map();
this.nodeMetaMap = /* @__PURE__ */ new WeakMap();
}
}
function maskInputValue({
element,
maskInputOptions,
tagName,
type,
value,
maskInputFn
}) {
let text = value || "";
const actualType = type && toLowerCase(type);
if (maskInputOptions[tagName.toLowerCase()] || actualType && maskInputOptions[actualType]) {
if (maskInputFn) {
text = maskInputFn(text, element);
} else {
text = "*".repeat(text.length);
}
}
return text;
}
function toLowerCase(str) {
return str.toLowerCase();
}
const ORIGINAL_ATTRIBUTE_NAME = "__rrweb_original__";
function is2DCanvasBlank(canvas) {
const ctx = canvas.getContext("2d");
if (!ctx)
return true;
const chunkSize = 50;
for (let x = 0; x < canvas.width; x += chunkSize) {
for (let y = 0; y < canvas.height; y += chunkSize) {
const getImageData = ctx.getImageData;
const originalGetImageData = ORIGINAL_ATTRIBUTE_NAME in getImageData ? getImageData[ORIGINAL_ATTRIBUTE_NAME] : getImageData;
const pixelBuffer = new Uint32Array(
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
originalGetImageData.call(
ctx,
x,
y,
Math.min(chunkSize, canvas.width - x),
Math.min(chunkSize, canvas.height - y)
).data.buffer
);
if (pixelBuffer.some((pixel) => pixel !== 0))
return false;
}
}
return true;
}
function getInputType(element) {
const type = element.type;
return element.hasAttribute("data-rr-is-password") ? "password" : type ? (
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
toLowerCase(type)
) : null;
}
function extractFileExtension(path, baseURL) {
let url;
try {
url = new URL(path, baseURL ?? window.location.href);
} catch (err) {
return null;
}
const regex = /\.([0-9a-z]+)(?:$)/i;
const match = url.pathname.match(regex);
return (match == null ? undefined : match[1]) ?? null;
}
let _id = 1;
const tagNameRegex = new RegExp("[^a-z0-9-_:]");
const IGNORED_NODE = -2;
function genId() {
return _id++;
}
function getValidTagName(element) {
if (element instanceof HTMLFormElement) {
return "form";
}
const processedTagName = toLowerCase(element.tagName);
if (tagNameRegex.test(processedTagName)) {
return "div";
}
return processedTagName;
}
function extractOrigin(url) {
let origin = "";
if (url.indexOf("//") > -1) {
origin = url.split("/").slice(0, 3).join("/");
} else {
origin = url.split("/")[0];
}
origin = origin.split("?")[0];
return origin;
}
let canvasService;
let canvasCtx;
const URL_IN_CSS_REF = /url\((?:(')([^']*)'|(")(.*?)"|([^)]*))\)/gm;
const URL_PROTOCOL_MATCH = /^(?:[a-z+]+:)?\/\//i;
const URL_WWW_MATCH = /^www\..*/i;
const DATA_URI = /^(data:)([^,]*),(.*)/i;
function absoluteToStylesheet(cssText, href) {
return (cssText || "").replace(
URL_IN_CSS_REF,
(origin, quote1, path1, quote2, path2, path3) => {
const filePath = path1 || path2 || path3;
const maybeQuote = quote1 || quote2 || "";
if (!filePath) {
return origin;
}
if (URL_PROTOCOL_MATCH.test(filePath) || URL_WWW_MATCH.test(filePath)) {
return `url(${maybeQuote}${filePath}${maybeQuote})`;
}
if (DATA_URI.test(filePath)) {
return `url(${maybeQuote}${filePath}${maybeQuote})`;
}
if (filePath[0] === "/") {
return `url(${maybeQuote}${extractOrigin(href) + filePath}${maybeQuote})`;
}
const stack = href.split("/");
const parts = filePath.split("/");
stack.pop();
for (const part of parts) {
if (part === ".") {
continue;
} else if (part === "..") {
stack.pop();
} else {
stack.push(part);
}
}
return `url(${maybeQuote}${stack.join("/")}${maybeQuote})`;
}
);
}
const SRCSET_NOT_SPACES = /^[^ \t\n\r\u000c]+/;
const SRCSET_COMMAS_OR_SPACES = /^[, \t\n\r\u000c]+/;
function getAbsoluteSrcsetString(doc, attributeValue) {
if (attributeValue.trim() === "") {
return attributeValue;
}
let pos = 0;
function collectCharacters(regEx) {
let chars;
const match = regEx.exec(attributeValue.substring(pos));
if (match) {
chars = match[0];
pos += chars.length;
return chars;
}
return "";
}
const output = [];
while (true) {
collectCharacters(SRCSET_COMMAS_OR_SPACES);
if (pos >= attributeValue.length) {
break;
}
let url = collectCharacters(SRCSET_NOT_SPACES);
if (url.slice(-1) === ",") {
url = absoluteToDoc(doc, url.substring(0, url.length - 1));
output.push(url);
} else {
let descriptorsStr = "";
url = absoluteToDoc(doc, url);
let inParens = false;
while (true) {
const c = attributeValue.charAt(pos);
if (c === "") {
output.push((url + descriptorsStr).trim());
break;
} else if (!inParens) {
if (c === ",") {
pos += 1;
output.push((url + descriptorsStr).trim());
break;
} else if (c === "(") {
inParens = true;
}
} else {
if (c === ")") {
inParens = false;
}
}
descriptorsStr += c;
pos += 1;
}
}
}
return output.join(", ");
}
const cachedDocument = /* @__PURE__ */ new WeakMap();
function absoluteToDoc(doc, attributeValue) {
if (!attributeValue || attributeValue.trim() === "") {
return attributeValue;
}
return getHref(doc, attributeValue);
}
function isSVGElement(el) {
return Boolean(el.tagName === "svg" || el.ownerSVGElement);
}
function getHref(doc, customHref) {
let a = cachedDocument.get(doc);
if (!a) {
a = doc.createElement("a");
cachedDocument.set(doc, a);
}
if (!customHref) {
customHref = "";
} else if (customHref.startsWith("blob:") || customHref.startsWith("data:")) {
return customHref;
}
a.setAttribute("href", customHref);
return a.href;
}
function transformAttribute(doc, tagName, name, value) {
if (!value) {
return value;
}
if (name === "src" || name === "href" && !(tagName === "use" && value[0] === "#")) {
return absoluteToDoc(doc, value);
} else if (name === "xlink:href" && value[0] !== "#") {
return absoluteToDoc(doc, value);
} else if (name === "background" && (tagName === "table" || tagName === "td" || tagName === "th")) {
return absoluteToDoc(doc, value);
} else if (name === "srcset") {
return getAbsoluteSrcsetString(doc, value);
} else if (name === "style") {
return absoluteToStylesheet(value, getHref(doc));
} else if (tagName === "object" && name === "data") {
return absoluteToDoc(doc, value);
}
return value;
}
function ignoreAttribute(tagName, name, _value) {
return (tagName === "video" || tagName === "audio") && name === "autoplay";
}
function _isBlockedElement(element, blockClass, blockSelector) {
try {
if (typeof blockClass === "string") {
if (element.classList.contains(blockClass)) {
return true;
}
} else {
for (let eIndex = element.classList.length; eIndex--; ) {
const className = element.classList[eIndex];
if (blockClass.test(className)) {
return true;
}
}
}
if (blockSelector) {
return element.matches(blockSelector);
}
} catch (e) {
}
return false;
}
function classMatchesRegex(node, regex, checkAncestors) {
if (!node)
return false;
if (node.nodeType !== node.ELEMENT_NODE) {
if (!checkAncestors)
return false;
return classMatchesRegex(node.parentNode, regex, checkAncestors);
}
for (let eIndex = node.classList.length; eIndex--; ) {
const className = node.classList[eIndex];
if (regex.test(className)) {
return true;
}
}
if (!checkAncestors)
return false;
return classMatchesRegex(node.parentNode, regex, checkAncestors);
}
function needMaskingText(node, maskTextClass, maskTextSelector, checkAncestors) {
try {
const el = node.nodeType === node.ELEMENT_NODE ? node : node.parentElement;
if (el === null)
return false;
if (typeof maskTextClass === "string") {
if (checkAncestors) {
if (el.closest(`.${maskTextClass}`))
return true;
} else {
if (el.classList.contains(maskTextClass))
return true;
}
} else {
if (classMatchesRegex(el, maskTextClass, checkAncestors))
return true;
}
if (maskTextSelector) {
if (checkAncestors) {
if (el.closest(maskTextSelector))
return true;
} else {
if (el.matches(maskTextSelector))
return true;
}
}
} catch (e) {
}
return false;
}
function onceIframeLoaded(iframeEl, listener, iframeLoadTimeout) {
const win = iframeEl.contentWindow;
if (!win) {
return;
}
let fired = false;
let readyState;
try {
readyState = win.document.readyState;
} catch (error) {
return;
}
if (readyState !== "complete") {
const timer = setTimeout(() => {
if (!fired) {
listener();
fired = true;
}
}, iframeLoadTimeout);
iframeEl.addEventListener("load", () => {
clearTimeout(timer);
fired = true;
listener();
});
return;
}
const blankUrl = "about:blank";
if (win.location.href !== blankUrl || iframeEl.src === blankUrl || iframeEl.src === "") {
setTimeout(listener, 0);
return iframeEl.addEventListener("load", listener);
}
iframeEl.addEventListener("load", listener);
}
function onceStylesheetLoaded(link, listener, styleSheetLoadTimeout) {
let fired = false;
let styleSheetLoaded;
try {
styleSheetLoaded = link.sheet;
} catch (error) {
return;
}
if (styleSheetLoaded)
return;
const timer = setTimeout(() => {
if (!fired) {
listener();
fired = true;
}
}, styleSheetLoadTimeout);
link.addEventListener("load", () => {
clearTimeout(timer);
fired = true;
listener();
});
}
function serializeNode(n, options) {
const {
doc,
mirror,
blockClass,
blockSelector,
needsMask,
inlineStylesheet,
maskInputOptions = {},
maskTextFn,
maskInputFn,
dataURLOptions = {},
inlineImages,
recordCanvas,
keepIframeSrcFn,
newlyAddedElement = false
} = options;
const rootId = getRootId(doc, mirror);
switch (n.nodeType) {
case n.DOCUMENT_NODE:
if (n.compatMode !== "CSS1Compat") {
return {
type: NodeType.Document,
childNodes: [],
compatMode: n.compatMode
// probably "BackCompat"
};
} else {
return {
type: NodeType.Document,
childNodes: []
};
}
case n.DOCUMENT_TYPE_NODE:
return {
type: NodeType.DocumentType,
name: n.name,
publicId: n.publicId,
systemId: n.systemId,
rootId
};
case n.ELEMENT_NODE:
return serializeElementNode(n, {
doc,
blockClass,
blockSelector,
inlineStylesheet,
maskInputOptions,
maskInputFn,
dataURLOptions,
inlineImages,
recordCanvas,
keepIframeSrcFn,
newlyAddedElement,
rootId
});
case n.TEXT_NODE:
return serializeTextNode(n, {
doc,
needsMask,
maskTextFn,
rootId
});
case n.CDATA_SECTION_NODE:
return {
type: NodeType.CDATA,
textContent: "",
rootId
};
case n.COMMENT_NODE:
return {
type: NodeType.Comment,
textContent: n.textContent || "",
rootId
};
default:
return false;
}
}
function getRootId(doc, mirror) {
if (!mirror.hasNode(doc))
return undefined;
const docId = mirror.getId(doc);
return docId === 1 ? undefined : docId;
}
function serializeTextNode(n, options) {
var _a;
const { needsMask, maskTextFn, rootId } = options;
const parentTagName = n.parentNode && n.parentNode.tagName;
let textContent = n.textContent;
const isStyle = parentTagName === "STYLE" ? true : undefined;
const isScript = parentTagName === "SCRIPT" ? true : undefined;
if (isStyle && textContent) {
try {
if (n.nextSibling || n.previousSibling) {
} else if ((_a = n.parentNode.sheet) == null ? void 0 : _a.cssRules) {
textContent = stringifyStylesheet(
n.parentNode.sheet
);
}
} catch (err) {
console.warn(
`Cannot get CSS styles from text's parentNode. Error: ${err}`,
n
);
}
textContent = absoluteToStylesheet(textContent, getHref(options.doc));
}
if (isScript) {
textContent = "SCRIPT_PLACEHOLDER";
}
if (!isStyle && !isScript && textContent && needsMask) {
textContent = maskTextFn ? maskTextFn(textContent, n.parentElement) : textContent.replace(/[\S]/g, "*");
}
return {
type: NodeType.Text,
textContent: textContent || "",
isStyle,
rootId
};
}
function serializeElementNode(n, options) {
const {
doc,
blockClass,
blockSelector,
inlineStylesheet,
maskInputOptions = {},
maskInputFn,
dataURLOptions = {},
inlineImages,
recordCanvas,
keepIframeSrcFn,
newlyAddedElement = false,
rootId
} = options;
const needBlock = _isBlockedElement(n, blockClass, blockSelector);
const tagName = getValidTagName(n);
let attributes2 = {};
const len = n.attributes.length;
for (let i = 0; i < len; i++) {
const attr = n.attributes[i];
if (!ignoreAttribute(tagName, attr.name, attr.value)) {
attributes2[attr.name] = transformAttribute(
doc,
tagName,
toLowerCase(attr.name),
attr.value
);
}
}
if (tagName === "link" && inlineStylesheet) {
const stylesheet = Array.from(doc.styleSheets).find((s) => {
return s.href === n.href;
});
let cssText = null;
if (stylesheet) {
cssText = stringifyStylesheet(stylesheet);
}
if (cssText) {
delete attributes2.rel;
delete attributes2.href;
attributes2._cssText = absoluteToStylesheet(cssText, stylesheet.href);
}
}
if (tagName === "style" && n.sheet && // TODO: Currently we only try to get dynamic stylesheet when it is an empty style element
!(n.innerText || n.textContent || "").trim().length) {
const cssText = stringifyStylesheet(
n.sheet
);
if (cssText) {
attributes2._cssText = absoluteToStylesheet(cssText, getHref(doc));
}
}
if (tagName === "input" || tagName === "textarea" || tagName === "select") {
const value = n.value;
const checked = n.checked;
if (attributes2.type !== "radio" && attributes2.type !== "checkbox" && attributes2.type !== "submit" && attributes2.type !== "button" && value) {
attributes2.value = maskInputValue({
element: n,
type: getInputType(n),
tagName,
value,
maskInputOptions,
maskInputFn
});
} else if (checked) {
attributes2.checked = checked;
}
}
if (tagName === "option") {
if (n.selected && !maskInputOptions["select"]) {
attributes2.selected = true;
} else {
delete attributes2.selected;
}
}
if (tagName === "canvas" && recordCanvas) {
if (n.__context === "2d") {
if (!is2DCanvasBlank(n)) {
attributes2.rr_dataURL = n.toDataURL(
dataURLOptions.type,
dataURLOptions.quality
);
}
} else if (!("__context" in n)) {
const canvasDataURL = n.toDataURL(
dataURLOptions.type,
dataURLOptions.quality
);
const blankCanvas = doc.createElement("canvas");
blankCanvas.width = n.width;
blankCanvas.height = n.height;
const blankCanvasDataURL = blankCanvas.toDataURL(
dataURLOptions.type,
dataURLOptions.quality
);
if (canvasDataURL !== blankCanvasDataURL) {
attributes2.rr_dataURL = canvasDataURL;
}
}
}
if (tagName === "img" && inlineImages) {
if (!canvasService) {
canvasService = doc.createElement("canvas");
canvasCtx = canvasService.getContext("2d");
}
const image = n;
const imageSrc = image.currentSrc || image.getAttribute("src") || "<unknown-src>";
const priorCrossOrigin = image.crossOrigin;
const recordInlineImage = () => {
image.removeEventListener("load", recordInlineImage);
try {
canvasService.width = image.naturalWidth;
canvasService.height = image.naturalHeight;
canvasCtx.drawImage(image, 0, 0);
attributes2.rr_dataURL = canvasService.toDataURL(
dataURLOptions.type,
dataURLOptions.quality
);
} catch (err) {
if (image.crossOrigin !== "anonymous") {
image.crossOrigin = "anonymous";
if (image.complete && image.naturalWidth !== 0)
recordInlineImage();
else
image.addEventListener("load", recordInlineImage);
return;
} else {
console.warn(
`Cannot inline img src=${imageSrc}! Error: ${err}`
);
}
}
if (image.crossOrigin === "anonymous") {
priorCrossOrigin ? attributes2.crossOrigin = priorCrossOrigin : image.removeAttribute("crossorigin");
}
};
if (image.complete && image.naturalWidth !== 0)
recordInlineImage();
else
image.addEventListener("load", recordInlineImage);
}
if (tagName === "audio" || tagName === "video") {
const mediaAttributes = attributes2;
mediaAttributes.rr_mediaState = n.paused ? "paused" : "played";
mediaAttributes.rr_mediaCurrentTime = n.currentTime;
mediaAttributes.rr_mediaPlaybackRate = n.playbackRate;
mediaAttributes.rr_mediaMuted = n.muted;
mediaAttributes.rr_mediaLoop = n.loop;
mediaAttributes.rr_mediaVolume = n.volume;
}
if (!newlyAddedElement) {
if (n.scrollLeft) {
attributes2.rr_scrollLeft = n.scrollLeft;
}
if (n.scrollTop) {
attributes2.rr_scrollTop = n.scrollTop;
}
}
if (needBlock) {
const { width, height } = n.getBoundingClientRect();
attributes2 = {
class: attributes2.class,
rr_width: `${width}px`,
rr_height: `${height}px`
};
}
if (tagName === "iframe" && !keepIframeSrcFn(attributes2.src)) {
if (!n.contentDocument) {
attributes2.rr_src = attributes2.src;
}
delete attributes2.src;
}
let isCustomElement;
try {
if (customElements.get(tagName))
isCustomElement = true;
} catch (e) {
}
return {
type: NodeType.Element,
tagName,
attributes: attributes2,
childNodes: [],
isSVG: isSVGElement(n) || undefined,
needBlock,
rootId,
isCustom: isCustomElement
};
}
function lowerIfExists(maybeAttr) {
if (maybeAttr === undefined || maybeAttr === null) {
return "";
} else {
return maybeAttr.toLowerCase();
}
}
function slimDOMExcluded(sn, slimDOMOptions) {
if (slimDOMOptions.comment && sn.type === NodeType.Comment) {
return true;
} else if (sn.type === NodeType.Element) {
if (slimDOMOptions.script && // script tag
(sn.tagName === "script" || // (module)preload link
sn.tagName === "link" && (sn.attributes.rel === "preload" || sn.attributes.rel === "modulepreload") && sn.attributes.as === "script" || // prefetch link
sn.tagName === "link" && sn.attributes.rel === "prefetch" && typeof sn.attributes.href === "string" && extractFileExtension(sn.attributes.href) === "js")) {
return true;
} else if (slimDOMOptions.headFavicon && (sn.tagName === "link" && sn.attributes.rel === "shortcut icon" || sn.tagName === "meta" && (lowerIfExists(sn.attributes.name).match(
/^msapplication-tile(image|color)$/
) || lowerIfExists(sn.attributes.name) === "application-name" || lowerIfExists(sn.attributes.rel) === "icon" || lowerIfExists(sn.attributes.rel) === "apple-touch-icon" || lowerIfExists(sn.attributes.rel) === "shortcut icon"))) {
return true;
} else if (sn.tagName === "meta") {
if (slimDOMOptions.headMetaDescKeywords && lowerIfExists(sn.attributes.name).match(/^description|keywords$/)) {
return true;
} else if (slimDOMOptions.headMetaSocial && (lowerIfExists(sn.attributes.property).match(/^(og|twitter|fb):/) || // og = opengraph (facebook)
lowerIfExists(sn.attributes.name).match(/^(og|twitter):/) || lowerIfExists(sn.attributes.name) === "pinterest")) {
return true;
} else if (slimDOMOptions.headMetaRobots && (lowerIfExists(sn.attributes.name) === "robots" || lowerIfExists(sn.attributes.name) === "googlebot" || lowerIfExists(sn.attributes.name) === "bingbot")) {
return true;
} else if (slimDOMOptions.headMetaHttpEquiv && sn.attributes["http-equiv"] !== undefined) {
return true;
} else if (slimDOMOptions.headMetaAuthorship && (lowerIfExists(sn.attributes.name) === "author" || lowerIfExists(sn.attributes.name) === "generator" || lowerIfExists(sn.attributes.name) === "framework" || lowerIfExists(sn.attributes.name) === "publisher" || lowerIfExists(sn.attributes.name) === "progid" || lowerIfExists(sn.attributes.property).match(/^article:/) || lowerIfExists(sn.attributes.property).match(/^product:/))) {
return true;
} else if (slimDOMOptions.headMetaVerification && (lowerIfExists(sn.attributes.name) === "google-site-verification" || lowerIfExists(sn.attributes.name) === "yandex-verification" || lowerIfExists(sn.attributes.name) === "csrf-token" || lowerIfExists(sn.attributes.name) === "p:domain_verify" || lowerIfExists(sn.attributes.name) === "verify-v1" || lowerIfExists(sn.attributes.name) === "verification" || lowerIfExists(sn.attributes.name) === "shopify-checkout-api-token")) {
return true;
}
}
}
return false;
}
function serializeNodeWithId(n, options) {
const {
doc,
mirror,
blockClass,
blockSelector,
maskTextClass,
maskTextSelector,
skipChild = false,
inlineStylesheet = true,
maskInputOptions = {},
maskTextFn,
maskInputFn,
slimDOMOptions,
dataURLOptions = {},
inlineImages = false,
recordCanvas = false,
onSerialize,
onIframeLoad,
iframeLoadTimeout = 5e3,
onStylesheetLoad,
stylesheetLoadTimeout = 5e3,
keepIframeSrcFn = () => false,
newlyAddedElement = false
} = options;
let { needsMask } = options;
let { preserveWhiteSpace = true } = options;
if (!needsMask && n.childNodes) {
const checkAncestors = needsMask === undefined;
needsMask = needMaskingText(
n,
maskTextClass,
maskTextSelector,
checkAncestors
);
}
const _serializedNode = serializeNode(n, {
doc,
mirror,
blockClass,
blockSelector,
needsMask,
inlineStylesheet,
maskInputOptions,
maskTextFn,
maskInputFn,
dataURLOptions,
inlineImages,
recordCanvas,
keepIframeSrcFn,
newlyAddedElement
});
if (!_serializedNode) {
console.warn(n, "not serialized");
return null;
}
let id;
if (mirror.hasNode(n)) {
id = mirror.getId(n);
} else if (slimDOMExcluded(_serializedNode, slimDOMOptions) || !preserveWhiteSpace && _serializedNode.type === NodeType.Text && !_serializedNode.isStyle && !_serializedNode.textContent.replace(/^\s+|\s+$/gm, "").length) {
id = IGNORED_NODE;
} else {
id = genId();
}
const serializedNode2 = Object.assign(_serializedNode, { id });
mirror.add(n, serializedNode2);
if (id === IGNORED_NODE) {
return null;
}
if (onSerialize) {
onSerialize(n);
}
let recordChild = !skipChild;
if (serializedNode2.type === NodeType.Element) {
recordChild = recordChild && !serializedNode2.needBlock;
delete serializedNode2.needBlock;
const shadowRoot = n.shadowRoot;
if (shadowRoot && isNativeShadowDom(shadowRoot))
serializedNode2.isShadowHost = true;
}
if ((serializedNode2.type === NodeType.Document || serializedNode2.type === NodeType.Element) && recordChild) {
if (slimDOMOptions.headWhitespace && serializedNode2.type === NodeType.Element && serializedNode2.tagName === "head") {
preserveWhiteSpace = false;
}
const bypassOptions = {
doc,
mirror,
blockClass,
blockSelector,
needsMask,
maskTextClass,
maskTextSelector,
skipChild,
inlineStylesheet,
maskInputOptions,
maskTextFn,
maskInputFn,
slimDOMOptions,
dataURLOptions,
inlineImages,
recordCanvas,
preserveWhiteSpace,
onSerialize,
onIframeLoad,
iframeLoadTimeout,
onStylesheetLoad,
stylesheetLoadTimeout,
keepIframeSrcFn
};
if (serializedNode2.type === NodeType.Element && serializedNode2.tagName === "textarea" && serializedNode2.attributes.value !== undefined)
;
else {
for (const childN of Array.from(n.childNodes)) {
const serializedChildNode = serializeNodeWithId(childN, bypassOptions);
if (serializedChildNode) {
serializedNode2.childNodes.push(serializedChildNode);
}
}
}
if (isElement(n) && n.shadowRoot) {
for (const childN of Array.from(n.shadowRoot.childNodes)) {
const serializedChildNode = serializeNodeWithId(childN, bypassOptions);
if (serializedChildNode) {
isNativeShadowDom(n.shadowRoot) && (serializedChildNode.isShadow = true);
serializedNode2.childNodes.push(serializedChildNode);
}
}
}
}
if (n.parentNode && isShadowRoot(n.parentNode) && isNativeShadowDom(n.parentNode)) {
serializedNode2.isShadow = true;
}
if (serializedNode2.type === NodeType.Element && serializedNode2.tagName === "iframe") {
onceIframeLoaded(
n,
() => {
const iframeDoc = n.contentDocument;
if (iframeDoc && onIframeLoad) {
const serializedIframeNode = serializeNodeWithId(iframeDoc, {
doc: iframeDoc,
mirror,
blockClass,
blockSelector,
needsMask,
maskTextClass,
maskTextSelector,
skipChild: false,
inlineStylesheet,
maskInputOptions,
maskTextFn,
maskInputFn,
slimDOMOptions,
dataURLOptions,
inlineImages,
recordCanvas,
preserveWhiteSpace,
onSerialize,
onIframeLoad,
iframeLoadTimeout,
onStylesheetLoad,
stylesheetLoadTimeout,
keepIframeSrcFn
});
if (serializedIframeNode) {
onIframeLoad(
n,
serializedIframeNode
);
}
}
},
iframeLoadTimeout
);
}
if (serializedNode2.type === NodeType.Element && serializedNode2.tagName === "link" && typeof serializedNode2.attributes.rel === "string" && (serializedNode2.attributes.rel === "stylesheet" || serializedNode2.attributes.rel === "preload" && typeof serializedNode2.attributes.href === "string" && extractFileExtension(serializedNode2.attributes.href) === "css")) {
onceStylesheetLoaded(
n,
() => {
if (onStylesheetLoad) {
const serializedLinkNode = serializeNodeWithId(n, {
doc,
mirror,
blockClass,
blockSelector,
needsMask,
maskTextClass,
maskTextSelector,
skipChild: false,
inlineStylesheet,
maskInputOptions,
maskTextFn,
maskInputFn,
slimDOMOptions,
dataURLOptions,
inlineImages,
recordCanvas,
preserveWhiteSpace,
onSerialize,
onIframeLoad,
iframeLoadTimeout,
onStylesheetLoad,
stylesheetLoadTimeout,
keepIframeSrcFn
});
if (serializedLinkNode) {
onStylesheetLoad(
n,
serializedLinkNode
);
}
}
},
stylesheetLoadTimeout
);
}
return serializedNode2;
}
function snapshot(n, options) {
const {
mirror = new Mirror(),
blockClass = "rr-block",
blockSelector = null,
maskTextClass = "rr-mask",
maskTextSelector = null,
inlineStylesheet = true,
inlineImages = false,
recordCanvas = false,
maskAllInputs = false,
maskTextFn,
maskInputFn,
slimDOM = false,
dataURLOptions,
preserveWhiteSpace,
onSerialize,
onIframeLoad,
iframeLoadTimeout,
onStylesheetLoad,
stylesheetLoadTimeout,
keepIframeSrcFn = () => false
} = options || {};
const maskInputOptions = maskAllInputs === true ? {
color: true,
date: true,
"datetime-local": true,
email: true,
month: true,
number: true,
range: true,
search: true,
tel: true,
text: true,
time: true,
url: true,
week: true,
textarea: true,
select: true,
password: true
} : maskAllInputs === false ? {
password: true
} : maskAllInputs;
const slimDOMOptions = slimDOM === true || slimDOM === "all" ? (
// if true: set of sensible options that should not throw away any information
{
script: true,
comment: true,
headFavicon: true,
headWhitespace: true,
headMetaDescKeywords: slimDOM === "all",
// destructive
headMetaSocial: true,
headMetaRobots: true,
headMetaHttpEquiv: true,
headMetaAuthorship: true,
headMetaVerification: true
}
) : slimDOM === false ? {} : slimDOM;
return serializeNodeWithId(n, {
doc: n,
mirror,
blockClass,
blockSelector,
maskTextClass,
maskTextSelector,
skipChild: false,
inlineStylesheet,
maskInputOptions,
maskTextFn,
maskInputFn,
slimDOMOptions,
dataURLOptions,
inlineImages,
recordCanvas,
preserveWhiteSpace,
onSerialize,
onIframeLoad,
iframeLoadTimeout,
onStylesheetLoad,
stylesheetLoadTimeout,
keepIframeSrcFn,
newlyAddedElement: false
});
}
// @ts-nocheck
function getWorkerString() {
var _this = this;
var MAX_CHUNK_SIZE = 1024 * 1024; //1MB
var ERROR_MESSAGE = 'Coralogix Browser SDK - Error from session recording worker:\n';
importScriptWithFallback('https://cdn.rum-ingress-coralogix.com/coralogix/browser/latest/pako_deflate.es5.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/pako/2.1.0/pako_deflate.es5.min.js');
self.onmessage = function (_a) {
var data = _a.data;
if (!_this.pako) {
console.warn('Coralogix Browser SDK - Web worker not created due to missing pako library');
self.postMessage({
event: 'stopRecording',
});
return;
}
var recordsData;
var isScreenshot = !!data.screenshotId;
if (isScreenshot) {
recordsData = JSON.stringify(data.records);
}
else {
recordsData = omitSquareBrackets(JSON.stringify(data.records));
}
var sessionId = data.sessionId;
var sessionCreationDate = data.sessionCreationDate;
var screenshotId = data.screenshotId;
var gzipData = _this.pako.gzip(recordsData);
var gzipSize = gzipData.byteLength;
if (gzipSize >= MAX_CHUNK_SIZE) {
var totalChunks = Math.ceil(gzipSize / MAX_CHUNK_SIZE);
for (var i = 0; i < totalChunks; i++) {
var start = i * MAX_CHUNK_SIZE;
var end = (i + 1) * MAX_CHUNK_SIZE;
var chunk = gzipData.slice(start, end);
createBlobAndSend(sessionId, sessionCreationDate, chunk, i, totalChunks - 1, screenshotId, 'splitRecordData');
}
}
else {
createBlobAndSend(sessionId, sessionCreationDate, gzipData, undefined, undefined, screenshotId);
}
};
self.onerror = function (err) {
console.warn(ERROR_MESSAGE, err);
self.postMessage({
event: 'stopRecording',
});
};
function omitSquareBrackets(json) {
return json.slice(1, -1);
}
function importScriptWithFallback(url, fallbackUrl) {
try {
importScripts(url);
}
catch (err) {
try {
importScripts(fallbackUrl);
}
catch (fallbackErr) {
self.postMessage({ event: 'stopRecording' });
}
}
}
function createBlobAndSend(sessionId, sessionCreationDate, gzipData, chunkIndex, totalChunks, screenshotId, event) {
if (event === undefined) { event = 'sendRecordData'; }
var blob = new Blob([gzipData], {
type: 'application/octet-stream',
});
self.postMessage({
sessionId: sessionId,
sessionCreationDate: sessionCreationDate,
gzipBlob: blob,
chunkIndex: chunkIndex,
totalChunks: totalChunks,
screenshotId: screenshotId,
event: event,
});
}
}
var WorkerManager = /** @class */ (function () {
function WorkerManager() {
}
WorkerManager.prototype.loadAndCreateWorker = function (workerUrl) {
return __awaiter(this, undefined, undefined, function () {
var workerCode, _a, workerBlob, blobUrl, error_1;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_b.trys.push([0, 4, , 5]);
if (!workerUrl) return [3 /*break*/, 2];
return [4 /*yield*/, this.loadWorkerScript(workerUrl)];
case 1:
_a = _b.sent();
return [3 /*break*/, 3];
case 2:
_a = "(".concat(getWorkerString.toString(), ")()");
_b.label = 3;
case 3:
workerCode = _a;
workerBlob = new Blob([workerCode], {
type: 'application/javascript',
});
blobUrl = URL.createObjectURL(workerBlob);
return [2 /*return*/, new Worker(blobUrl)];
case 4:
error_1 = _b.sent();
console.warn("CoralogixRum: Error creating worker ".concat(error_1));
return [2 /*return*/, undefined];
case 5: return [2 /*return*/];
}
});
});
};
WorkerManager.prototype.loadWorkerScript = function (url) {
return __awaiter(this, undefined, undefined, function () {
var response;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 3, , 4]);
return [4 /*yield*/, fetch(this.getFullWorkerUrl(url))];
case 1:
response = _a.sent();
if (!response.ok) {
console.warn("CoralogixRum: Error fetching custom web worker");
return [2 /*return*/, ''];
}
return [4 /*yield*/, response.text()];
case 2: return [2 /*return*/, _a.sent()];
case 3:
_a.sent();
console.warn("CoralogixRum: Error fetching custom web worker");
return [2 /*return*/, ''];
case 4: return [2 /*return*/];
}
});
});
};
WorkerManager.prototype.getFullWorkerUrl = function (workerUrl) {
if (workerUrl.startsWith('http://') || workerUrl.startsWith('https://')) {
return workerUrl;
}
return "".concat(CxGlobal.location.origin).concat(workerUrl);
};
return WorkerManager;
}());
var SessionRecorder = /** @class */ (function () {
function SessionRecorder(sessionManager, recordConfig) {
var _this = this;
var _a;
this.isAutoStartRecording = false;
this.onlySessionWithErrorMode = false;
this.recordEvents = [];
this.recordEventsForSessionWithError = [[], []];
this.segmentIndexCounter = {};
this.hasRecording = false;
this.hasScreenshot = false;
this.recordingStopped = false;
this.batchTimeDelay = BATCH_TIME_DELAY;
this.isErrorOccurred = false;
this.debugMode = !!((_a = getSdkConfig()) === null || _a === undefined ? undefined : _a.debug);
this._recordingStopDueToTimeout = false;
this.handleRecordEvent = function (event, isCheckout) {
if (!_this.recordingStopped) {
if (_this.onlySessionWithErrorMode) {
_this.handleRecordEventForSessionWithError(event, isCheckout);
}
else {
_this.recordEvents.push(event);
}
}
};
this.prepareRecordEventsBeforeSend = function () {
if (_this.onlySessionWithErrorMode) {
_this.prepareRecordEventsForSessionWithError();
}
else {
if (!_this.recordEvents.length) {
return;
}
_this.compressRecordData(_this.recordEvents);
_this.resetBatching();
}
};
this.sendRecordEvents = function (workerData, shouldSplit) {
var formData = new FormData();
var metaData = _this.getMetadata(workerData, shouldSplit);
formData.append('chunk', workerData.gzipBlob);
formData.append('metaData', JSON.stringify(metaData));
var sendRecordRequest = function () { return __awaiter(_this, undefined, undefined, function () {
var response, _a;
var _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
_c.trys.push([0, 4, , 5]);
if (!!this.isErrorOccurred) return [3 /*break*/, 2];
return [4 /*yield*/, ((_b = this.request) === null || _b === undefined ? undefined : _b.send(formData))];
case 1:
_a = _c.sent();
return [3 /*break*/, 3];
case 2:
_a = undefined;
_c.label = 3;
case 3:
response = _a;
this.handleSessionRecordingResponse(response);
return [3 /*break*/, 5];
case 4:
_c.sent();
this.handleSessionRecordingResponse(undefined);
return [3 /*break*/, 5];
case 5: return [2 /*return*/];
}
});
}); };
if (shouldSplit) {
_this.batchTimeout = setTimeout(sendRecordRequest, _this.batchTimeDelay);
_this.batchTimeDelay += BATCH_TIME_DELAY;
}
else {
sendRecordRequest();
_this.batchTimeDelay = BATCH_TIME_DELAY;
}
};
CxGlobal[SESSION_RECORDER_KEY] = this;
this.sessionManager = sessionManager;
var onlySessionWithErrorMode = sessionManager.onlySessionWithErrorMode, maxRecordTimeForSessionWithError = sessionManager.maxRecordTimeForSessionWithError;
var maxMutations = recordConfig.maxMutations, autoStartSessionRecording = recordConfig.autoStartSessionRecording, workerUrl = recordConfig.workerUrl;
this.onlySessionWithErrorMode = onlySessionWithErrorMode;
this.maxRecordTimeForSessionWithError = maxRecordTimeForSessionWithError;
this.isAutoStartRecording = autoStartSessionRecording;
this.maxMutations = maxMutations !== null && maxMutations !== undefined ? maxMutations : MAX_MUTATIONS_FOR_SESSION_RECORDING;
this.recordConfig = this.prepareRecordConfig(recordConfig);
if (CxGlobal.Worker) {
this.workerManager = new WorkerManager();
this.initializeSessionWorker(workerUrl);
}
else {
if (this.debugMode) {
console.warn(SESSION_RECORDING_DEFAULT_ERROR_MESSAGE);
}
}
}
SessionRecorder.prototype.getSessionHasScreenshot = function () {
return this.hasScreenshot;
};
SessionRecorder.prototype.getSessionHasRecording = function () {
var _a;
return (this.hasRecording &&
!!this.segmentIndexCounter[(_a = this.sessionManager.getActiveSession()) === null || _a === undefined ? undefined : _a.sessionId]);
};
SessionRecorder.prototype.updateSegmentIndexCounter = function (segmentIndexCounter) {
this.segmentIndexCounter = segmentIndexCounter;
};
SessionRecorder.prototype.getIsAutoStartRecording = function () {
return this.isAutoStartRecording;
};
Object.defineProperty(SessionRecorder.prototype, "recordingStopDueToTimeout", {
get: function () {
return this._recordingStopDueToTimeout;
},
set: function (value) {
this._recordingStopDueToTimeout = value;
},
enumerable: false,
configurable: true
});
SessionRecorder.prototype.startRecording = function () {
return __awaiter(this, undefined, undefined, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.isWorkerReady];
case 1:
_a.sent();
if (!this.sessionWorker || this.recordRef) {
return [2 /*return*/];
}
if (this.debugMode) {
console.debug('Coralogix Browser SDK - Session recording started');
}
this.startMutationObserver();
this.resetBatching();
this.hasRecording = true;
this.recordingStopped = false;
this.isErrorOccurred = false;
this.recordingStopDueToTimeout = false;
this.recordRef = record(this.recordConfig);
this.startBatchingRecords();
return [2 /*return*/];
}
});
});
};
SessionRecorder.prototype.screenshot = function (id) {
this.hasScreenshot = true;
var _a = this.sessionManager.getActiveSession() || {}, sessionId = _a.sessionId, sessionCreationDate = _a.sessionCreationDate;
var snapshotRecords = snapshot(document, this.recordConfig);
if (snapshotRecords) {
this.sessionWorker.postMessage({
event: 'sendRecordData',
records: snapshotRecords,
sessionId: sessionId,
screenshotId: id,
sessionCreationDate: sessionCreationDate,
});
}
};
SessionRecorder.prototype.stopRecording = function () {
if (!this.recordRef) {
return;
}
if (this.debugMode) {
console.debug('Coralogix Browser SDK - Session recording stopped');
}
this.recordRef();
this.recordRef = undefined;
this.recordingStopped = true;
this.hasRecording = false;
this.prepareRecordEventsBeforeSend();
this.clearIntervals();
this.stopMutation