@sentry-internal/rrweb
Version:
record and replay the web
1,726 lines • 317 kB
JavaScript
var __defProp$1 = Object.defineProperty;
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
var NodeType$2 = /* @__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$2 || {});
function isElement(n2) {
return n2.nodeType === n2.ELEMENT_NODE;
}
function isShadowRoot(n2) {
const host = n2?.host;
return Boolean(host?.shadowRoot === n2);
}
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(s2) {
try {
const rules2 = s2.rules || s2.cssRules;
return rules2 ? fixBrowserCompatibilityIssuesInCSS(
Array.from(rules2, stringifyRule).join("")
) : null;
} catch (error) {
return null;
}
}
function fixAllCssProperty(rule) {
let styles = "";
for (let i2 = 0; i2 < rule.style.length; i2++) {
const styleDeclaration = rule.style;
const attribute = styleDeclaration[i2];
const isImportant = styleDeclaration.getPropertyPriority(attribute);
styles += `${attribute}:${styleDeclaration.getPropertyValue(attribute)}${isImportant ? ` !important` : ""};`;
}
return `${rule.selectorText} { ${styles} }`;
}
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)) {
let cssText = rule.cssText;
const needsSafariColonFix = rule.selectorText.includes(":");
const needsAllFix = typeof rule.style["all"] === "string" && rule.style["all"];
if (needsAllFix) {
cssText = fixAllCssProperty(rule);
}
if (needsSafariColonFix) {
cssText = fixSafariColons(cssText);
}
if (needsSafariColonFix || needsAllFix) {
return 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$1(this, "idNodeMap", /* @__PURE__ */ new Map());
__publicField$1(this, "nodeMetaMap", /* @__PURE__ */ new WeakMap());
}
getId(n2) {
if (!n2) return -1;
const id = this.getMeta(n2)?.id;
return id ?? -1;
}
getNode(id) {
return this.idNodeMap.get(id) || null;
}
getIds() {
return Array.from(this.idNodeMap.keys());
}
getMeta(n2) {
return this.nodeMetaMap.get(n2) || null;
}
// removes the node from idNodeMap
// doesn't remove the node from nodeMetaMap
removeNodeFromMap(n2) {
const id = this.getId(n2);
this.idNodeMap.delete(id);
if (n2.childNodes) {
n2.childNodes.forEach(
(childNode) => this.removeNodeFromMap(childNode)
);
}
}
has(id) {
return this.idNodeMap.has(id);
}
hasNode(node) {
return this.nodeMetaMap.has(node);
}
add(n2, meta) {
const id = meta.id;
this.idNodeMap.set(id, n2);
this.nodeMetaMap.set(n2, meta);
}
replace(id, n2) {
const oldNode = this.getNode(id);
if (oldNode) {
const meta = this.nodeMetaMap.get(oldNode);
if (meta) this.nodeMetaMap.set(n2, meta);
}
this.idNodeMap.set(id, n2);
}
reset() {
this.idNodeMap = /* @__PURE__ */ new Map();
this.nodeMetaMap = /* @__PURE__ */ new WeakMap();
}
}
function createMirror$2() {
return new Mirror();
}
function shouldMaskInput({
maskInputOptions,
tagName,
type
}) {
if (tagName === "OPTION") {
tagName = "SELECT";
}
return Boolean(
maskInputOptions[tagName.toLowerCase()] || type && maskInputOptions[type] || type === "password" || // Default to "text" option for inputs without a "type" attribute defined
tagName === "INPUT" && !type && maskInputOptions["text"]
);
}
function maskInputValue({
isMasked,
element,
value,
maskInputFn
}) {
let text = value || "";
if (!isMasked) {
return text;
}
if (maskInputFn) {
text = maskInputFn(text, element);
}
return "*".repeat(text.length);
}
function toLowerCase(str) {
return str.toLowerCase();
}
function toUpperCase(str) {
return str.toUpperCase();
}
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 isNodeMetaEqual(a2, b) {
if (!a2 || !b || a2.type !== b.type) return false;
if (a2.type === NodeType$2.Document)
return a2.compatMode === b.compatMode;
else if (a2.type === NodeType$2.DocumentType)
return a2.name === b.name && a2.publicId === b.publicId && a2.systemId === b.systemId;
else if (a2.type === NodeType$2.Comment || a2.type === NodeType$2.Text || a2.type === NodeType$2.CDATA)
return a2.textContent === b.textContent;
else if (a2.type === NodeType$2.Element)
return a2.tagName === b.tagName && JSON.stringify(a2.attributes) === JSON.stringify(b.attributes) && a2.isSVG === b.isSVG && a2.needBlock === b.needBlock;
return false;
}
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 getInputValue(el, tagName, type) {
if (tagName === "INPUT" && (type === "radio" || type === "checkbox")) {
return el.getAttribute("value") || "";
}
return el.value;
}
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?.[1] ?? null;
}
const cachedImplementations$1 = {};
function getImplementation$1(name) {
const cached = cachedImplementations$1[name];
if (cached) {
return cached;
}
const document2 = window.document;
let impl = window[name];
if (document2 && typeof document2.createElement === "function") {
try {
const sandbox = document2.createElement("iframe");
sandbox.hidden = true;
document2.head.appendChild(sandbox);
const contentWindow = sandbox.contentWindow;
if (contentWindow && contentWindow[name]) {
impl = // eslint-disable-next-line @typescript-eslint/unbound-method
contentWindow[name];
}
document2.head.removeChild(sandbox);
} catch (e2) {
}
}
return cachedImplementations$1[name] = impl.bind(
window
);
}
function setTimeout$2(...rest) {
return getImplementation$1("setTimeout")(...rest);
}
function clearTimeout$1(...rest) {
return getImplementation$1("clearTimeout")(...rest);
}
function getIframeContentDocument(iframe) {
try {
return iframe.contentDocument;
} catch (e2) {
}
}
let _id = 1;
const tagNameRegex = new RegExp("[^a-z0-9-_:]");
const IGNORED_NODE = -2;
function genId() {
return _id++;
}
function getValidTagName$1(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 chars2;
const match = regEx.exec(attributeValue.substring(pos));
if (match) {
chars2 = match[0];
pos += chars2.length;
return chars2;
}
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 c2 = attributeValue.charAt(pos);
if (c2 === "") {
output.push((url + descriptorsStr).trim());
break;
} else if (!inParens) {
if (c2 === ",") {
pos += 1;
output.push((url + descriptorsStr).trim());
break;
} else if (c2 === "(") {
inParens = true;
}
} else {
if (c2 === ")") {
inParens = false;
}
}
descriptorsStr += c2;
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 a2 = cachedDocument.get(doc);
if (!a2) {
a2 = doc.createElement("a");
cachedDocument.set(doc, a2);
}
if (!customHref) {
customHref = "";
} else if (customHref.startsWith("blob:") || customHref.startsWith("data:")) {
return customHref;
}
a2.setAttribute("href", customHref);
return a2.href;
}
function transformAttribute(doc, tagName, name, value, element, maskAttributeFn) {
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);
}
if (typeof maskAttributeFn === "function") {
return maskAttributeFn(name, value, element);
}
return value;
}
function ignoreAttribute(tagName, name, _value) {
return (tagName === "video" || tagName === "audio") && name === "autoplay";
}
function _isBlockedElement(element, blockClass, blockSelector, unblockSelector) {
try {
if (unblockSelector && element.matches(unblockSelector)) {
return false;
}
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 (e2) {
}
return false;
}
function elementClassMatchesRegex(el, regex) {
for (let eIndex = el.classList.length; eIndex--; ) {
const className = el.classList[eIndex];
if (regex.test(className)) {
return true;
}
}
return false;
}
function distanceToMatch(node, matchPredicate, limit = Infinity, distance = 0) {
if (!node) return -1;
if (node.nodeType !== node.ELEMENT_NODE) return -1;
if (distance > limit) return -1;
if (matchPredicate(node)) return distance;
return distanceToMatch(node.parentNode, matchPredicate, limit, distance + 1);
}
function createMatchPredicate(className, selector) {
return (node) => {
const el = node;
if (el === null) return false;
try {
if (className) {
if (typeof className === "string") {
if (el.matches(`.${className}`)) return true;
} else if (elementClassMatchesRegex(el, className)) {
return true;
}
}
if (selector && el.matches(selector)) return true;
return false;
} catch {
return false;
}
};
}
function needMaskingText(node, maskTextClass, maskTextSelector, unmaskTextClass, unmaskTextSelector, maskAllText) {
try {
const el = node.nodeType === node.ELEMENT_NODE ? node : node.parentElement;
if (el === null) return false;
if (el.tagName === "INPUT") {
const autocomplete = el.getAttribute("autocomplete");
const disallowedAutocompleteValues = [
"current-password",
"new-password",
"cc-number",
"cc-exp",
"cc-exp-month",
"cc-exp-year",
"cc-csc"
];
if (disallowedAutocompleteValues.includes(autocomplete)) {
return true;
}
}
let maskDistance = -1;
let unmaskDistance = -1;
if (maskAllText) {
unmaskDistance = distanceToMatch(
el,
createMatchPredicate(unmaskTextClass, unmaskTextSelector)
);
if (unmaskDistance < 0) {
return true;
}
maskDistance = distanceToMatch(
el,
createMatchPredicate(maskTextClass, maskTextSelector),
unmaskDistance >= 0 ? unmaskDistance : Infinity
);
} else {
maskDistance = distanceToMatch(
el,
createMatchPredicate(maskTextClass, maskTextSelector)
);
if (maskDistance < 0) {
return false;
}
unmaskDistance = distanceToMatch(
el,
createMatchPredicate(unmaskTextClass, unmaskTextSelector),
maskDistance >= 0 ? maskDistance : Infinity
);
}
return maskDistance >= 0 ? unmaskDistance >= 0 ? maskDistance <= unmaskDistance : true : unmaskDistance >= 0 ? false : !!maskAllText;
} catch (e2) {
}
return !!maskAllText;
}
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$2(() => {
if (!fired) {
listener();
fired = true;
}
}, iframeLoadTimeout);
iframeEl.addEventListener("load", () => {
clearTimeout$1(timer);
fired = true;
listener();
});
return;
}
const blankUrl = "about:blank";
if (win.location.href !== blankUrl || iframeEl.src === blankUrl || iframeEl.src === "") {
setTimeout$2(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$2(() => {
if (!fired) {
listener();
fired = true;
}
}, styleSheetLoadTimeout);
link.addEventListener("load", () => {
clearTimeout$1(timer);
fired = true;
listener();
});
}
function serializeNode(n2, options) {
const {
doc,
mirror: mirror2,
blockClass,
blockSelector,
unblockSelector,
maskAllText,
maskAttributeFn,
maskTextClass,
unmaskTextClass,
maskTextSelector,
unmaskTextSelector,
inlineStylesheet,
maskInputOptions = {},
maskTextFn,
maskInputFn,
dataURLOptions = {},
inlineImages,
recordCanvas,
keepIframeSrcFn,
newlyAddedElement = false
} = options;
const rootId = getRootId(doc, mirror2);
switch (n2.nodeType) {
case n2.DOCUMENT_NODE:
if (n2.compatMode !== "CSS1Compat") {
return {
type: NodeType$2.Document,
childNodes: [],
compatMode: n2.compatMode
// probably "BackCompat"
};
} else {
return {
type: NodeType$2.Document,
childNodes: []
};
}
case n2.DOCUMENT_TYPE_NODE:
return {
type: NodeType$2.DocumentType,
name: n2.name,
publicId: n2.publicId,
systemId: n2.systemId,
rootId
};
case n2.ELEMENT_NODE:
return serializeElementNode(n2, {
doc,
blockClass,
blockSelector,
unblockSelector,
inlineStylesheet,
maskAttributeFn,
maskInputOptions,
maskInputFn,
dataURLOptions,
inlineImages,
recordCanvas,
keepIframeSrcFn,
newlyAddedElement,
rootId,
maskAllText,
maskTextClass,
unmaskTextClass,
maskTextSelector,
unmaskTextSelector
});
case n2.TEXT_NODE:
return serializeTextNode(n2, {
doc,
maskAllText,
maskTextClass,
unmaskTextClass,
maskTextSelector,
unmaskTextSelector,
maskTextFn,
maskInputOptions,
maskInputFn,
rootId
});
case n2.CDATA_SECTION_NODE:
return {
type: NodeType$2.CDATA,
textContent: "",
rootId
};
case n2.COMMENT_NODE:
return {
type: NodeType$2.Comment,
textContent: n2.textContent || "",
rootId
};
default:
return false;
}
}
function getRootId(doc, mirror2) {
if (!mirror2.hasNode(doc)) return void 0;
const docId = mirror2.getId(doc);
return docId === 1 ? void 0 : docId;
}
function serializeTextNode(n2, options) {
const {
maskAllText,
maskTextClass,
unmaskTextClass,
maskTextSelector,
unmaskTextSelector,
maskTextFn,
maskInputOptions,
maskInputFn,
rootId
} = options;
const parentTagName = n2.parentNode && n2.parentNode.tagName;
let textContent = n2.textContent;
const isStyle = parentTagName === "STYLE" ? true : void 0;
const isScript = parentTagName === "SCRIPT" ? true : void 0;
const isTextarea = parentTagName === "TEXTAREA" ? true : void 0;
if (isStyle && textContent) {
try {
if (n2.nextSibling || n2.previousSibling) {
} else if (n2.parentNode.sheet?.cssRules) {
textContent = stringifyStylesheet(
n2.parentNode.sheet
);
}
} catch (err) {
console.warn(
`Cannot get CSS styles from text's parentNode. Error: ${err}`,
n2
);
}
textContent = absoluteToStylesheet(textContent, getHref(options.doc));
}
if (isScript) {
textContent = "SCRIPT_PLACEHOLDER";
}
const forceMask = needMaskingText(
n2,
maskTextClass,
maskTextSelector,
unmaskTextClass,
unmaskTextSelector,
maskAllText
);
if (!isStyle && !isScript && !isTextarea && textContent && forceMask) {
textContent = maskTextFn ? maskTextFn(textContent, n2.parentElement) : textContent.replace(/[\S]/g, "*");
}
if (isTextarea && textContent && (maskInputOptions.textarea || forceMask)) {
textContent = maskInputFn ? maskInputFn(textContent, n2.parentNode) : textContent.replace(/[\S]/g, "*");
}
if (parentTagName === "OPTION" && textContent) {
const isInputMasked = shouldMaskInput({
type: null,
tagName: parentTagName,
maskInputOptions
});
textContent = maskInputValue({
isMasked: needMaskingText(
n2,
maskTextClass,
maskTextSelector,
unmaskTextClass,
unmaskTextSelector,
isInputMasked
),
element: n2,
value: textContent,
maskInputFn
});
}
return {
type: NodeType$2.Text,
textContent: textContent || "",
isStyle,
rootId
};
}
function serializeElementNode(n2, options) {
const {
doc,
blockClass,
blockSelector,
unblockSelector,
inlineStylesheet,
maskInputOptions = {},
maskAttributeFn,
maskInputFn,
dataURLOptions = {},
inlineImages,
recordCanvas,
keepIframeSrcFn,
newlyAddedElement = false,
rootId,
maskTextClass,
unmaskTextClass,
maskTextSelector,
unmaskTextSelector
} = options;
const needBlock = _isBlockedElement(
n2,
blockClass,
blockSelector,
unblockSelector
);
const tagName = getValidTagName$1(n2);
let attributes2 = {};
const len = n2.attributes.length;
for (let i2 = 0; i2 < len; i2++) {
const attr = n2.attributes[i2];
if (attr.name && !ignoreAttribute(tagName, attr.name, attr.value)) {
attributes2[attr.name] = transformAttribute(
doc,
tagName,
toLowerCase(attr.name),
attr.value,
n2,
maskAttributeFn
);
}
}
if (tagName === "link" && inlineStylesheet) {
const stylesheet = Array.from(doc.styleSheets).find((s2) => {
return s2.href === n2.href;
});
let cssText = null;
if (stylesheet) {
cssText = stringifyStylesheet(stylesheet);
}
if (cssText) {
attributes2.rel = null;
attributes2.href = null;
attributes2.crossorigin = null;
attributes2._cssText = absoluteToStylesheet(cssText, stylesheet.href);
}
}
if (tagName === "style" && n2.sheet && // TODO: Currently we only try to get dynamic stylesheet when it is an empty style element
!(n2.innerText || n2.textContent || "").trim().length) {
const cssText = stringifyStylesheet(
n2.sheet
);
if (cssText) {
attributes2._cssText = absoluteToStylesheet(cssText, getHref(doc));
}
}
if (tagName === "input" || tagName === "textarea" || tagName === "select" || tagName === "option") {
const el = n2;
const type = getInputType(el);
const value = getInputValue(el, toUpperCase(tagName), type);
const checked = el.checked;
if (type !== "submit" && type !== "button" && value) {
const forceMask = needMaskingText(
el,
maskTextClass,
maskTextSelector,
unmaskTextClass,
unmaskTextSelector,
shouldMaskInput({
type,
tagName: toUpperCase(tagName),
maskInputOptions
})
);
attributes2.value = maskInputValue({
isMasked: forceMask,
element: el,
value,
maskInputFn
});
}
if (checked) {
attributes2.checked = checked;
}
}
if (tagName === "option") {
if (n2.selected && !maskInputOptions["select"]) {
attributes2.selected = true;
} else {
delete attributes2.selected;
}
}
if (tagName === "canvas" && recordCanvas) {
if (n2.__context === "2d") {
if (!is2DCanvasBlank(n2)) {
attributes2.rr_dataURL = n2.toDataURL(
dataURLOptions.type,
dataURLOptions.quality
);
}
} else if (!("__context" in n2)) {
const canvasDataURL = n2.toDataURL(
dataURLOptions.type,
dataURLOptions.quality
);
const blankCanvas = doc.createElement("canvas");
blankCanvas.width = n2.width;
blankCanvas.height = n2.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 = n2;
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") {
attributes2.rr_mediaState = n2.paused ? "paused" : "played";
attributes2.rr_mediaCurrentTime = n2.currentTime;
}
if (!newlyAddedElement) {
if (n2.scrollLeft) {
attributes2.rr_scrollLeft = n2.scrollLeft;
}
if (n2.scrollTop) {
attributes2.rr_scrollTop = n2.scrollTop;
}
}
if (needBlock) {
const { width, height } = n2.getBoundingClientRect();
attributes2 = {
class: attributes2.class,
rr_width: `${width}px`,
rr_height: `${height}px`
};
}
if (tagName === "iframe" && !keepIframeSrcFn(attributes2.src)) {
if (!needBlock && !getIframeContentDocument(n2)) {
attributes2.rr_src = attributes2.src;
}
delete attributes2.src;
}
let isCustomElement;
try {
if (customElements.get(tagName)) isCustomElement = true;
} catch (e2) {
}
return {
type: NodeType$2.Element,
tagName,
attributes: attributes2,
childNodes: [],
isSVG: isSVGElement(n2) || void 0,
needBlock,
rootId,
isCustom: isCustomElement
};
}
function lowerIfExists(maybeAttr) {
if (maybeAttr === void 0 || maybeAttr === null) {
return "";
} else {
return maybeAttr.toLowerCase();
}
}
function slimDOMExcluded(sn, slimDOMOptions) {
if (slimDOMOptions.comment && sn.type === NodeType$2.Comment) {
return true;
} else if (sn.type === NodeType$2.Element) {
if (slimDOMOptions.script && // script tag
(sn.tagName === "script" || // (module)preload link
sn.tagName === "link" && (sn.attributes.rel === "preload" || sn.attributes.rel === "modulepreload") || // 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"] !== void 0) {
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(n2, options) {
const {
doc,
mirror: mirror2,
blockClass,
blockSelector,
unblockSelector,
maskAllText,
maskTextClass,
unmaskTextClass,
maskTextSelector,
unmaskTextSelector,
skipChild = false,
inlineStylesheet = true,
maskInputOptions = {},
maskAttributeFn,
maskTextFn,
maskInputFn,
slimDOMOptions,
dataURLOptions = {},
inlineImages = false,
recordCanvas = false,
onSerialize,
onIframeLoad,
iframeLoadTimeout = 5e3,
onStylesheetLoad,
stylesheetLoadTimeout = 5e3,
keepIframeSrcFn = () => false,
newlyAddedElement = false
} = options;
let { preserveWhiteSpace = true } = options;
const _serializedNode = serializeNode(n2, {
doc,
mirror: mirror2,
blockClass,
blockSelector,
maskAllText,
unblockSelector,
maskTextClass,
unmaskTextClass,
maskTextSelector,
unmaskTextSelector,
inlineStylesheet,
maskInputOptions,
maskAttributeFn,
maskTextFn,
maskInputFn,
dataURLOptions,
inlineImages,
recordCanvas,
keepIframeSrcFn,
newlyAddedElement
});
if (!_serializedNode) {
console.warn(n2, "not serialized");
return null;
}
let id;
if (mirror2.hasNode(n2)) {
id = mirror2.getId(n2);
} else if (slimDOMExcluded(_serializedNode, slimDOMOptions) || !preserveWhiteSpace && _serializedNode.type === NodeType$2.Text && !_serializedNode.isStyle && !_serializedNode.textContent.replace(/^\s+|\s+$/gm, "").length) {
id = IGNORED_NODE;
} else {
id = genId();
}
const serializedNode2 = Object.assign(_serializedNode, { id });
mirror2.add(n2, serializedNode2);
if (id === IGNORED_NODE) {
return null;
}
if (onSerialize) {
onSerialize(n2);
}
let recordChild = !skipChild;
if (serializedNode2.type === NodeType$2.Element) {
recordChild = recordChild && !serializedNode2.needBlock;
delete serializedNode2.needBlock;
const shadowRoot = n2.shadowRoot;
if (shadowRoot && isNativeShadowDom(shadowRoot))
serializedNode2.isShadowHost = true;
}
if ((serializedNode2.type === NodeType$2.Document || serializedNode2.type === NodeType$2.Element) && recordChild) {
if (slimDOMOptions.headWhitespace && serializedNode2.type === NodeType$2.Element && serializedNode2.tagName === "head") {
preserveWhiteSpace = false;
}
const bypassOptions = {
doc,
mirror: mirror2,
blockClass,
blockSelector,
maskAllText,
unblockSelector,
maskTextClass,
unmaskTextClass,
maskTextSelector,
unmaskTextSelector,
skipChild,
inlineStylesheet,
maskInputOptions,
maskAttributeFn,
maskTextFn,
maskInputFn,
slimDOMOptions,
dataURLOptions,
inlineImages,
recordCanvas,
preserveWhiteSpace,
onSerialize,
onIframeLoad,
iframeLoadTimeout,
onStylesheetLoad,
stylesheetLoadTimeout,
keepIframeSrcFn
};
for (const childN of Array.from(n2.childNodes)) {
const serializedChildNode = serializeNodeWithId(childN, bypassOptions);
if (serializedChildNode) {
serializedNode2.childNodes.push(serializedChildNode);
}
}
if (isElement(n2) && n2.shadowRoot) {
for (const childN of Array.from(n2.shadowRoot.childNodes)) {
const serializedChildNode = serializeNodeWithId(childN, bypassOptions);
if (serializedChildNode) {
isNativeShadowDom(n2.shadowRoot) && (serializedChildNode.isShadow = true);
serializedNode2.childNodes.push(serializedChildNode);
}
}
}
}
if (n2.parentNode && isShadowRoot(n2.parentNode) && isNativeShadowDom(n2.parentNode)) {
serializedNode2.isShadow = true;
}
if (serializedNode2.type === NodeType$2.Element && serializedNode2.tagName === "iframe" && !_isBlockedElement(
n2,
blockClass,
blockSelector,
unblockSelector
)) {
onceIframeLoaded(
n2,
() => {
const iframeDoc = getIframeContentDocument(n2);
if (iframeDoc && onIframeLoad) {
const serializedIframeNode = serializeNodeWithId(iframeDoc, {
doc: iframeDoc,
mirror: mirror2,
blockClass,
blockSelector,
unblockSelector,
maskAllText,
maskTextClass,
unmaskTextClass,
maskTextSelector,
unmaskTextSelector,
skipChild: false,
inlineStylesheet,
maskInputOptions,
maskAttributeFn,
maskTextFn,
maskInputFn,
slimDOMOptions,
dataURLOptions,
inlineImages,
recordCanvas,
preserveWhiteSpace,
onSerialize,
onIframeLoad,
iframeLoadTimeout,
onStylesheetLoad,
stylesheetLoadTimeout,
keepIframeSrcFn
});
if (serializedIframeNode) {
onIframeLoad(
n2,
serializedIframeNode
);
}
}
},
iframeLoadTimeout
);
}
if (serializedNode2.type === NodeType$2.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(
n2,
() => {
if (onStylesheetLoad) {
const serializedLinkNode = serializeNodeWithId(n2, {
doc,
mirror: mirror2,
blockClass,
blockSelector,
unblockSelector,
maskAllText,
maskTextClass,
unmaskTextClass,
maskTextSelector,
unmaskTextSelector,
skipChild: false,
inlineStylesheet,
maskInputOptions,
maskAttributeFn,
maskTextFn,
maskInputFn,
slimDOMOptions,
dataURLOptions,
inlineImages,
recordCanvas,
preserveWhiteSpace,
onSerialize,
onIframeLoad,
iframeLoadTimeout,
onStylesheetLoad,
stylesheetLoadTimeout,
keepIframeSrcFn
});
if (serializedLinkNode) {
onStylesheetLoad(
n2,
serializedLinkNode
);
}
}
},
stylesheetLoadTimeout
);
}
return serializedNode2;
}
function snapshot(n2, options) {
const {
mirror: mirror2 = new Mirror(),
blockClass = "rr-block",
blockSelector = null,
unblockSelector = null,
maskAllText = false,
maskTextClass = "rr-mask",
unmaskTextClass = null,
maskTextSelector = null,
unmaskTextSelector = null,
inlineStylesheet = true,
inlineImages = false,
recordCanvas = false,
maskAllInputs = false,
maskAttributeFn,
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
} : maskAllInputs === false ? {} : 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(n2, {
doc: n2,
mirror: mirror2,
blockClass,
blockSelector,
unblockSelector,
maskAllText,
maskTextClass,
unmaskTextClass,
maskTextSelector,
unmaskTextSelector,
skipChild: false,
inlineStylesheet,
maskInputOptions,
maskAttributeFn,
maskTextFn,
maskInputFn,
slimDOMOptions,
dataURLOptions,
inlineImages,
recordCanvas,
preserveWhiteSpace,
onSerialize,
onIframeLoad,
iframeLoadTimeout,
onStylesheetLoad,
stylesheetLoadTimeout,
keepIframeSrcFn,
newlyAddedElement: false
});
}
const commentre = /\/\*[^*]*\*+([^/*][^*]*\*+)*\//g;
function parse(css, options = {}) {
let lineno = 1;
let column = 1;
function updatePosition(str) {
const lines = str.match(/\n/g);
if (lines) {
lineno += lines.length;
}
const i2 = str.lastIndexOf("\n");
column = i2 === -1 ? column + str.length : str.length - i2;
}
function position() {
const start = { line: lineno, column };
return (node) => {
node.position = new Position(start);
whitespace();
return node;
};
}
const _Position = class _Position2 {
constructor(start) {
__publicField$1(this, "content");
__publicField$1(this, "start");
__publicField$1(this, "end");
__publicField$1(this, "source");
this.start = start;
this.end = { line: lineno, column };
this.source = options.source;
this.content = _Position2.content;
}
};
__publicField$1(_Position, "content");
let Position = _Position;
Position.content = css;
const errorsList = [];
function error(msg) {
const err = new Error(
`${options.source || ""}:${lineno}:${column}: ${msg}`
);
err.reason = msg;
err.filename = options.source;
err.line = lineno;
err.column = column;
err.source = css;
if (options.silent) {
errorsList.push(err);
} else {
throw err;
}
}
function stylesheet() {
const rulesList = rules2();
return {
type: "stylesheet",
stylesheet: {
source: options.source,
rules: rulesList,
parsingErrors: errorsList
}
};
}
function open() {
return match(/^{\s*/);
}
function close() {
return match(/^}/);
}
function rules2() {
let node;
const rules22 = [];
whitespace();
comments(rules22);
while (css.length && css.charAt(0) !== "}" && (node = atrule() || rule())) {
if (node) {
rules22.push(node);
comments(rules22);
}
}
return rules22;
}
function match(re) {
const m = re.exec(css);
if (!m) {
return;
}
const str = m[0];
updatePosition(str);
css = css.slice(str.length);
return m;
}
function whitespace() {
match(/^\s*/);
}
function comments(rules22 = []) {
let c2;
while (c2 = comment()) {
if (c2) {
rules22.push(c2);
}
c2 = comment();
}
return rules22;
}
function comment() {
const pos = position();
if ("/" !== css.charAt(0) || "*" !== css.charAt(1)) {
return;
}
let i2 = 2;
while ("" !== css.charAt(i2) && ("*" !== css.charAt(i2) || "/" !== css.charAt(i2 + 1))) {
++i2;
}
i2 += 2;
if ("" === css.charAt(i2 - 1)) {
return error("End of comment missing");
}
const str = css.slice(2, i2 - 2);
column += 2;
updatePosition(str);
css = css.slice(i2);
column += 2;
return pos({
type: "comment",
comment: str
});
}
function selector() {
const m = match(/^([^{]+)/);
if (!m) {
return;
}
const splitSelectors = trim(m[0]).replace(/\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*\/+/g, "").replace(/"(?:\\"|[^"])*"|'(?:\\'|[^'])*'/g, (m2) => {
return m2.replace(/,/g, "");
}).split(/\s*(?![^(]*\)),\s*/);
if (splitSelectors.length <= 1) {
return splitSelectors.map((s2) => {
return s2.replace(/\u200C/g, ",");
});
}
let i2 = 0;
let j = 0;
const len = splitSelectors.length;
const finalSelectors = [];
while (i2 < len) {
const openingParensCount = (splitSelectors[i2].match(/\(/g) || []).length;
const closingParensCount = (splitSelectors[i2].match(/\)/g) || []).length;
let unbalancedParens = openingParensCount - closingParensCount;
if (unbalancedParens >= 1) {
let foundClosingSelector = false;
j = i2 + 1;
while (j < len) {
const nextOpeningParensCount = (splitSelectors[j].match(/\(/g) || []).length;
const nextClosingParensCount = (splitSelectors[j].match(/\)/g) || []).length;
const nextUnbalancedParens = nextClosingParensCount - nextOpeningParensCount;
if (nextUnbalancedParens === unbalancedParens) {
finalSelectors.push(splitSelectors.slice(i2, j + 1).join(","));
i2 = j + 1;
foundClosingSelector = true;
break;
}
j++;
unbalancedParens -= nextUnbalancedParens;
}
if (foundClosingSelector) {
continue;
}
splitSelectors.slice(i2, len).forEach((selector2) => selector2 && finalSelectors.push(selector2));
break;
}
splitSelectors[i2] && finalSelectors.push(splitSelectors[i2]);
i2++;
}
return finalSelectors.map((s2) => {
return s2.replace(/\u200C/g, ",");
});
}
function declaration() {
const pos = position();
const propMatch = match(/^(\*?[-#\/\*\\\w]+(\[[0-9a-z_-]+\])?)\s*/);
if (!propMatch) {
return;
}
const prop = trim(propMatch[0]);
if (!match(/^:\s*/)) {
return error(`property missing ':'`);
}
const val = match(/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)/);
const ret = pos({
type: "declaration",
property: prop.replace(commentre, ""),
value: val ? trim(val[0]).replace(commentre, "") : ""
});
match(/^[;\s]*/);
return ret;
}
function declarations() {
const decls = [];
if (!open()) {
return error(`missing '{'`);
}
comments(decls);
let decl;
while (decl = declaration()) {
if (decl !== false) {
decls.push(decl);
comments(decls);
}
decl = declaration();
}
if (!close()) {
return error(`missing '}'`);
}
return decls;
}
function keyframe() {
let m;
const vals = [];
const pos = position();
while (m = match(/^((\d+\.\d+|\.\d+|\d+)%?|[a-z]+)\s*/)) {
vals.push(m[1]);
match(/^,\s*/);
}
if (!vals.length) {
return;
}
return pos({
type: "keyframe",
values: vals,
declarations: declarations()
});
}
function atkeyframes() {
const pos = position();
let m = match(/^@([-\w]+)?keyframes\s*/);
if (!m) {
return;
}
const vendor = m[1];
m = match(/^([-\w]+)\s*/);
if (!m) {
return error("@keyframes missing name");
}
const name = m[1];
if (!open()) {
return error(`@keyframes missing '{'`);
}
let frame;
let frames = comments();
while (frame = keyframe()) {
frames.push(frame);
frames = frames.concat(comments());
}
if (!close()) {
return error(`@keyframes missing '}'`);
}
return pos({
type: "keyframes",
name,
vendor,
keyframes: frames
});
}
function atsupports() {
const pos = position();
const m = match(/^@supports *([^{]+)/);
if (!m) {
return;
}
const supports = trim(m[1]);
if (!open()) {
return error(`@supports missing '{'`);
}
const style = comments().concat(rules2());
if (!close()) {
return error(`@supports missing '}'`);
}
return pos({
type: "supports",
supports,
rules: style
});
}
function athost() {
const pos = position();
const m = match(/^@host\s*/);
if (!m) {
return;
}
if (!open()) {
return error(`@host missing '{'`);
}
const style = comments().concat(rules2());
if (!close()) {
return error(`@host missing '}'`);
}
return pos({
type: "host",
rules: style
});
}
function atmedia() {
const pos = position();
const m = match(/^@media *([^{]+)/);
if (!m) {
return;
}
const media = trim(m[1]);
if (!open()) {
return error(`@media missing '{'`);
}
const style = comments().concat(rules2());
if (!close()) {
return error(`@media missing '}'`);
}
return pos({
type: "media",
media,
rules: style
});
}
function atcustommedia() {
const pos = position();
const m = match(/^@custom-media\s+(--[^\s]+)\s*([^{;]+);/);
if (!m) {
return;
}
return pos({
type: "custom-media",
name: trim(m[1]),
media: trim(m[2])
});
}
function atpage() {
const pos = position();
const m = match(/^@page */);
if (!m) {
return;
}
const sel = selector() || [];
if (!open()) {
return error(`@page missing '{'`);
}
let decls = comments();
let decl;
while (decl = declarati