UNPKG

@sentry-internal/rrweb

Version:
1 lines 435 kB
{"version":3,"file":"rrweb.cjs","sources":["../../rrdom/dist/rrdom.js","../src/record/style-declaration-parser.ts","../src/record/mutation.ts","../src/record/observer.ts","../src/record/cross-origin-iframe-mirror.ts","../src/record/iframe-manager.ts","../src/record/shadow-dom-manager.ts","../src/record/stylesheet-manager.ts","../src/record/processed-node-manager.ts","../src/record/index.ts","../../../node_modules/mitt/dist/mitt.mjs","../src/replay/smoothscroll.ts","../src/replay/timer.ts","../../../node_modules/@xstate/fsm/es/index.js","../src/replay/machine.ts","../src/replay/styles/inject-style.ts","../src/replay/canvas/deserialize-args.ts","../src/replay/canvas/webgl.ts","../src/replay/canvas/2d.ts","../src/replay/canvas/index.ts","../src/replay/index.ts"],"sourcesContent":["var __defProp = Object.defineProperty;\nvar __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;\nvar __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== \"symbol\" ? key + \"\" : key, value);\nvar __defProp2 = Object.defineProperty;\nvar __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;\nvar __publicField2 = (obj, key, value) => __defNormalProp2(obj, typeof key !== \"symbol\" ? key + \"\" : key, value);\nvar NodeType$1 = /* @__PURE__ */ ((NodeType2) => {\n NodeType2[NodeType2[\"Document\"] = 0] = \"Document\";\n NodeType2[NodeType2[\"DocumentType\"] = 1] = \"DocumentType\";\n NodeType2[NodeType2[\"Element\"] = 2] = \"Element\";\n NodeType2[NodeType2[\"Text\"] = 3] = \"Text\";\n NodeType2[NodeType2[\"CDATA\"] = 4] = \"CDATA\";\n NodeType2[NodeType2[\"Comment\"] = 5] = \"Comment\";\n return NodeType2;\n})(NodeType$1 || {});\nlet Mirror$1 = class Mirror {\n constructor() {\n __publicField2(this, \"idNodeMap\", /* @__PURE__ */ new Map());\n __publicField2(this, \"nodeMetaMap\", /* @__PURE__ */ new WeakMap());\n }\n getId(n) {\n if (!n) return -1;\n const id = this.getMeta(n)?.id;\n return id ?? -1;\n }\n getNode(id) {\n return this.idNodeMap.get(id) || null;\n }\n getIds() {\n return Array.from(this.idNodeMap.keys());\n }\n getMeta(n) {\n return this.nodeMetaMap.get(n) || null;\n }\n // removes the node from idNodeMap\n // doesn't remove the node from nodeMetaMap\n removeNodeFromMap(n) {\n const id = this.getId(n);\n this.idNodeMap.delete(id);\n if (n.childNodes) {\n n.childNodes.forEach(\n (childNode) => this.removeNodeFromMap(childNode)\n );\n }\n }\n has(id) {\n return this.idNodeMap.has(id);\n }\n hasNode(node) {\n return this.nodeMetaMap.has(node);\n }\n add(n, meta) {\n const id = meta.id;\n this.idNodeMap.set(id, n);\n this.nodeMetaMap.set(n, meta);\n }\n replace(id, n) {\n const oldNode = this.getNode(id);\n if (oldNode) {\n const meta = this.nodeMetaMap.get(oldNode);\n if (meta) this.nodeMetaMap.set(n, meta);\n }\n this.idNodeMap.set(id, n);\n }\n reset() {\n this.idNodeMap = /* @__PURE__ */ new Map();\n this.nodeMetaMap = /* @__PURE__ */ new WeakMap();\n }\n};\nfunction createMirror$1() {\n return new Mirror$1();\n}\nfunction parseCSSText(cssText) {\n const res = {};\n const listDelimiter = /;(?![^(]*\\))/g;\n const propertyDelimiter = /:(.+)/;\n const comment = /\\/\\*.*?\\*\\//g;\n cssText.replace(comment, \"\").split(listDelimiter).forEach(function(item) {\n if (item) {\n const tmp = item.split(propertyDelimiter);\n tmp.length > 1 && (res[camelize(tmp[0].trim())] = tmp[1].trim());\n }\n });\n return res;\n}\nfunction toCSSText(style) {\n const properties = [];\n for (const name in style) {\n const value = style[name];\n if (typeof value !== \"string\") continue;\n const normalizedName = hyphenate(name);\n properties.push(`${normalizedName}: ${value};`);\n }\n return properties.join(\" \");\n}\nconst camelizeRE = /-([a-z])/g;\nconst CUSTOM_PROPERTY_REGEX = /^--[a-zA-Z0-9-]+$/;\nconst camelize = (str) => {\n if (CUSTOM_PROPERTY_REGEX.test(str)) return str;\n return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : \"\");\n};\nconst hyphenateRE = /\\B([A-Z])/g;\nconst hyphenate = (str) => {\n return str.replace(hyphenateRE, \"-$1\").toLowerCase();\n};\nclass BaseRRNode {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any\n constructor(..._args) {\n __publicField(this, \"parentElement\", null);\n __publicField(this, \"parentNode\", null);\n __publicField(this, \"ownerDocument\");\n __publicField(this, \"firstChild\", null);\n __publicField(this, \"lastChild\", null);\n __publicField(this, \"previousSibling\", null);\n __publicField(this, \"nextSibling\", null);\n __publicField(this, \"ELEMENT_NODE\", 1);\n __publicField(this, \"TEXT_NODE\", 3);\n // corresponding nodeType value of standard HTML Node\n __publicField(this, \"nodeType\");\n __publicField(this, \"nodeName\");\n __publicField(this, \"RRNodeType\");\n }\n get childNodes() {\n const childNodes = [];\n let childIterator = this.firstChild;\n while (childIterator) {\n childNodes.push(childIterator);\n childIterator = childIterator.nextSibling;\n }\n return childNodes;\n }\n contains(node) {\n if (!(node instanceof BaseRRNode)) return false;\n else if (node.ownerDocument !== this.ownerDocument) return false;\n else if (node === this) return true;\n while (node.parentNode) {\n if (node.parentNode === this) return true;\n node = node.parentNode;\n }\n return false;\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n appendChild(_newChild) {\n throw new Error(\n `RRDomException: Failed to execute 'appendChild' on 'RRNode': This RRNode type does not support this method.`\n );\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n insertBefore(_newChild, _refChild) {\n throw new Error(\n `RRDomException: Failed to execute 'insertBefore' on 'RRNode': This RRNode type does not support this method.`\n );\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n removeChild(_node) {\n throw new Error(\n `RRDomException: Failed to execute 'removeChild' on 'RRNode': This RRNode type does not support this method.`\n );\n }\n toString() {\n return \"RRNode\";\n }\n}\nclass BaseRRDocument extends BaseRRNode {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n constructor(...args) {\n super(args);\n __publicField(this, \"nodeType\", 9);\n __publicField(this, \"nodeName\", \"#document\");\n __publicField(this, \"compatMode\", \"CSS1Compat\");\n __publicField(this, \"RRNodeType\", NodeType$1.Document);\n __publicField(this, \"textContent\", null);\n this.ownerDocument = this;\n }\n get documentElement() {\n return this.childNodes.find(\n (node) => node.RRNodeType === NodeType$1.Element && node.tagName === \"HTML\"\n ) || null;\n }\n get body() {\n return this.documentElement?.childNodes.find(\n (node) => node.RRNodeType === NodeType$1.Element && node.tagName === \"BODY\"\n ) || null;\n }\n get head() {\n return this.documentElement?.childNodes.find(\n (node) => node.RRNodeType === NodeType$1.Element && node.tagName === \"HEAD\"\n ) || null;\n }\n get implementation() {\n return this;\n }\n get firstElementChild() {\n return this.documentElement;\n }\n appendChild(newChild) {\n const nodeType = newChild.RRNodeType;\n if (nodeType === NodeType$1.Element || nodeType === NodeType$1.DocumentType) {\n if (this.childNodes.some((s) => s.RRNodeType === nodeType)) {\n throw new Error(\n `RRDomException: Failed to execute 'appendChild' on 'RRNode': Only one ${nodeType === NodeType$1.Element ? \"RRElement\" : \"RRDoctype\"} on RRDocument allowed.`\n );\n }\n }\n const child = appendChild(this, newChild);\n child.parentElement = null;\n return child;\n }\n insertBefore(newChild, refChild) {\n const nodeType = newChild.RRNodeType;\n if (nodeType === NodeType$1.Element || nodeType === NodeType$1.DocumentType) {\n if (this.childNodes.some((s) => s.RRNodeType === nodeType)) {\n throw new Error(\n `RRDomException: Failed to execute 'insertBefore' on 'RRNode': Only one ${nodeType === NodeType$1.Element ? \"RRElement\" : \"RRDoctype\"} on RRDocument allowed.`\n );\n }\n }\n const child = insertBefore(this, newChild, refChild);\n child.parentElement = null;\n return child;\n }\n removeChild(node) {\n return removeChild(this, node);\n }\n open() {\n this.firstChild = null;\n this.lastChild = null;\n }\n close() {\n }\n /**\n * Adhoc implementation for setting xhtml namespace in rebuilt.ts (rrweb-snapshot).\n * There are two lines used this function:\n * 1. doc.write('\\<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"\"\\>')\n * 2. doc.write('\\<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"\"\\>')\n */\n write(content) {\n let publicId;\n if (content === '<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"\">')\n publicId = \"-//W3C//DTD XHTML 1.0 Transitional//EN\";\n else if (content === '<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"\">')\n publicId = \"-//W3C//DTD HTML 4.0 Transitional//EN\";\n if (publicId) {\n const doctype = this.createDocumentType(\"html\", publicId, \"\");\n this.open();\n this.appendChild(doctype);\n }\n }\n createDocument(_namespace, _qualifiedName, _doctype) {\n return new BaseRRDocument();\n }\n createDocumentType(qualifiedName, publicId, systemId) {\n const doctype = new BaseRRDocumentType(qualifiedName, publicId, systemId);\n doctype.ownerDocument = this;\n return doctype;\n }\n createElement(tagName) {\n const element = new BaseRRElement(tagName);\n element.ownerDocument = this;\n return element;\n }\n createElementNS(_namespaceURI, qualifiedName) {\n return this.createElement(qualifiedName);\n }\n createTextNode(data) {\n const text = new BaseRRText(data);\n text.ownerDocument = this;\n return text;\n }\n createComment(data) {\n const comment = new BaseRRComment(data);\n comment.ownerDocument = this;\n return comment;\n }\n createCDATASection(data) {\n const CDATASection = new BaseRRCDATASection(data);\n CDATASection.ownerDocument = this;\n return CDATASection;\n }\n toString() {\n return \"RRDocument\";\n }\n}\nclass BaseRRDocumentType extends BaseRRNode {\n constructor(qualifiedName, publicId, systemId) {\n super();\n __publicField(this, \"nodeType\", 10);\n __publicField(this, \"RRNodeType\", NodeType$1.DocumentType);\n __publicField(this, \"name\");\n __publicField(this, \"publicId\");\n __publicField(this, \"systemId\");\n __publicField(this, \"textContent\", null);\n this.name = qualifiedName;\n this.publicId = publicId;\n this.systemId = systemId;\n this.nodeName = qualifiedName;\n }\n toString() {\n return \"RRDocumentType\";\n }\n}\nclass BaseRRElement extends BaseRRNode {\n constructor(tagName) {\n super();\n __publicField(this, \"nodeType\", 1);\n __publicField(this, \"RRNodeType\", NodeType$1.Element);\n __publicField(this, \"tagName\");\n __publicField(this, \"attributes\", {});\n __publicField(this, \"shadowRoot\", null);\n __publicField(this, \"scrollLeft\");\n __publicField(this, \"scrollTop\");\n this.tagName = tagName.toUpperCase();\n this.nodeName = tagName.toUpperCase();\n }\n get textContent() {\n let result = \"\";\n this.childNodes.forEach((node) => result += node.textContent);\n return result;\n }\n set textContent(textContent) {\n this.firstChild = null;\n this.lastChild = null;\n this.appendChild(this.ownerDocument.createTextNode(textContent));\n }\n get classList() {\n return new ClassList(\n this.attributes.class,\n (newClassName) => {\n this.attributes.class = newClassName;\n }\n );\n }\n get id() {\n return this.attributes.id || \"\";\n }\n get className() {\n return this.attributes.class || \"\";\n }\n get style() {\n const style = this.attributes.style ? parseCSSText(this.attributes.style) : {};\n const hyphenateRE2 = /\\B([A-Z])/g;\n style.setProperty = (name, value, priority) => {\n if (hyphenateRE2.test(name)) return;\n const normalizedName = camelize(name);\n if (!value) delete style[normalizedName];\n else style[normalizedName] = value;\n if (priority === \"important\") style[normalizedName] += \" !important\";\n this.attributes.style = toCSSText(style);\n };\n style.removeProperty = (name) => {\n if (hyphenateRE2.test(name)) return \"\";\n const normalizedName = camelize(name);\n const value = style[normalizedName] || \"\";\n delete style[normalizedName];\n this.attributes.style = toCSSText(style);\n return value;\n };\n return style;\n }\n getAttribute(name) {\n return this.attributes[name] || null;\n }\n setAttribute(name, attribute) {\n this.attributes[name] = attribute;\n }\n setAttributeNS(_namespace, qualifiedName, value) {\n this.setAttribute(qualifiedName, value);\n }\n removeAttribute(name) {\n delete this.attributes[name];\n }\n appendChild(newChild) {\n return appendChild(this, newChild);\n }\n insertBefore(newChild, refChild) {\n return insertBefore(this, newChild, refChild);\n }\n removeChild(node) {\n return removeChild(this, node);\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n attachShadow(_init) {\n const shadowRoot = this.ownerDocument.createElement(\"SHADOWROOT\");\n this.shadowRoot = shadowRoot;\n return shadowRoot;\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n dispatchEvent(_event) {\n return true;\n }\n toString() {\n let attributeString = \"\";\n for (const attribute in this.attributes) {\n attributeString += `${attribute}=\"${this.attributes[attribute]}\" `;\n }\n return `${this.tagName} ${attributeString}`;\n }\n}\nclass BaseRRMediaElement extends BaseRRElement {\n constructor() {\n super(...arguments);\n __publicField(this, \"currentTime\");\n __publicField(this, \"volume\");\n __publicField(this, \"paused\");\n __publicField(this, \"muted\");\n __publicField(this, \"playbackRate\");\n __publicField(this, \"loop\");\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n attachShadow(_init) {\n throw new Error(\n `RRDomException: Failed to execute 'attachShadow' on 'RRElement': This RRElement does not support attachShadow`\n );\n }\n play() {\n this.paused = false;\n }\n pause() {\n this.paused = true;\n }\n}\nclass BaseRRText extends BaseRRNode {\n constructor(data) {\n super();\n __publicField(this, \"nodeType\", 3);\n __publicField(this, \"nodeName\", \"#text\");\n __publicField(this, \"RRNodeType\", NodeType$1.Text);\n __publicField(this, \"data\");\n this.data = data;\n }\n get textContent() {\n return this.data;\n }\n set textContent(textContent) {\n this.data = textContent;\n }\n toString() {\n return `RRText text=${JSON.stringify(this.data)}`;\n }\n}\nclass BaseRRComment extends BaseRRNode {\n constructor(data) {\n super();\n __publicField(this, \"nodeType\", 8);\n __publicField(this, \"nodeName\", \"#comment\");\n __publicField(this, \"RRNodeType\", NodeType$1.Comment);\n __publicField(this, \"data\");\n this.data = data;\n }\n get textContent() {\n return this.data;\n }\n set textContent(textContent) {\n this.data = textContent;\n }\n toString() {\n return `RRComment text=${JSON.stringify(this.data)}`;\n }\n}\nclass BaseRRCDATASection extends BaseRRNode {\n constructor(data) {\n super();\n __publicField(this, \"nodeName\", \"#cdata-section\");\n __publicField(this, \"nodeType\", 4);\n __publicField(this, \"RRNodeType\", NodeType$1.CDATA);\n __publicField(this, \"data\");\n this.data = data;\n }\n get textContent() {\n return this.data;\n }\n set textContent(textContent) {\n this.data = textContent;\n }\n toString() {\n return `RRCDATASection data=${JSON.stringify(this.data)}`;\n }\n}\nclass ClassList {\n constructor(classText, onChange) {\n __publicField(this, \"onChange\");\n __publicField(this, \"classes\", []);\n __publicField(this, \"add\", (...classNames) => {\n for (const item of classNames) {\n const className = String(item);\n if (this.classes.indexOf(className) >= 0) continue;\n this.classes.push(className);\n }\n this.onChange && this.onChange(this.classes.join(\" \"));\n });\n __publicField(this, \"remove\", (...classNames) => {\n this.classes = this.classes.filter(\n (item) => classNames.indexOf(item) === -1\n );\n this.onChange && this.onChange(this.classes.join(\" \"));\n });\n if (classText) {\n const classes = classText.trim().split(/\\s+/);\n this.classes.push(...classes);\n }\n this.onChange = onChange;\n }\n}\nfunction appendChild(parent, newChild) {\n if (newChild.parentNode) newChild.parentNode.removeChild(newChild);\n if (parent.lastChild) {\n parent.lastChild.nextSibling = newChild;\n newChild.previousSibling = parent.lastChild;\n } else {\n parent.firstChild = newChild;\n newChild.previousSibling = null;\n }\n parent.lastChild = newChild;\n newChild.nextSibling = null;\n newChild.parentNode = parent;\n newChild.parentElement = parent;\n newChild.ownerDocument = parent.ownerDocument;\n return newChild;\n}\nfunction insertBefore(parent, newChild, refChild) {\n if (!refChild) return appendChild(parent, newChild);\n if (refChild.parentNode !== parent)\n throw new Error(\n \"Failed to execute 'insertBefore' on 'RRNode': The RRNode before which the new node is to be inserted is not a child of this RRNode.\"\n );\n if (newChild === refChild) return newChild;\n if (newChild.parentNode) newChild.parentNode.removeChild(newChild);\n newChild.previousSibling = refChild.previousSibling;\n refChild.previousSibling = newChild;\n newChild.nextSibling = refChild;\n if (newChild.previousSibling) newChild.previousSibling.nextSibling = newChild;\n else parent.firstChild = newChild;\n newChild.parentElement = parent;\n newChild.parentNode = parent;\n newChild.ownerDocument = parent.ownerDocument;\n return newChild;\n}\nfunction removeChild(parent, child) {\n if (child.parentNode !== parent)\n throw new Error(\n \"Failed to execute 'removeChild' on 'RRNode': The RRNode to be removed is not a child of this RRNode.\"\n );\n if (child.previousSibling)\n child.previousSibling.nextSibling = child.nextSibling;\n else parent.firstChild = child.nextSibling;\n if (child.nextSibling)\n child.nextSibling.previousSibling = child.previousSibling;\n else parent.lastChild = child.previousSibling;\n child.previousSibling = null;\n child.nextSibling = null;\n child.parentElement = null;\n child.parentNode = null;\n return child;\n}\nvar NodeType = /* @__PURE__ */ ((NodeType2) => {\n NodeType2[NodeType2[\"PLACEHOLDER\"] = 0] = \"PLACEHOLDER\";\n NodeType2[NodeType2[\"ELEMENT_NODE\"] = 1] = \"ELEMENT_NODE\";\n NodeType2[NodeType2[\"ATTRIBUTE_NODE\"] = 2] = \"ATTRIBUTE_NODE\";\n NodeType2[NodeType2[\"TEXT_NODE\"] = 3] = \"TEXT_NODE\";\n NodeType2[NodeType2[\"CDATA_SECTION_NODE\"] = 4] = \"CDATA_SECTION_NODE\";\n NodeType2[NodeType2[\"ENTITY_REFERENCE_NODE\"] = 5] = \"ENTITY_REFERENCE_NODE\";\n NodeType2[NodeType2[\"ENTITY_NODE\"] = 6] = \"ENTITY_NODE\";\n NodeType2[NodeType2[\"PROCESSING_INSTRUCTION_NODE\"] = 7] = \"PROCESSING_INSTRUCTION_NODE\";\n NodeType2[NodeType2[\"COMMENT_NODE\"] = 8] = \"COMMENT_NODE\";\n NodeType2[NodeType2[\"DOCUMENT_NODE\"] = 9] = \"DOCUMENT_NODE\";\n NodeType2[NodeType2[\"DOCUMENT_TYPE_NODE\"] = 10] = \"DOCUMENT_TYPE_NODE\";\n NodeType2[NodeType2[\"DOCUMENT_FRAGMENT_NODE\"] = 11] = \"DOCUMENT_FRAGMENT_NODE\";\n return NodeType2;\n})(NodeType || {});\nfunction getIFrameContentDocument(iframe) {\n try {\n return iframe.contentDocument;\n } catch (e) {\n }\n}\nfunction getIFrameContentWindow(iframe) {\n try {\n return iframe.contentWindow;\n } catch (e) {\n }\n}\nconst NAMESPACES = {\n svg: \"http://www.w3.org/2000/svg\",\n \"xlink:href\": \"http://www.w3.org/1999/xlink\",\n xmlns: \"http://www.w3.org/2000/xmlns/\"\n};\nconst SVGTagMap = {\n altglyph: \"altGlyph\",\n altglyphdef: \"altGlyphDef\",\n altglyphitem: \"altGlyphItem\",\n animatecolor: \"animateColor\",\n animatemotion: \"animateMotion\",\n animatetransform: \"animateTransform\",\n clippath: \"clipPath\",\n feblend: \"feBlend\",\n fecolormatrix: \"feColorMatrix\",\n fecomponenttransfer: \"feComponentTransfer\",\n fecomposite: \"feComposite\",\n feconvolvematrix: \"feConvolveMatrix\",\n fediffuselighting: \"feDiffuseLighting\",\n fedisplacementmap: \"feDisplacementMap\",\n fedistantlight: \"feDistantLight\",\n fedropshadow: \"feDropShadow\",\n feflood: \"feFlood\",\n fefunca: \"feFuncA\",\n fefuncb: \"feFuncB\",\n fefuncg: \"feFuncG\",\n fefuncr: \"feFuncR\",\n fegaussianblur: \"feGaussianBlur\",\n feimage: \"feImage\",\n femerge: \"feMerge\",\n femergenode: \"feMergeNode\",\n femorphology: \"feMorphology\",\n feoffset: \"feOffset\",\n fepointlight: \"fePointLight\",\n fespecularlighting: \"feSpecularLighting\",\n fespotlight: \"feSpotLight\",\n fetile: \"feTile\",\n feturbulence: \"feTurbulence\",\n foreignobject: \"foreignObject\",\n glyphref: \"glyphRef\",\n lineargradient: \"linearGradient\",\n radialgradient: \"radialGradient\"\n};\nlet createdNodeSet = null;\nfunction diff(oldTree, newTree, replayer, rrnodeMirror = newTree.mirror || newTree.ownerDocument.mirror) {\n oldTree = diffBeforeUpdatingChildren(\n oldTree,\n newTree,\n replayer,\n rrnodeMirror\n );\n diffChildren(oldTree, newTree, replayer, rrnodeMirror);\n diffAfterUpdatingChildren(oldTree, newTree, replayer);\n}\nfunction diffBeforeUpdatingChildren(oldTree, newTree, replayer, rrnodeMirror) {\n if (replayer.afterAppend && !createdNodeSet) {\n createdNodeSet = /* @__PURE__ */ new WeakSet();\n setTimeout(() => {\n createdNodeSet = null;\n }, 0);\n }\n if (!sameNodeType(oldTree, newTree)) {\n const calibratedOldTree = createOrGetNode(\n newTree,\n replayer.mirror,\n rrnodeMirror\n );\n oldTree.parentNode?.replaceChild(calibratedOldTree, oldTree);\n oldTree = calibratedOldTree;\n }\n switch (newTree.RRNodeType) {\n case NodeType$1.Document: {\n if (!nodeMatching(oldTree, newTree, replayer.mirror, rrnodeMirror)) {\n const newMeta = rrnodeMirror.getMeta(newTree);\n if (newMeta) {\n replayer.mirror.removeNodeFromMap(oldTree);\n oldTree.close();\n oldTree.open();\n replayer.mirror.add(oldTree, newMeta);\n createdNodeSet?.add(oldTree);\n }\n }\n break;\n }\n case NodeType$1.Element: {\n const oldElement = oldTree;\n const newRRElement = newTree;\n switch (newRRElement.tagName) {\n case \"IFRAME\": {\n const oldContentDocument = getIFrameContentDocument(\n oldTree\n );\n if (!oldContentDocument) break;\n diff(\n oldContentDocument,\n newTree.contentDocument,\n replayer,\n rrnodeMirror\n );\n break;\n }\n }\n if (newRRElement.shadowRoot) {\n if (!oldElement.shadowRoot) oldElement.attachShadow({ mode: \"open\" });\n diffChildren(\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n oldElement.shadowRoot,\n newRRElement.shadowRoot,\n replayer,\n rrnodeMirror\n );\n }\n diffProps(oldElement, newRRElement, rrnodeMirror);\n break;\n }\n }\n return oldTree;\n}\nfunction diffAfterUpdatingChildren(oldTree, newTree, replayer) {\n switch (newTree.RRNodeType) {\n case NodeType$1.Document: {\n const scrollData = newTree.scrollData;\n scrollData && replayer.applyScroll(scrollData, true);\n break;\n }\n case NodeType$1.Element: {\n const oldElement = oldTree;\n const newRRElement = newTree;\n newRRElement.scrollData && replayer.applyScroll(newRRElement.scrollData, true);\n newRRElement.inputData && replayer.applyInput(newRRElement.inputData);\n switch (newRRElement.tagName) {\n case \"AUDIO\":\n case \"VIDEO\": {\n const oldMediaElement = oldTree;\n const newMediaRRElement = newRRElement;\n if (newMediaRRElement.paused !== void 0) {\n const maybePromise = newMediaRRElement.paused ? oldMediaElement.pause() : oldMediaElement.play();\n if (typeof maybePromise?.catch === \"function\") {\n maybePromise.catch((e) => {\n console.warn(e);\n });\n }\n }\n if (newMediaRRElement.muted !== void 0)\n oldMediaElement.muted = newMediaRRElement.muted;\n if (newMediaRRElement.volume !== void 0)\n oldMediaElement.volume = newMediaRRElement.volume;\n if (newMediaRRElement.currentTime !== void 0)\n oldMediaElement.currentTime = newMediaRRElement.currentTime;\n if (newMediaRRElement.playbackRate !== void 0)\n oldMediaElement.playbackRate = newMediaRRElement.playbackRate;\n break;\n }\n case \"CANVAS\": {\n const rrCanvasElement = newTree;\n if (rrCanvasElement.rr_dataURL !== null) {\n const image = document.createElement(\"img\");\n image.onload = () => {\n const ctx = oldElement.getContext(\"2d\");\n if (ctx) {\n ctx.drawImage(image, 0, 0, image.width, image.height);\n }\n };\n image.src = rrCanvasElement.rr_dataURL;\n }\n rrCanvasElement.canvasMutations.forEach(\n (canvasMutation) => replayer.applyCanvas(\n canvasMutation.event,\n canvasMutation.mutation,\n oldTree\n )\n );\n break;\n }\n // Props of style elements have to be updated after all children are updated. Otherwise the props can be overwritten by textContent.\n case \"STYLE\": {\n const styleSheet = oldElement.sheet;\n styleSheet && newTree.rules.forEach(\n (data) => replayer.applyStyleSheetMutation(data, styleSheet)\n );\n break;\n }\n }\n break;\n }\n case NodeType$1.Text:\n case NodeType$1.Comment:\n case NodeType$1.CDATA: {\n if (oldTree.textContent !== newTree.data)\n oldTree.textContent = newTree.data;\n break;\n }\n }\n if (createdNodeSet?.has(oldTree)) {\n createdNodeSet.delete(oldTree);\n replayer.afterAppend?.(oldTree, replayer.mirror.getId(oldTree));\n }\n}\nfunction diffProps(oldTree, newTree, rrnodeMirror) {\n const oldAttributes = oldTree.attributes;\n const newAttributes = newTree.attributes;\n for (const name in newAttributes) {\n const newValue = newAttributes[name];\n const sn = rrnodeMirror.getMeta(newTree);\n if (sn?.isSVG && NAMESPACES[name])\n oldTree.setAttributeNS(NAMESPACES[name], name, newValue);\n else if (newTree.tagName === \"CANVAS\" && name === \"rr_dataURL\") {\n const image = document.createElement(\"img\");\n image.src = newValue;\n image.onload = () => {\n const ctx = oldTree.getContext(\"2d\");\n if (ctx) {\n ctx.drawImage(image, 0, 0, image.width, image.height);\n }\n };\n } else if (newTree.tagName === \"IFRAME\" && name === \"srcdoc\") continue;\n else {\n try {\n oldTree.setAttribute(name, newValue);\n } catch (err) {\n console.warn(err);\n }\n }\n }\n for (const { name } of Array.from(oldAttributes))\n if (!(name in newAttributes)) oldTree.removeAttribute(name);\n newTree.scrollLeft && (oldTree.scrollLeft = newTree.scrollLeft);\n newTree.scrollTop && (oldTree.scrollTop = newTree.scrollTop);\n}\nfunction diffChildren(oldTree, newTree, replayer, rrnodeMirror) {\n const oldChildren = Array.from(oldTree.childNodes);\n const newChildren = newTree.childNodes;\n if (oldChildren.length === 0 && newChildren.length === 0) return;\n let oldStartIndex = 0, oldEndIndex = oldChildren.length - 1, newStartIndex = 0, newEndIndex = newChildren.length - 1;\n let oldStartNode = oldChildren[oldStartIndex], oldEndNode = oldChildren[oldEndIndex], newStartNode = newChildren[newStartIndex], newEndNode = newChildren[newEndIndex];\n let oldIdToIndex = void 0, indexInOld = void 0;\n while (oldStartIndex <= oldEndIndex && newStartIndex <= newEndIndex) {\n if (oldStartNode === void 0) {\n oldStartNode = oldChildren[++oldStartIndex];\n } else if (oldEndNode === void 0) {\n oldEndNode = oldChildren[--oldEndIndex];\n } else if (\n // same first node?\n nodeMatching(oldStartNode, newStartNode, replayer.mirror, rrnodeMirror)\n ) {\n oldStartNode = oldChildren[++oldStartIndex];\n newStartNode = newChildren[++newStartIndex];\n } else if (\n // same last node?\n nodeMatching(oldEndNode, newEndNode, replayer.mirror, rrnodeMirror)\n ) {\n oldEndNode = oldChildren[--oldEndIndex];\n newEndNode = newChildren[--newEndIndex];\n } else if (\n // is the first old node the same as the last new node?\n nodeMatching(oldStartNode, newEndNode, replayer.mirror, rrnodeMirror)\n ) {\n try {\n handleInsertBefore(oldTree, oldStartNode, oldEndNode.nextSibling);\n } catch (e) {\n console.warn(e);\n }\n oldStartNode = oldChildren[++oldStartIndex];\n newEndNode = newChildren[--newEndIndex];\n } else if (\n // is the last old node the same as the first new node?\n nodeMatching(oldEndNode, newStartNode, replayer.mirror, rrnodeMirror)\n ) {\n try {\n handleInsertBefore(oldTree, oldEndNode, oldStartNode);\n } catch (e) {\n console.warn(e);\n }\n oldEndNode = oldChildren[--oldEndIndex];\n newStartNode = newChildren[++newStartIndex];\n } else {\n if (!oldIdToIndex) {\n oldIdToIndex = {};\n for (let i = oldStartIndex; i <= oldEndIndex; i++) {\n const oldChild2 = oldChildren[i];\n if (oldChild2 && replayer.mirror.hasNode(oldChild2))\n oldIdToIndex[replayer.mirror.getId(oldChild2)] = i;\n }\n }\n indexInOld = oldIdToIndex[rrnodeMirror.getId(newStartNode)];\n const nodeToMove = oldChildren[indexInOld];\n if (indexInOld !== void 0 && nodeToMove && nodeMatching(nodeToMove, newStartNode, replayer.mirror, rrnodeMirror)) {\n try {\n handleInsertBefore(oldTree, nodeToMove, oldStartNode);\n } catch (e) {\n console.warn(e);\n }\n oldChildren[indexInOld] = void 0;\n } else {\n const newNode = createOrGetNode(\n newStartNode,\n replayer.mirror,\n rrnodeMirror\n );\n if (oldTree.nodeName === \"#document\" && oldStartNode && /**\n * Special case 1: one document isn't allowed to have two doctype nodes at the same time, so we need to remove the old one first before inserting the new one.\n * How this case happens: A parent document in the old tree already has a doctype node with an id e.g. #1. A new full snapshot rebuilds the replayer with a new doctype node with another id #2. According to the algorithm, the new doctype node will be inserted before the old one, which is not allowed by the Document standard.\n */\n (newNode.nodeType === newNode.DOCUMENT_TYPE_NODE && oldStartNode.nodeType === oldStartNode.DOCUMENT_TYPE_NODE || /**\n * Special case 2: one document isn't allowed to have two HTMLElements at the same time, so we need to remove the old one first before inserting the new one.\n * How this case happens: A mounted iframe element has an automatically created HTML element. We should delete it before inserting a serialized one. Otherwise, an error 'Only one element on document allowed' will be thrown.\n */\n newNode.nodeType === newNode.ELEMENT_NODE && oldStartNode.nodeType === oldStartNode.ELEMENT_NODE)) {\n oldTree.removeChild(oldStartNode);\n replayer.mirror.removeNodeFromMap(oldStartNode);\n oldStartNode = oldChildren[++oldStartIndex];\n }\n try {\n handleInsertBefore(oldTree, newNode, oldStartNode || null);\n } catch (e) {\n console.warn(e);\n }\n }\n newStartNode = newChildren[++newStartIndex];\n }\n }\n if (oldStartIndex > oldEndIndex) {\n const referenceRRNode = newChildren[newEndIndex + 1];\n let referenceNode = null;\n if (referenceRRNode)\n referenceNode = replayer.mirror.getNode(\n rrnodeMirror.getId(referenceRRNode)\n );\n for (; newStartIndex <= newEndIndex; ++newStartIndex) {\n const newNode = createOrGetNode(\n newChildren[newStartIndex],\n replayer.mirror,\n rrnodeMirror\n );\n try {\n handleInsertBefore(oldTree, newNode, referenceNode);\n } catch (e) {\n console.warn(e);\n }\n }\n } else if (newStartIndex > newEndIndex) {\n for (; oldStartIndex <= oldEndIndex; oldStartIndex++) {\n const node = oldChildren[oldStartIndex];\n if (!node || node.parentNode !== oldTree) continue;\n try {\n oldTree.removeChild(node);\n replayer.mirror.removeNodeFromMap(node);\n } catch (e) {\n console.warn(e);\n }\n }\n }\n let oldChild = oldTree.firstChild;\n let newChild = newTree.firstChild;\n while (oldChild !== null && newChild !== null) {\n diff(oldChild, newChild, replayer, rrnodeMirror);\n oldChild = oldChild.nextSibling;\n newChild = newChild.nextSibling;\n }\n}\nfunction createOrGetNode(rrNode, domMirror, rrnodeMirror) {\n const nodeId = rrnodeMirror.getId(rrNode);\n const sn = rrnodeMirror.getMeta(rrNode);\n let node = null;\n if (nodeId > -1) node = domMirror.getNode(nodeId);\n if (node !== null && sameNodeType(node, rrNode)) return node;\n switch (rrNode.RRNodeType) {\n case NodeType$1.Document:\n node = new Document();\n break;\n case NodeType$1.DocumentType:\n node = document.implementation.createDocumentType(\n rrNode.name,\n rrNode.publicId,\n rrNode.systemId\n );\n break;\n case NodeType$1.Element: {\n let tagName = rrNode.tagName.toLowerCase();\n tagName = SVGTagMap[tagName] || tagName;\n if (sn && \"isSVG\" in sn && sn?.isSVG) {\n node = document.createElementNS(NAMESPACES[\"svg\"], tagName);\n } else node = document.createElement(rrNode.tagName);\n break;\n }\n case NodeType$1.Text:\n node = document.createTextNode(rrNode.data);\n break;\n case NodeType$1.Comment:\n node = document.createComment(rrNode.data);\n break;\n case NodeType$1.CDATA:\n node = document.createCDATASection(rrNode.data);\n break;\n }\n if (sn) domMirror.add(node, { ...sn });\n try {\n createdNodeSet?.add(node);\n } catch (e) {\n }\n return node;\n}\nfunction sameNodeType(node1, node2) {\n if (node1.nodeType !== node2.nodeType) return false;\n return node1.nodeType !== node1.ELEMENT_NODE || node1.tagName.toUpperCase() === node2.tagName;\n}\nfunction nodeMatching(node1, node2, domMirror, rrdomMirror) {\n const node1Id = domMirror.getId(node1);\n const node2Id = rrdomMirror.getId(node2);\n if (node1Id === -1 || node1Id !== node2Id) return false;\n return sameNodeType(node1, node2);\n}\nfunction getInsertedStylesFromElement(styleElement) {\n const elementCssRules = styleElement.sheet?.cssRules;\n if (!elementCssRules || !elementCssRules.length) return;\n const tempStyleSheet = new CSSStyleSheet();\n tempStyleSheet.replaceSync(styleElement.innerText);\n const innerTextStylesMap = {};\n for (let i = 0; i < tempStyleSheet.cssRules.length; i++) {\n innerTextStylesMap[tempStyleSheet.cssRules[i].cssText] = tempStyleSheet.cssRules[i];\n }\n const insertedStylesStyleSheet = [];\n for (let i = 0; i < elementCssRules?.length; i++) {\n const cssRuleText = elementCssRules[i].cssText;\n if (!innerTextStylesMap[cssRuleText]) {\n insertedStylesStyleSheet.push({\n index: i,\n cssRuleText\n });\n }\n }\n return insertedStylesStyleSheet;\n}\nfunction handleInsertBefore(oldTree, nodeToMove, insertBeforeNode) {\n let insertedStyles;\n if (nodeToMove.nodeName === \"STYLE\") {\n insertedStyles = getInsertedStylesFromElement(\n nodeToMove\n );\n }\n oldTree.insertBefore(nodeToMove, insertBeforeNode);\n if (insertedStyles && insertedStyles.length) {\n insertedStyles.forEach(({ cssRuleText, index }) => {\n nodeToMove.sheet?.insertRule(cssRuleText, index);\n });\n }\n}\nclass RRDocument extends BaseRRDocument {\n constructor(mirror) {\n super();\n __publicField(this, \"UNSERIALIZED_STARTING_ID\", -2);\n // In the rrweb replayer, there are some unserialized nodes like the element that stores the injected style rules.\n // These unserialized nodes may interfere the execution of the diff algorithm.\n // The id of serialized node is larger than 0. So this value less than 0 is used as id for these unserialized nodes.\n __publicField(this, \"_unserializedId\", this.UNSERIALIZED_STARTING_ID);\n __publicField(this, \"mirror\", createMirror());\n __publicField(this, \"scrollData\", null);\n if (mirror) {\n this.mirror = mirror;\n }\n }\n /**\n * Every time the id is used, it will minus 1 automatically to avoid collisions.\n */\n get unserializedId() {\n return this._unserializedId--;\n }\n createDocument(_namespace, _qualifiedName, _doctype) {\n return new RRDocument();\n }\n createDocumentType(qualifiedName, publicId, systemId) {\n const documentTypeNode = new RRDocumentType(\n qualifiedName,\n publicId,\n systemId\n );\n documentTypeNode.ownerDocument = this;\n return documentTypeNode;\n }\n createElement(tagName) {\n const upperTagName = tagName.toUpperCase();\n let element;\n switch (upperTagName) {\n case \"AUDIO\":\n case \"VIDEO\":\n element = new RRMediaElement(upperTagName);\n break;\n case \"IFRAME\":\n element = new RRIFrameElement(upperTagName, this.mirror);\n break;\n case \"CANVAS\":\n element = new RRCanvasElement(upperTagName);\n break;\n case \"STYLE\":\n element = new RRStyleElement(upperTagName);\n break;\n default:\n element = new RRElement(upperTagName);\n break;\n }\n element.ownerDocument = this;\n return element;\n }\n createComment(data) {\n const commentNode = new RRComment(data);\n commentNode.ownerDocument = this;\n return commentNode;\n }\n createCDATASection(data) {\n const sectionNode = new RRCDATASection(data);\n sectionNode.ownerDocument = this;\n return sectionNode;\n }\n createTextNode(data) {\n const textNode = new RRText(data);\n textNode.ownerDocument = this;\n return textNode;\n }\n destroyTree() {\n this.firstChild = null;\n this.lastChild = null;\n this.mirror.reset();\n }\n open() {\n super.open();\n this._unserializedId = this.UNSERIALIZED_STARTING_ID;\n }\n}\nconst RRDocumentType = BaseRRDocumentType;\nclass RRElement extends BaseRRElement {\n constructor() {\n super(...arguments);\n __publicField(this, \"inputData\", null);\n __publicField(this, \"scrollData\", null);\n }\n}\nclass RRMediaElement extends BaseRRMediaElement {\n}\nclass RRCanvasElement extends RRElement {\n constructor() {\n super(...arguments);\n __publicField(this, \"rr_dataURL\", null);\n __publicField(this, \"canvasMutations\", []);\n }\n /**\n * This is a dummy implementation to distinguish RRCanvasElement from real HTMLCanvasElement.\n */\n getContext() {\n return null;\n }\n}\nclass RRStyleElement extends RRElement {\n constructor() {\n super(...arguments);\n __publicField(this, \"rules\", []);\n }\n}\nclass RRIFrameElement extends RRElement {\n constructor(upperTagName, mirror) {\n super(upperTagName);\n __publicField(this, \"contentDocument\", new RRDocument());\n this.contentDocument.mirror = mirror;\n }\n}\nconst RRText = BaseRRText;\nconst RRComment = BaseRRComment;\nconst RRCDATASection = BaseRRCDATASection;\nfunction getValidTagName(element) {\n if (element instanceof HTMLFormElement) {\n return \"FORM\";\n }\n return element.tagName.toUpperCase();\n}\nfunction buildFromNode(node, rrdom, domMirror, parentRRNode) {\n let rrNode;\n switch (node.nodeType) {\n case NodeType.DOCUMENT_NODE:\n if (parentRRNode && parentRRNode.nodeName === \"IFRAME\")\n rrNode = parentRRNode.contentDocument;\n else {\n rrNode = rrdom;\n rrNode.compatMode = node.compatMode;\n }\n break;\n case NodeType.DOCUMENT_TYPE_NODE: {\n const documentType = node;\n rrNode = rrdom.createDocumentType(\n documentType.name,\n documentType.publicId,\n documentType.systemId\n );\n break;\n }\n case NodeType.ELEMENT_NODE: {\n const elementNode = node;\n const tagName = getValidTagName(elementNode);\n rrNode = rrdom.createElement(tagName);\n const rrElement = rrNode;\n for (const { name, value } of Array.from(elementNode.attributes)) {\n rrElement.attributes[name] = value;\n }\n elementNode.scrollLeft && (rrElement.scrollLeft = elementNode.scrollLeft);\n elementNode.scrollTop && (rrElement.scrollTop = elementNode.scrollTop);\n break;\n }\n case NodeType.TEXT_NODE:\n rrNode = rrdom.createTextNode(node.textContent || \"\");\n break;\n case NodeType.CDATA_SECTION_NODE:\n rrNode = rrdom.createCDATASection(node.data);\n break;\n case NodeType.COMMENT_NODE:\n rrNode = rrdom.createComment(node.textContent || \"\");\n break;\n // if node is a shadow root\n case NodeType.DOCUMENT_FRAGMENT_NODE:\n rrNode = parentRRNode.attachShadow({ mode: \"open\" });\n break;\n default:\n return null;\n }\n let sn = domMirror.getMeta(node);\n if (rrdom instanceof RRDocument) {\n if (!sn) {\n sn = getDefaultSN(rrNode, rrdom.unserializedId);\n domMirror.add(node, sn);\n }\n rrdom.mirror.add(rrNode, { ...sn });\n }\n return rrNode;\n}\nfunction buildFromDom(dom, domMirror = createMirror$1(), rrdom = new RRDocument()) {\n function walk2(node, parentRRNode) {\n const rrNode = buildFromNode(node, rrdom, domMirror, parentRRNode);\n if (rrNode === null) return;\n if (\n // if the parentRRNode isn't a RRIFrameElement\n parentRRNode?.nodeName !== \"IFRAME\" && // if node isn't a shadow root\n node.nodeType !== NodeType.DOCUMENT_FRAGMENT_NODE\n ) {\n parentRRNode?.appendChild(rrNode);\n rrNode.parentNode = parentRRNode;\n rrNode.parentElement = parentRRNode;\n }\n if (node.nodeName === \"IFRAME\") {\n const iframeDoc = getIFrameContentDocument(node);\n iframeDoc && walk2(iframeDoc, rrNode);\n } else if (node.nodeType === NodeType.DOCUMENT_NODE || node.nodeType === NodeType.ELEMENT_NODE || node.nodeType === NodeType.DOCUMENT_FRAGMENT_NODE) {\n if (node.nodeType === NodeType.ELEMENT_NODE && node.shadowRoot)\n walk2(node.shadowRoot, rrNode);\n node.childNodes.forEach((childNode) => walk2(childNode, rrNode));\n }\n }\n walk2(dom, null);\n return rrdom;\n}\nfunction createMirror() {\n return new Mirror2();\n}\nclass Mirror2 {\n constructor() {\n __publicField(this, \"idNodeMap\", /* @__PURE__ */ new Map());\n __publicField(this, \"nodeMetaMap\", /* @__PURE__ */ new WeakMap());\n }\n getId(n) {\n if (!n) return -1;\n const id = this.getMeta(n)?.id;\n return id ?? -1;\n }\n getNode(id) {\n return this.idNodeMap.get(id) || null;\n }\n getIds() {\n return Array.from(this.idNodeMap.keys());\n }\n getMeta(n) {\n return this.nodeMetaMap.get(n) || null;\n }\n // removes the node from idNodeMap\n // doesn't remove the node from nodeMetaMap\n removeNodeFromMap(n) {\n const id = this.getId(n);\n this.idNodeMap.delete(id);\n if (n.childNodes) {\n n.childNodes.forEach((childNode) => this.removeNodeFromMap(childNode));\n }\n }\n has(id) {\n return this.idNodeMap.has(id);\n }\n hasNode(node) {\n return this.nodeMetaMap.has(node);\n }\n add(n, meta) {\n const id = meta.id;\n this.idNodeMap.set(id, n);\n this.nodeMetaMap.set(n, meta);\n }\n replace(id, n) {\n const oldNode = this.getNode(id);\n if (oldNode) {\n const meta = this.nodeMetaMap.get(oldNode);\n if (meta) this.nodeMetaMap.set(n, meta);\n }\n this.idNodeMap.set(id, n);\n }\n reset() {\n this.idNodeMap = /* @__PURE__ */ new Map();\n this.nodeMetaMap = /* @__PURE__ */ new WeakMap();\n }\n}\nfunction getDefaultSN(node, id) {\n switch (node.RRNodeType) {\n case NodeType$1.Document:\n return {\n id,\n type: node.RRNodeType,\n childNodes: []\n };\n case NodeType$1.DocumentType: {\n const doctype = node;\n return {\n id,\n type: node.RRNodeType,\n name: doctype.name,\n publicId: doctype.publicId,\n systemId: doctype.systemId\n };\n }\n case NodeType$1.Element:\n return {\n id,\n type: node.RRNodeType,\n tagName: node.tagName.toLowerCase(),\n // In rrweb data, all tagNames are lowercase.\n attributes: {},\n childNodes: []\n };\n case NodeType$1.Text:\n return {\n id,\n type: node.RRNodeType,\n textContent: node.textContent || \"\"\n };\n case NodeType$1.Comment:\n return {\n id,\n type: node.RRNodeType,\n textContent: node.textContent || \"\"\n };\n case NodeType$1.CDATA:\n return {\n id,\n type: node.RRNodeType,\n textContent: \"\"\n };\n }\n}\nfunction printRRDom(rootNode, mirror) {\n return walk(rootNode, mirror, \"\");\n}\nfunction walk(node, mirror, blankSpace) {\n let printText = `${blankSpace}${mirror.getId(node)} ${node.toString()}\n`;\n if (node.RRNodeType === NodeType$1.Element) {\n const element = node;\n if (element.shadowRoot)\n printText += walk(element.shadowRoot, mirror, blankSpace + \" \");\n }\n for (const child of node.childNodes)\n printText += walk(child, mirror, blankSpace + \" \");\n if (node.nodeName === \"IFRAME\")\n printText += walk(\n node.contentDocument,\n mirror,\n blankSpace + \" \"\n );\n return printText;\n}\nexport {\n BaseRRCDATASection,\n BaseRRComment,\n BaseRRDocument,\n BaseRRDocumentType,\n BaseRRElement,\n BaseRRMediaElement,\n BaseRRNode,\n BaseRRText,\n ClassList,\n Mirror2 as Mirror,\n NodeType,\n RRCDATASection,\n RRCanvasElement,\n RRComment,\n RRDocument,\n RRDocumentType,\n RRElement,\n RRIFrameElement,\n RRMediaElement,\n BaseRRNode as RRNode,\n RRStyleElement,\n RRText,\n buildFromDom,\n buildFromNode,\n createMirror,\n createOrGetNode,\n diff,\n getDefaultSN,\n getIFrameContentDocument,\n getIFrameContentWindow,\n printRRDom\n};\n//# sourceMappingURL=rrdom.js.map\n","/**\n * This class is used to parse a style declaration into a CSSStyleDeclaration object.\n * It uses an unattached doc unless `CSSStyleSheet.prototype.replaceSync` is available which can be used to bypass CSP violations.\n * https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/replaceSync\n *\n * This builds on https://github.com/getsentry/rrweb/pull/211#issuecomment-2284551183 which exhausted the other available options.\n *\n * Note: This means some browsers (older than 23 March 2023) will use the unattached doc and may experience CSP violations,\n * but newer browsers will use the replaceSync method and will not experience CSP violations.\n */\nexport class StyleDeclarationParser {\n private unattachedDoc: Document | null = null;\n\n public constructor(private readonly doc: Document) {}\n\n public parse(styleText: string): CSSStyleDeclaration | null {\n return (\n this.parseWithConstructableStylesheet(styleText) ||\n this.parseWithDetachedElement(styleText)\n );\n }\n\n private parseWithConstructableStylesheet(\n styleText: string,\n ): CSSStyleDeclaration | null {\n if (\n typeof CSSStyleSheet === 'undefined' ||\n typeof CSSStyleSheet.prototype.replaceSync !== 'function'\n ) {\n return null;\n }\n\n try {\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(`x { ${styleText} }`);\n\n const rule = sheet.cssRules[0];\n if (!rule || rule.type !== CSSRule.STYLE_RULE) {\n return null;\n }\n\n return (rule as CSSStyleRule).style;\n } catch {\n return null;\n }\n }\n\n private parseWithDetachedElement(styleText: string): CSSStyleDeclaration {\n const old = this.getUnattachedDoc().createElement('span');\n old.setAttribute('style', styleText);\n return old.style;\n