{"version":3,"file":"static/js/recorder.c783a24c.chunk.js","mappings":"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","sources":["../node_modules/@datadog/browser-rum/src/domain/record/serialization/serializationUtils.ts","../node_modules/@datadog/browser-rum/src/types/sessionReplayConstants.ts","../node_modules/@datadog/browser-rum/src/domain/record/serialization/serializeStyleSheets.ts","../node_modules/@datadog/browser-rum/src/domain/record/serialization/serializeAttribute.ts","../node_modules/@datadog/browser-rum/src/domain/record/serialization/serializeAttributes.ts","../node_modules/@datadog/browser-rum/src/domain/record/serialization/serializeNode.ts","../node_modules/@datadog/browser-rum/src/domain/record/serialization/serializeDocument.ts","../node_modules/@datadog/browser-rum/src/domain/record/eventsUtils.ts","../node_modules/@datadog/browser-rum/src/domain/record/viewports.ts","../node_modules/@datadog/browser-rum/src/domain/record/assembly.ts","../node_modules/@datadog/browser-rum/src/domain/record/trackers/trackMove.ts","../node_modules/@datadog/browser-rum/src/domain/record/trackers/trackMouseInteraction.ts","../node_modules/@datadog/browser-rum/src/domain/record/trackers/trackScroll.ts","../node_modules/@datadog/browser-rum/src/domain/record/trackers/trackViewportResize.ts","../node_modules/@datadog/browser-rum/src/domain/record/trackers/trackMediaInteraction.ts","../node_modules/@datadog/browser-rum/src/domain/record/trackers/trackStyleSheet.ts","../node_modules/@datadog/browser-rum/src/domain/record/trackers/trackFocus.ts","../node_modules/@datadog/browser-rum/src/domain/record/trackers/trackFrustration.ts","../node_modules/@datadog/browser-rum/src/domain/record/trackers/trackViewEnd.ts","../node_modules/@datadog/browser-rum/src/domain/record/trackers/trackInput.ts","../node_modules/@datadog/browser-rum/src/domain/record/mutationBatch.ts","../node_modules/@datadog/browser-rum/src/domain/record/trackers/trackMutation.ts","../node_modules/@datadog/browser-rum/src/domain/record/shadowRootsController.ts","../node_modules/@datadog/browser-rum/src/domain/record/record.ts","../node_modules/@datadog/browser-rum/src/domain/record/elementsScrollPositions.ts","../node_modules/@datadog/browser-rum/src/domain/record/startFullSnapshots.ts","../node_modules/@datadog/browser-rum/src/domain/record/recordIds.ts","../node_modules/@datadog/browser-rum/src/domain/segmentCollection/segment.ts","../node_modules/@datadog/browser-rum/src/domain/segmentCollection/segmentCollection.ts","../node_modules/@datadog/browser-rum/src/domain/segmentCollection/buildReplayPayload.ts","../node_modules/@datadog/browser-rum/src/boot/startRecording.ts","../node_modules/@datadog/browser-rum/src/domain/startRecordBridge.ts"],"sourcesContent":["import { buildUrl } from '@datadog/browser-core'\nimport { getParentNode, isNodeShadowRoot, CENSORED_STRING_MARK, shouldMaskNode } from '@datadog/browser-rum-core'\nimport type { NodePrivacyLevel } from '@datadog/browser-rum-core'\nimport type { NodeWithSerializedNode } from './serialization.types'\n\nconst serializedNodeIds = new WeakMap<Node, number>()\n\nexport function hasSerializedNode(node: Node): node is NodeWithSerializedNode {\n return serializedNodeIds.has(node)\n}\n\nexport function nodeAndAncestorsHaveSerializedNode(node: Node): node is NodeWithSerializedNode {\n let current: Node | null = node\n while (current) {\n if (!hasSerializedNode(current) && !isNodeShadowRoot(current)) {\n return false\n }\n current = getParentNode(current)\n }\n return true\n}\n\nexport function getSerializedNodeId(node: NodeWithSerializedNode): number\nexport function getSerializedNodeId(node: Node): number | undefined\nexport function getSerializedNodeId(node: Node) {\n return serializedNodeIds.get(node)\n}\n\nexport function setSerializedNodeId(node: Node, serializeNodeId: number) {\n serializedNodeIds.set(node, serializeNodeId)\n}\n\n/**\n * Get the element \"value\" to be serialized as an attribute or an input update record. It respects\n * the input privacy mode of the element.\n * PERFROMANCE OPTIMIZATION: Assumes that privacy level `HIDDEN` is never encountered because of earlier checks.\n */\nexport function getElementInputValue(element: Element, nodePrivacyLevel: NodePrivacyLevel) {\n /*\n BROWSER SPEC NOTE: <input>, <select>\n For some <input> elements, the `value` is an exceptional property/attribute that has the\n value synced between el.value and el.getAttribute()\n input[type=button,checkbox,hidden,image,radio,reset,submit]\n */\n const tagName = element.tagName\n const value = (element as HTMLInputElement | HTMLTextAreaElement).value\n\n if (shouldMaskNode(element, nodePrivacyLevel)) {\n const type = (element as HTMLInputElement | HTMLTextAreaElement).type\n if (tagName === 'INPUT' && (type === 'button' || type === 'submit' || type === 'reset')) {\n // Overrule `MASK` privacy level for button-like element values, as they are used during replay\n // to display their label. They can still be hidden via the \"hidden\" privacy attribute or class name.\n return value\n } else if (!value || tagName === 'OPTION') {\n // <Option> value provides no benefit\n return\n }\n return CENSORED_STRING_MARK\n }\n\n if (tagName === 'OPTION' || tagName === 'SELECT') {\n return (element as HTMLOptionElement | HTMLSelectElement).value\n }\n\n if (tagName !== 'INPUT' && tagName !== 'TEXTAREA') {\n return\n }\n\n return value\n}\n\nexport const URL_IN_CSS_REF = /url\\((?:(')([^']*)'|(\")([^\"]*)\"|([^)]*))\\)/gm\nexport const ABSOLUTE_URL = /^[A-Za-z]+:|^\\/\\//\nexport const DATA_URI = /^data:.*,/i\n\nexport function switchToAbsoluteUrl(cssText: string, cssHref: string | null): string {\n return cssText.replace(\n URL_IN_CSS_REF,\n (\n matchingSubstring: string,\n singleQuote: string | undefined,\n urlWrappedInSingleQuotes: string | undefined,\n doubleQuote: string | undefined,\n urlWrappedInDoubleQuotes: string | undefined,\n urlNotWrappedInQuotes: string | undefined\n ) => {\n const url = urlWrappedInSingleQuotes || urlWrappedInDoubleQuotes || urlNotWrappedInQuotes\n\n if (!cssHref || !url || ABSOLUTE_URL.test(url) || DATA_URI.test(url)) {\n return matchingSubstring\n }\n\n const quote = singleQuote || doubleQuote || ''\n return `url(${quote}${makeUrlAbsolute(url, cssHref)}${quote})`\n }\n )\n}\n\nexport function makeUrlAbsolute(url: string, baseUrl: string): string {\n try {\n return buildUrl(url, baseUrl).href\n } catch {\n return url\n }\n}\n\nconst TAG_NAME_REGEX = /[^a-z1-6-_]/\nexport function getValidTagName(tagName: string): string {\n const processedTagName = tagName.toLowerCase().trim()\n\n if (TAG_NAME_REGEX.test(processedTagName)) {\n // if the tag name is odd and we cannot extract\n // anything from the string, then we return a\n // generic div\n return 'div'\n }\n\n return processedTagName\n}\n\nexport function censoredImageForSize(width: number, height: number) {\n return `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='${width}' height='${height}' style='background-color:silver'%3E%3C/svg%3E`\n}\n","import type * as SessionReplay from './sessionReplay'\n\nexport const RecordType: {\n FullSnapshot: SessionReplay.BrowserFullSnapshotRecord['type']\n IncrementalSnapshot: SessionReplay.BrowserIncrementalSnapshotRecord['type']\n Meta: SessionReplay.MetaRecord['type']\n Focus: SessionReplay.FocusRecord['type']\n ViewEnd: SessionReplay.ViewEndRecord['type']\n VisualViewport: SessionReplay.VisualViewportRecord['type']\n FrustrationRecord: SessionReplay.FrustrationRecord['type']\n} = {\n FullSnapshot: 2,\n IncrementalSnapshot: 3,\n Meta: 4,\n Focus: 6,\n ViewEnd: 7,\n VisualViewport: 8,\n FrustrationRecord: 9,\n} as const\n\nexport type RecordType = (typeof RecordType)[keyof typeof RecordType]\n\nexport const NodeType: {\n Document: SessionReplay.DocumentNode['type']\n DocumentType: SessionReplay.DocumentTypeNode['type']\n Element: SessionReplay.ElementNode['type']\n Text: SessionReplay.TextNode['type']\n CDATA: SessionReplay.CDataNode['type']\n DocumentFragment: SessionReplay.DocumentFragmentNode['type']\n} = {\n Document: 0,\n DocumentType: 1,\n Element: 2,\n Text: 3,\n CDATA: 4,\n DocumentFragment: 11,\n} as const\n\nexport type NodeType = (typeof NodeType)[keyof typeof NodeType]\n\nexport const IncrementalSource: {\n Mutation: SessionReplay.BrowserMutationData['source']\n MouseMove: Exclude<SessionReplay.MousemoveData['source'], 6>\n MouseInteraction: SessionReplay.MouseInteractionData['source']\n Scroll: SessionReplay.ScrollData['source']\n ViewportResize: SessionReplay.ViewportResizeData['source']\n Input: SessionReplay.InputData['source']\n TouchMove: Exclude<SessionReplay.MousemoveData['source'], 1>\n MediaInteraction: SessionReplay.MediaInteractionData['source']\n StyleSheetRule: SessionReplay.StyleSheetRuleData['source']\n} = {\n Mutation: 0,\n MouseMove: 1,\n MouseInteraction: 2,\n Scroll: 3,\n ViewportResize: 4,\n Input: 5,\n TouchMove: 6,\n MediaInteraction: 7,\n StyleSheetRule: 8,\n // CanvasMutation : 9,\n // Font : 10,\n} as const\n\nexport type IncrementalSource = (typeof IncrementalSource)[keyof typeof IncrementalSource]\n\nexport const MouseInteractionType = {\n MouseUp: 0,\n MouseDown: 1,\n Click: 2,\n ContextMenu: 3,\n DblClick: 4,\n Focus: 5,\n Blur: 6,\n TouchStart: 7,\n TouchEnd: 9,\n} as const\n\nexport type MouseInteractionType = (typeof MouseInteractionType)[keyof typeof MouseInteractionType]\n\nexport const MediaInteractionType = {\n Play: 0,\n Pause: 1,\n} as const\n\nexport type MediaInteractionType = (typeof MediaInteractionType)[keyof typeof MediaInteractionType]\n","import type { StyleSheet } from '../../../types'\n\nexport function serializeStyleSheets(cssStyleSheets: CSSStyleSheet[] | undefined): StyleSheet[] | undefined {\n if (cssStyleSheets === undefined || cssStyleSheets.length === 0) {\n return undefined\n }\n return cssStyleSheets.map((cssStyleSheet) => {\n const rules = cssStyleSheet.cssRules || cssStyleSheet.rules\n const cssRules = Array.from(rules, (cssRule) => cssRule.cssText)\n\n const styleSheet: StyleSheet = {\n cssRules,\n disabled: cssStyleSheet.disabled || undefined,\n media: cssStyleSheet.media.length > 0 ? Array.from(cssStyleSheet.media) : undefined,\n }\n return styleSheet\n })\n}\n","import {\n NodePrivacyLevel,\n PRIVACY_ATTR_NAME,\n CENSORED_STRING_MARK,\n CENSORED_IMG_MARK,\n STABLE_ATTRIBUTES,\n isLongDataUrl,\n sanitizeDataUrl,\n} from '@datadog/browser-rum-core'\nimport type { RumConfiguration } from '@datadog/browser-rum-core'\nimport { censoredImageForSize } from './serializationUtils'\n\nexport function serializeAttribute(\n element: Element,\n nodePrivacyLevel: NodePrivacyLevel,\n attributeName: string,\n configuration: RumConfiguration\n): string | number | boolean | null {\n if (nodePrivacyLevel === NodePrivacyLevel.HIDDEN) {\n // dup condition for direct access case\n return null\n }\n const attributeValue = element.getAttribute(attributeName)\n if (\n nodePrivacyLevel === NodePrivacyLevel.MASK &&\n attributeName !== PRIVACY_ATTR_NAME &&\n !STABLE_ATTRIBUTES.includes(attributeName) &&\n attributeName !== configuration.actionNameAttribute\n ) {\n const tagName = element.tagName\n\n switch (attributeName) {\n // Mask Attribute text content\n case 'title':\n case 'alt':\n case 'placeholder':\n return CENSORED_STRING_MARK\n }\n\n // mask image URLs\n if (tagName === 'IMG' && (attributeName === 'src' || attributeName === 'srcset')) {\n // generate image with similar dimension than the original to have the same rendering behaviour\n const image = element as HTMLImageElement\n if (image.naturalWidth > 0) {\n return censoredImageForSize(image.naturalWidth, image.naturalHeight)\n }\n const { width, height } = element.getBoundingClientRect()\n if (width > 0 || height > 0) {\n return censoredImageForSize(width, height)\n }\n // if we can't get the image size, fallback to the censored image\n return CENSORED_IMG_MARK\n }\n\n // mask source URLs\n if (tagName === 'SOURCE' && (attributeName === 'src' || attributeName === 'srcset')) {\n return CENSORED_IMG_MARK\n }\n\n // mask <a> URLs\n if (tagName === 'A' && attributeName === 'href') {\n return CENSORED_STRING_MARK\n }\n\n // mask data-* attributes\n if (attributeValue && attributeName.startsWith('data-')) {\n // Exception: it's safe to reveal the `${PRIVACY_ATTR_NAME}` attr\n return CENSORED_STRING_MARK\n }\n\n // mask iframe srcdoc\n if (tagName === 'IFRAME' && attributeName === 'srcdoc') {\n return CENSORED_STRING_MARK\n }\n }\n\n if (!attributeValue || typeof attributeValue !== 'string') {\n return attributeValue\n }\n\n // Minimum Fix for customer.\n if (isLongDataUrl(attributeValue)) {\n return sanitizeDataUrl(attributeValue)\n }\n\n return attributeValue\n}\n","import { NodePrivacyLevel, shouldMaskNode } from '@datadog/browser-rum-core'\nimport { isSafari } from '@datadog/browser-core'\nimport { getElementInputValue, switchToAbsoluteUrl, getValidTagName } from './serializationUtils'\nimport type { SerializeOptions } from './serialization.types'\nimport { SerializationContextStatus } from './serialization.types'\nimport { serializeAttribute } from './serializeAttribute'\n\nexport function serializeAttributes(\n element: Element,\n nodePrivacyLevel: NodePrivacyLevel,\n options: SerializeOptions\n): Record<string, string | number | boolean> {\n if (nodePrivacyLevel === NodePrivacyLevel.HIDDEN) {\n return {}\n }\n const safeAttrs: Record<string, string | number | boolean> = {}\n const tagName = getValidTagName(element.tagName)\n const doc = element.ownerDocument\n\n for (let i = 0; i < element.attributes.length; i += 1) {\n const attribute = element.attributes.item(i)!\n const attributeName = attribute.name\n const attributeValue = serializeAttribute(element, nodePrivacyLevel, attributeName, options.configuration)\n if (attributeValue !== null) {\n safeAttrs[attributeName] = attributeValue\n }\n }\n\n if (\n (element as HTMLInputElement).value &&\n (tagName === 'textarea' || tagName === 'select' || tagName === 'option' || tagName === 'input')\n ) {\n const formValue = getElementInputValue(element, nodePrivacyLevel)\n if (formValue !== undefined) {\n safeAttrs.value = formValue\n }\n }\n\n /**\n * <Option> can be selected, which occurs if its `value` matches ancestor `<Select>.value`\n */\n if (tagName === 'option' && nodePrivacyLevel === NodePrivacyLevel.ALLOW) {\n // For privacy=`MASK`, all the values would be the same, so skip.\n const optionElement = element as HTMLOptionElement\n if (optionElement.selected) {\n safeAttrs.selected = optionElement.selected\n }\n }\n\n // remote css\n if (tagName === 'link') {\n const stylesheet = Array.from(doc.styleSheets).find((s) => s.href === (element as HTMLLinkElement).href)\n const cssText = getCssRulesString(stylesheet)\n if (cssText && stylesheet) {\n safeAttrs._cssText = cssText\n }\n }\n\n // dynamic stylesheet\n if (tagName === 'style' && (element as HTMLStyleElement).sheet) {\n const cssText = getCssRulesString((element as HTMLStyleElement).sheet)\n if (cssText) {\n safeAttrs._cssText = cssText\n }\n }\n\n /**\n * Forms: input[type=checkbox,radio]\n * The `checked` property for <input> is a little bit special:\n * 1. el.checked is a setter that returns if truthy.\n * 2. getAttribute returns the string value\n * getAttribute('checked') does not sync with `Element.checked`, so use JS property\n * NOTE: `checked` property exists on `HTMLInputElement`. For serializer assumptions, we check for type=radio|check.\n */\n const inputElement = element as HTMLInputElement\n if (tagName === 'input' && (inputElement.type === 'radio' || inputElement.type === 'checkbox')) {\n if (nodePrivacyLevel === NodePrivacyLevel.ALLOW) {\n safeAttrs.checked = !!inputElement.checked\n } else if (shouldMaskNode(inputElement, nodePrivacyLevel)) {\n delete safeAttrs.checked\n }\n }\n\n /**\n * Serialize the media playback state\n */\n if (tagName === 'audio' || tagName === 'video') {\n const mediaElement = element as HTMLMediaElement\n safeAttrs.rr_mediaState = mediaElement.paused ? 'paused' : 'played'\n }\n\n /**\n * Serialize the scroll state for each element only for full snapshot\n */\n let scrollTop: number | undefined\n let scrollLeft: number | undefined\n const serializationContext = options.serializationContext\n switch (serializationContext.status) {\n case SerializationContextStatus.INITIAL_FULL_SNAPSHOT:\n scrollTop = Math.round(element.scrollTop)\n scrollLeft = Math.round(element.scrollLeft)\n if (scrollTop || scrollLeft) {\n serializationContext.elementsScrollPositions.set(element, { scrollTop, scrollLeft })\n }\n break\n case SerializationContextStatus.SUBSEQUENT_FULL_SNAPSHOT:\n if (serializationContext.elementsScrollPositions.has(element)) {\n ;({ scrollTop, scrollLeft } = serializationContext.elementsScrollPositions.get(element)!)\n }\n break\n }\n if (scrollLeft) {\n safeAttrs.rr_scrollLeft = scrollLeft\n }\n if (scrollTop) {\n safeAttrs.rr_scrollTop = scrollTop\n }\n\n return safeAttrs\n}\n\nexport function getCssRulesString(cssStyleSheet: CSSStyleSheet | undefined | null): string | null {\n if (!cssStyleSheet) {\n return null\n }\n let rules: CSSRuleList | undefined\n try {\n rules = cssStyleSheet.rules || cssStyleSheet.cssRules\n } catch {\n // if css is protected by CORS we cannot access cssRules see: https://www.w3.org/TR/cssom-1/#the-cssstylesheet-interface\n }\n if (!rules) {\n return null\n }\n const styleSheetCssText = Array.from(rules, isSafari() ? getCssRuleStringForSafari : getCssRuleString).join('')\n return switchToAbsoluteUrl(styleSheetCssText, cssStyleSheet.href)\n}\n\nfunction getCssRuleStringForSafari(rule: CSSRule): string {\n // Safari does not escape attribute selectors containing : properly\n // https://bugs.webkit.org/show_bug.cgi?id=184604\n if (isCSSStyleRule(rule) && rule.selectorText.includes(':')) {\n // This regex replaces [foo:bar] by [foo\\\\:bar]\n const escapeColon = /(\\[[\\w-]+[^\\\\])(:[^\\]]+\\])/g\n return rule.cssText.replace(escapeColon, '$1\\\\$2')\n }\n\n return getCssRuleString(rule)\n}\n\nfunction getCssRuleString(rule: CSSRule): string {\n // If it's an @import rule, try to inline sub-rules recursively with `getCssRulesString`. This\n // operation can fail if the imported stylesheet is protected by CORS, in which case we fallback\n // to the @import rule CSS text.\n return (isCSSImportRule(rule) && getCssRulesString(rule.styleSheet)) || rule.cssText\n}\n\nfunction isCSSImportRule(rule: CSSRule): rule is CSSImportRule {\n return 'styleSheet' in rule\n}\n\nfunction isCSSStyleRule(rule: CSSRule): rule is CSSStyleRule {\n return 'selectorText' in rule\n}\n","import {\n reducePrivacyLevel,\n getNodeSelfPrivacyLevel,\n getTextContent,\n isNodeShadowRoot,\n hasChildNodes,\n forEachChildNodes,\n NodePrivacyLevel,\n PRIVACY_ATTR_NAME,\n PRIVACY_ATTR_VALUE_HIDDEN,\n} from '@datadog/browser-rum-core'\nimport type {\n DocumentFragmentNode,\n DocumentNode,\n SerializedNode,\n SerializedNodeWithId,\n CDataNode,\n DocumentTypeNode,\n ElementNode,\n TextNode,\n} from '../../../types'\nimport { NodeType } from '../../../types'\nimport { getSerializedNodeId, getValidTagName, setSerializedNodeId } from './serializationUtils'\nimport type { SerializeOptions } from './serialization.types'\nimport { serializeStyleSheets } from './serializeStyleSheets'\nimport { serializeAttributes } from './serializeAttributes'\n\nexport function serializeNodeWithId(node: Node, options: SerializeOptions): SerializedNodeWithId | null {\n const serializedNode = serializeNode(node, options)\n if (!serializedNode) {\n return null\n }\n\n // Try to reuse the previous id\n const id = getSerializedNodeId(node) || generateNextId()\n const serializedNodeWithId = serializedNode as SerializedNodeWithId\n serializedNodeWithId.id = id\n setSerializedNodeId(node, id)\n if (options.serializedNodeIds) {\n options.serializedNodeIds.add(id)\n }\n return serializedNodeWithId\n}\n\nlet _nextId = 1\nexport function generateNextId(): number {\n return _nextId++\n}\n\nexport function serializeChildNodes(node: Node, options: SerializeOptions): SerializedNodeWithId[] {\n const result: SerializedNodeWithId[] = []\n forEachChildNodes(node, (childNode) => {\n const serializedChildNode = serializeNodeWithId(childNode, options)\n if (serializedChildNode) {\n result.push(serializedChildNode)\n }\n })\n return result\n}\n\nfunction serializeNode(node: Node, options: SerializeOptions): SerializedNode | undefined {\n switch (node.nodeType) {\n case node.DOCUMENT_NODE:\n return serializeDocumentNode(node as Document, options)\n case node.DOCUMENT_FRAGMENT_NODE:\n return serializeDocumentFragmentNode(node as DocumentFragment, options)\n case node.DOCUMENT_TYPE_NODE:\n return serializeDocumentTypeNode(node as DocumentType)\n case node.ELEMENT_NODE:\n return serializeElementNode(node as Element, options)\n case node.TEXT_NODE:\n return serializeTextNode(node as Text, options)\n case node.CDATA_SECTION_NODE:\n return serializeCDataNode()\n }\n}\n\nexport function serializeDocumentNode(document: Document, options: SerializeOptions): DocumentNode {\n return {\n type: NodeType.Document,\n childNodes: serializeChildNodes(document, options),\n adoptedStyleSheets: serializeStyleSheets(document.adoptedStyleSheets),\n }\n}\n\nfunction serializeDocumentFragmentNode(\n element: DocumentFragment,\n options: SerializeOptions\n): DocumentFragmentNode | undefined {\n const isShadowRoot = isNodeShadowRoot(element)\n if (isShadowRoot) {\n options.serializationContext.shadowRootsController.addShadowRoot(element)\n }\n\n return {\n type: NodeType.DocumentFragment,\n childNodes: serializeChildNodes(element, options),\n isShadowRoot,\n adoptedStyleSheets: isShadowRoot ? serializeStyleSheets(element.adoptedStyleSheets) : undefined,\n }\n}\n\nfunction serializeDocumentTypeNode(documentType: DocumentType): DocumentTypeNode {\n return {\n type: NodeType.DocumentType,\n name: documentType.name,\n publicId: documentType.publicId,\n systemId: documentType.systemId,\n }\n}\n\n/**\n * Serializing Element nodes involves capturing:\n * 1. HTML ATTRIBUTES:\n * 2. JS STATE:\n * - scroll offsets\n * - Form fields (input value, checkbox checked, option selection, range)\n * - Canvas state,\n * - Media (video/audio) play mode + currentTime\n * - iframe contents\n * - webcomponents\n * 3. CUSTOM PROPERTIES:\n * - height+width for when `hidden` to cover the element\n * 4. EXCLUDED INTERACTION STATE:\n * - focus (possible, but not worth perf impact)\n * - hover (tracked only via mouse activity)\n * - fullscreen mode\n */\n\nfunction serializeElementNode(element: Element, options: SerializeOptions): ElementNode | undefined {\n const tagName = getValidTagName(element.tagName)\n const isSVG = isSVGElement(element) || undefined\n\n // For performance reason, we don't use getNodePrivacyLevel directly: we leverage the\n // parentNodePrivacyLevel option to avoid iterating over all parents\n const nodePrivacyLevel = reducePrivacyLevel(getNodeSelfPrivacyLevel(element), options.parentNodePrivacyLevel)\n\n if (nodePrivacyLevel === NodePrivacyLevel.HIDDEN) {\n const { width, height } = element.getBoundingClientRect()\n return {\n type: NodeType.Element,\n tagName,\n attributes: {\n rr_width: `${width}px`,\n rr_height: `${height}px`,\n [PRIVACY_ATTR_NAME]: PRIVACY_ATTR_VALUE_HIDDEN,\n },\n childNodes: [],\n isSVG,\n }\n }\n\n // Ignore Elements like Script and some Link, Metas\n if (nodePrivacyLevel === NodePrivacyLevel.IGNORE) {\n return\n }\n\n const attributes = serializeAttributes(element, nodePrivacyLevel, options)\n\n let childNodes: SerializedNodeWithId[] = []\n if (\n hasChildNodes(element) &&\n // Do not serialize style children as the css rules are already in the _cssText attribute\n tagName !== 'style'\n ) {\n // OBJECT POOLING OPTIMIZATION:\n // We should not create a new object systematically as it could impact performances. Try to reuse\n // the same object as much as possible, and clone it only if we need to.\n let childNodesSerializationOptions\n if (options.parentNodePrivacyLevel === nodePrivacyLevel && options.ignoreWhiteSpace === (tagName === 'head')) {\n childNodesSerializationOptions = options\n } else {\n childNodesSerializationOptions = {\n ...options,\n parentNodePrivacyLevel: nodePrivacyLevel,\n ignoreWhiteSpace: tagName === 'head',\n }\n }\n childNodes = serializeChildNodes(element, childNodesSerializationOptions)\n }\n\n return {\n type: NodeType.Element,\n tagName,\n attributes,\n childNodes,\n isSVG,\n }\n}\n\nfunction isSVGElement(el: Element): boolean {\n return el.tagName === 'svg' || el instanceof SVGElement\n}\n\n/**\n * Text Nodes are dependant on Element nodes\n * Privacy levels are set on elements so we check the parentElement of a text node\n * for privacy level.\n */\n\nfunction serializeTextNode(textNode: Text, options: SerializeOptions): TextNode | undefined {\n const textContent = getTextContent(textNode, options.ignoreWhiteSpace || false, options.parentNodePrivacyLevel)\n if (textContent === undefined) {\n return\n }\n return {\n type: NodeType.Text,\n textContent,\n }\n}\n\nfunction serializeCDataNode(): CDataNode {\n return {\n type: NodeType.CDATA,\n textContent: '',\n }\n}\n","import type { RumConfiguration } from '@datadog/browser-rum-core'\nimport type { SerializedNodeWithId } from '../../../types'\nimport type { SerializationContext } from './serialization.types'\nimport { serializeNodeWithId } from './serializeNode'\n\nexport function serializeDocument(\n document: Document,\n configuration: RumConfiguration,\n serializationContext: SerializationContext\n): SerializedNodeWithId {\n // We are sure that Documents are never ignored, so this function never returns null\n return serializeNodeWithId(document, {\n serializationContext,\n parentNodePrivacyLevel: configuration.defaultPrivacyLevel,\n configuration,\n })!\n}\n","import { isNodeShadowHost } from '@datadog/browser-rum-core'\n\nexport function isTouchEvent(event: MouseEvent | TouchEvent): event is TouchEvent {\n return Boolean((event as TouchEvent).changedTouches)\n}\n\nexport function getEventTarget(event: Event): Node {\n if (event.composed === true && isNodeShadowHost(event.target as Node)) {\n return event.composedPath()[0] as Node\n }\n return event.target as Node\n}\n","/**\n * Browsers have not standardized various dimension properties. Mobile devices typically report\n * dimensions in reference to the visual viewport, while desktop uses the layout viewport. For example,\n * Mobile Chrome will change innerWidth when a pinch zoom takes place, while Chrome Desktop (mac) will not.\n *\n * With the new Viewport API, we now calculate and normalize dimension properties to the layout viewport.\n * If the VisualViewport API is not supported by a browser, it isn't reasonably possible to detect or normalize\n * which viewport is being measured. Therefore these exported functions will fallback to assuming that the layout\n * viewport is being measured by the browser\n */\n\nimport type { VisualViewportRecord } from '../../types'\n\n// Scrollbar widths vary across properties on different devices and browsers\nconst TOLERANCE = 25\n\n/**\n * Use the Visual Viewport API's properties to measure scrollX/Y in reference to the layout viewport\n * in order to determine if window.scrollX/Y is measuring the layout or visual viewport.\n * This finding corresponds to which viewport mouseEvent.clientX/Y and window.innerWidth/Height measures.\n */\nfunction isVisualViewportFactoredIn(visualViewport: VisualViewport) {\n return (\n Math.abs(visualViewport.pageTop - visualViewport.offsetTop - window.scrollY) > TOLERANCE ||\n Math.abs(visualViewport.pageLeft - visualViewport.offsetLeft - window.scrollX) > TOLERANCE\n )\n}\n\ninterface LayoutCoordinates {\n layoutViewportX: number\n layoutViewportY: number\n visualViewportX: number\n visualViewportY: number\n}\n\nexport const convertMouseEventToLayoutCoordinates = (clientX: number, clientY: number): LayoutCoordinates => {\n const visualViewport = window.visualViewport\n const normalized: LayoutCoordinates = {\n layoutViewportX: clientX,\n layoutViewportY: clientY,\n visualViewportX: clientX,\n visualViewportY: clientY,\n }\n\n if (!visualViewport) {\n // On old browsers, we cannot normalize, so fallback to clientX/Y\n return normalized\n } else if (isVisualViewportFactoredIn(visualViewport)) {\n // Typically Mobile Devices\n normalized.layoutViewportX = Math.round(clientX + visualViewport.offsetLeft)\n normalized.layoutViewportY = Math.round(clientY + visualViewport.offsetTop)\n } else {\n // Typically Desktop Devices\n normalized.visualViewportX = Math.round(clientX - visualViewport.offsetLeft)\n normalized.visualViewportY = Math.round(clientY - visualViewport.offsetTop)\n }\n return normalized\n}\n\nexport const getVisualViewport = (visualViewport: VisualViewport): VisualViewportRecord['data'] => ({\n scale: visualViewport.scale,\n offsetLeft: visualViewport.offsetLeft,\n offsetTop: visualViewport.offsetTop,\n pageLeft: visualViewport.pageLeft,\n pageTop: visualViewport.pageTop,\n height: visualViewport.height,\n width: visualViewport.width,\n})\n","import { timeStampNow } from '@datadog/browser-core'\nimport type { BrowserIncrementalData, BrowserIncrementalSnapshotRecord } from '../../types'\nimport { RecordType } from '../../types'\n\nexport function assembleIncrementalSnapshot<Data extends BrowserIncrementalData>(\n source: Data['source'],\n data: Omit<Data, 'source'>\n): BrowserIncrementalSnapshotRecord {\n return {\n data: {\n source,\n ...data,\n } as Data,\n type: RecordType.IncrementalSnapshot,\n timestamp: timeStampNow(),\n }\n}\n","import { addEventListeners, addTelemetryDebug, DOM_EVENT, throttle } from '@datadog/browser-core'\nimport type { RumConfiguration } from '@datadog/browser-rum-core'\nimport { getSerializedNodeId, hasSerializedNode } from '../serialization'\nimport type { BrowserIncrementalSnapshotRecord, MousemoveData, MousePosition } from '../../../types'\nimport { IncrementalSource } from '../../../types'\nimport { getEventTarget, isTouchEvent } from '../eventsUtils'\nimport { convertMouseEventToLayoutCoordinates } from '../viewports'\nimport { assembleIncrementalSnapshot } from '../assembly'\nimport type { Tracker } from './tracker.types'\n\nconst MOUSE_MOVE_OBSERVER_THRESHOLD = 50\n\nexport type MousemoveCallBack = (incrementalSnapshotRecord: BrowserIncrementalSnapshotRecord) => void\n\nexport function trackMove(configuration: RumConfiguration, moveCb: MousemoveCallBack): Tracker {\n const { throttled: updatePosition, cancel: cancelThrottle } = throttle(\n (event: MouseEvent | TouchEvent) => {\n const target = getEventTarget(event)\n if (hasSerializedNode(target)) {\n const coordinates = tryToComputeCoordinates(event)\n if (!coordinates) {\n return\n }\n const position: MousePosition = {\n id: getSerializedNodeId(target),\n timeOffset: 0,\n x: coordinates.x,\n y: coordinates.y,\n }\n\n moveCb(\n assembleIncrementalSnapshot<MousemoveData>(\n isTouchEvent(event) ? IncrementalSource.TouchMove : IncrementalSource.MouseMove,\n { positions: [position] }\n )\n )\n }\n },\n MOUSE_MOVE_OBSERVER_THRESHOLD,\n {\n trailing: false,\n }\n )\n\n const { stop: removeListener } = addEventListeners(\n configuration,\n document,\n [DOM_EVENT.MOUSE_MOVE, DOM_EVENT.TOUCH_MOVE],\n updatePosition,\n {\n capture: true,\n passive: true,\n }\n )\n\n return {\n stop: () => {\n removeListener()\n cancelThrottle()\n },\n }\n}\n\nexport function tryToComputeCoordinates(event: MouseEvent | TouchEvent) {\n let { clientX: x, clientY: y } = isTouchEvent(event) ? event.changedTouches[0] : event\n if (window.visualViewport) {\n const { visualViewportX, visualViewportY } = convertMouseEventToLayoutCoordinates(x, y)\n x = visualViewportX\n y = visualViewportY\n }\n if (!Number.isFinite(x) || !Number.isFinite(y)) {\n if (event.isTrusted) {\n addTelemetryDebug('mouse/touch event without x/y')\n }\n return undefined\n }\n return { x, y }\n}\n","import { addEventListeners, DOM_EVENT } from '@datadog/browser-core'\nimport { getNodePrivacyLevel, NodePrivacyLevel } from '@datadog/browser-rum-core'\nimport type { RumConfiguration } from '@datadog/browser-rum-core'\nimport type { MouseInteraction, MouseInteractionData, BrowserIncrementalSnapshotRecord } from '../../../types'\nimport { IncrementalSource, MouseInteractionType } from '../../../types'\nimport { assembleIncrementalSnapshot } from '../assembly'\nimport { getEventTarget } from '../eventsUtils'\nimport { getSerializedNodeId, hasSerializedNode } from '../serialization'\nimport type { RecordIds } from '../recordIds'\nimport { tryToComputeCoordinates } from './trackMove'\nimport type { Tracker } from './tracker.types'\n\nconst eventTypeToMouseInteraction = {\n // Listen for pointerup DOM events instead of mouseup for MouseInteraction/MouseUp records. This\n // allows to reference such records from Frustration records.\n //\n // In the context of supporting Mobile Session Replay, we introduced `PointerInteraction` records\n // used by the Mobile SDKs in place of `MouseInteraction`. In the future, we should replace\n // `MouseInteraction` by `PointerInteraction` in the Browser SDK so we have an uniform way to\n // convey such interaction. This would cleanly solve the issue since we would have\n // `PointerInteraction/Up` records that we could reference from `Frustration` records.\n [DOM_EVENT.POINTER_UP]: MouseInteractionType.MouseUp,\n\n [DOM_EVENT.MOUSE_DOWN]: MouseInteractionType.MouseDown,\n [DOM_EVENT.CLICK]: MouseInteractionType.Click,\n [DOM_EVENT.CONTEXT_MENU]: MouseInteractionType.ContextMenu,\n [DOM_EVENT.DBL_CLICK]: MouseInteractionType.DblClick,\n [DOM_EVENT.FOCUS]: MouseInteractionType.Focus,\n [DOM_EVENT.BLUR]: MouseInteractionType.Blur,\n [DOM_EVENT.TOUCH_START]: MouseInteractionType.TouchStart,\n [DOM_EVENT.TOUCH_END]: MouseInteractionType.TouchEnd,\n}\n\nexport type MouseInteractionCallback = (record: BrowserIncrementalSnapshotRecord) => void\n\nexport function trackMouseInteraction(\n configuration: RumConfiguration,\n mouseInteractionCb: MouseInteractionCallback,\n recordIds: RecordIds\n): Tracker {\n const handler = (event: MouseEvent | TouchEvent | FocusEvent) => {\n const target = getEventTarget(event)\n if (\n getNodePrivacyLevel(target, configuration.defaultPrivacyLevel) === NodePrivacyLevel.HIDDEN ||\n !hasSerializedNode(target)\n ) {\n return\n }\n const id = getSerializedNodeId(target)\n const type = eventTypeToMouseInteraction[event.type as keyof typeof eventTypeToMouseInteraction]\n\n let interaction: MouseInteraction\n if (type !== MouseInteractionType.Blur && type !== MouseInteractionType.Focus) {\n const coordinates = tryToComputeCoordinates(event as MouseEvent | TouchEvent)\n if (!coordinates) {\n return\n }\n interaction = { id, type, x: coordinates.x, y: coordinates.y }\n } else {\n interaction = { id, type }\n }\n\n const record = {\n id: recordIds.getIdForEvent(event),\n ...assembleIncrementalSnapshot<MouseInteractionData>(IncrementalSource.MouseInteraction, interaction),\n }\n\n mouseInteractionCb(record)\n }\n return addEventListeners(\n configuration,\n document,\n Object.keys(eventTypeToMouseInteraction) as Array<keyof typeof eventTypeToMouseInteraction>,\n handler,\n {\n capture: true,\n passive: true,\n }\n )\n}\n","import { DOM_EVENT, throttle, addEventListener } from '@datadog/browser-core'\nimport type { RumConfiguration } from '@datadog/browser-rum-core'\nimport { getScrollX, getScrollY, getNodePrivacyLevel, NodePrivacyLevel } from '@datadog/browser-rum-core'\nimport type { ElementsScrollPositions } from '../elementsScrollPositions'\nimport { getEventTarget } from '../eventsUtils'\nimport { getSerializedNodeId, hasSerializedNode } from '../serialization'\nimport { IncrementalSource } from '../../../types'\nimport type { BrowserIncrementalSnapshotRecord, ScrollData } from '../../../types'\nimport { assembleIncrementalSnapshot } from '../assembly'\nimport type { Tracker } from './tracker.types'\n\nconst SCROLL_OBSERVER_THRESHOLD = 100\n\nexport type ScrollCallback = (incrementalSnapshotRecord: BrowserIncrementalSnapshotRecord) => void\n\nexport function trackScroll(\n configuration: RumConfiguration,\n scrollCb: ScrollCallback,\n elementsScrollPositions: ElementsScrollPositions,\n target: Document | ShadowRoot = document\n): Tracker {\n const { throttled: updatePosition, cancel: cancelThrottle } = throttle((event: Event) => {\n const target = getEventTarget(event) as HTMLElement | Document\n if (\n !target ||\n getNodePrivacyLevel(target, configuration.defaultPrivacyLevel) === NodePrivacyLevel.HIDDEN ||\n !hasSerializedNode(target)\n ) {\n return\n }\n const id = getSerializedNodeId(target)\n const scrollPositions =\n target === document\n ? {\n scrollTop: getScrollY(),\n scrollLeft: getScrollX(),\n }\n : {\n scrollTop: Math.round((target as HTMLElement).scrollTop),\n scrollLeft: Math.round((target as HTMLElement).scrollLeft),\n }\n elementsScrollPositions.set(target, scrollPositions)\n scrollCb(\n assembleIncrementalSnapshot<ScrollData>(IncrementalSource.Scroll, {\n id,\n x: scrollPositions.scrollLeft,\n y: scrollPositions.scrollTop,\n })\n )\n }, SCROLL_OBSERVER_THRESHOLD)\n\n const { stop: removeListener } = addEventListener(configuration, target, DOM_EVENT.SCROLL, updatePosition, {\n capture: true,\n passive: true,\n })\n\n return {\n stop: () => {\n removeListener()\n cancelThrottle()\n },\n }\n}\n","import { throttle, DOM_EVENT, addEventListeners, timeStampNow, noop } from '@datadog/browser-core'\nimport type { RumConfiguration, ViewportDimension } from '@datadog/browser-rum-core'\nimport { initViewportObservable } from '@datadog/browser-rum-core'\nimport { IncrementalSource, RecordType } from '../../../types'\nimport type { BrowserIncrementalSnapshotRecord, ViewportResizeData, VisualViewportRecord } from '../../../types'\nimport { getVisualViewport } from '../viewports'\nimport { assembleIncrementalSnapshot } from '../assembly'\nimport type { Tracker } from './tracker.types'\n\nconst VISUAL_VIEWPORT_OBSERVER_THRESHOLD = 200\n\nexport type ViewportResizeCallback = (incrementalSnapshotRecord: BrowserIncrementalSnapshotRecord) => void\n\nexport type VisualViewportResizeCallback = (visualViewportRecord: VisualViewportRecord) => void\n\nexport function trackViewportResize(\n configuration: RumConfiguration,\n viewportResizeCb: ViewportResizeCallback\n): Tracker {\n const viewportResizeSubscription = initViewportObservable(configuration).subscribe((data: ViewportDimension) => {\n viewportResizeCb(assembleIncrementalSnapshot<ViewportResizeData>(IncrementalSource.ViewportResize, data))\n })\n\n return {\n stop: () => {\n viewportResizeSubscription.unsubscribe()\n },\n }\n}\n\nexport function trackVisualViewportResize(\n configuration: RumConfiguration,\n visualViewportResizeCb: VisualViewportResizeCallback\n): Tracker {\n const visualViewport = window.visualViewport\n if (!visualViewport) {\n return { stop: noop }\n }\n const { throttled: updateDimension, cancel: cancelThrottle } = throttle(\n () => {\n visualViewportResizeCb({\n data: getVisualViewport(visualViewport),\n type: RecordType.VisualViewport,\n timestamp: timeStampNow(),\n })\n },\n VISUAL_VIEWPORT_OBSERVER_THRESHOLD,\n {\n trailing: false,\n }\n )\n const { stop: removeListener } = addEventListeners(\n configuration,\n visualViewport,\n [DOM_EVENT.RESIZE, DOM_EVENT.SCROLL],\n updateDimension,\n {\n capture: true,\n passive: true,\n }\n )\n\n return {\n stop: () => {\n removeListener()\n cancelThrottle()\n },\n }\n}\n","import { DOM_EVENT, addEventListeners } from '@datadog/browser-core'\nimport type { RumConfiguration } from '@datadog/browser-rum-core'\nimport { NodePrivacyLevel, getNodePrivacyLevel } from '@datadog/browser-rum-core'\nimport type { BrowserIncrementalSnapshotRecord, MediaInteractionData } from '../../../types'\nimport { IncrementalSource, MediaInteractionType } from '../../../types'\nimport { getEventTarget } from '../eventsUtils'\nimport { getSerializedNodeId, hasSerializedNode } from '../serialization'\nimport { assembleIncrementalSnapshot } from '../assembly'\nimport type { Tracker } from './tracker.types'\n\nexport type MediaInteractionCallback = (incrementalSnapshotRecord: BrowserIncrementalSnapshotRecord) => void\n\nexport function trackMediaInteraction(\n configuration: RumConfiguration,\n mediaInteractionCb: MediaInteractionCallback\n): Tracker {\n return addEventListeners(\n configuration,\n document,\n [DOM_EVENT.PLAY, DOM_EVENT.PAUSE],\n (event) => {\n const target = getEventTarget(event)\n if (\n !target ||\n getNodePrivacyLevel(target, configuration.defaultPrivacyLevel) === NodePrivacyLevel.HIDDEN ||\n !hasSerializedNode(target)\n ) {\n return\n }\n mediaInteractionCb(\n assembleIncrementalSnapshot<MediaInteractionData>(IncrementalSource.MediaInteraction, {\n id: getSerializedNodeId(target),\n type: event.type === DOM_EVENT.PLAY ? MediaInteractionType.Play : MediaInteractionType.Pause,\n })\n )\n },\n {\n capture: true,\n passive: true,\n }\n )\n}\n","import { instrumentMethod } from '@datadog/browser-core'\nimport { IncrementalSource } from '../../../types'\nimport type { StyleSheetRuleData, BrowserIncrementalSnapshotRecord } from '../../../types'\nimport { getSerializedNodeId, hasSerializedNode } from '../serialization'\nimport { assembleIncrementalSnapshot } from '../assembly'\nimport type { Tracker } from './tracker.types'\n\ntype GroupingCSSRuleTypes = typeof CSSGroupingRule | typeof CSSMediaRule | typeof CSSSupportsRule\n\nexport type StyleSheetCallback = (incrementalSnapshotRecord: BrowserIncrementalSnapshotRecord) => void\n\nexport function trackStyleSheet(styleSheetCb: StyleSheetCallback): Tracker {\n function checkStyleSheetAndCallback(styleSheet: CSSStyleSheet | null, callback: (id: number) => void): void {\n if (styleSheet && hasSerializedNode(styleSheet.ownerNode!)) {\n callback(getSerializedNodeId(styleSheet.ownerNode))\n }\n }\n\n const instrumentationStoppers = [\n instrumentMethod(CSSStyleSheet.prototype, 'insertRule', ({ target: styleSheet, parameters: [rule, index] }) => {\n checkStyleSheetAndCallback(styleSheet, (id) =>\n styleSheetCb(\n assembleIncrementalSnapshot<StyleSheetRuleData>(IncrementalSource.StyleSheetRule, {\n id,\n adds: [{ rule, index }],\n })\n )\n )\n }),\n\n instrumentMethod(CSSStyleSheet.prototype, 'deleteRule', ({ target: styleSheet, parameters: [index] }) => {\n checkStyleSheetAndCallback(styleSheet, (id) =>\n styleSheetCb(\n assembleIncrementalSnapshot<StyleSheetRuleData>(IncrementalSource.StyleSheetRule, {\n id,\n removes: [{ index }],\n })\n )\n )\n }),\n ]\n\n if (typeof CSSGroupingRule !== 'undefined') {\n instrumentGroupingCSSRuleClass(CSSGroupingRule)\n } else {\n instrumentGroupingCSSRuleClass(CSSMediaRule)\n instrumentGroupingCSSRuleClass(CSSSupportsRule)\n }\n\n function instrumentGroupingCSSRuleClass(cls: GroupingCSSRuleTypes) {\n instrumentationStoppers.push(\n instrumentMethod(cls.prototype, 'insertRule', ({ target: styleSheet, parameters: [rule, index] }) => {\n checkStyleSheetAndCallback(styleSheet.parentStyleSheet, (id) => {\n const path = getPathToNestedCSSRule(styleSheet)\n if (path) {\n path.push(index || 0)\n styleSheetCb(\n assembleIncrementalSnapshot<StyleSheetRuleData>(IncrementalSource.StyleSheetRule, {\n id,\n adds: [{ rule, index: path }],\n })\n )\n }\n })\n }),\n\n instrumentMethod(cls.prototype, 'deleteRule', ({ target: styleSheet, parameters: [index] }) => {\n checkStyleSheetAndCallback(styleSheet.parentStyleSheet, (id) => {\n const path = getPathToNestedCSSRule(styleSheet)\n if (path) {\n path.push(index)\n styleSheetCb(\n assembleIncrementalSnapshot<StyleSheetRuleData>(IncrementalSource.StyleSheetRule, {\n id,\n removes: [{ index: path }],\n })\n )\n }\n })\n })\n )\n }\n\n return {\n stop: () => {\n instrumentationStoppers.forEach((stopper) => stopper.stop())\n },\n }\n}\n\nexport function getPathToNestedCSSRule(rule: CSSRule): number[] | undefined {\n const path: number[] = []\n let currentRule = rule\n while (currentRule.parentRule) {\n const rules = Array.from((currentRule.parentRule as CSSGroupingRule).cssRules)\n const index = rules.indexOf(currentRule)\n path.unshift(index)\n currentRule = currentRule.parentRule\n }\n // A rule may not be attached to a stylesheet\n if (!currentRule.parentStyleSheet) {\n return\n }\n\n const rules = Array.from(currentRule.parentStyleSheet.cssRules)\n const index = rules.indexOf(currentRule)\n path.unshift(index)\n\n return path\n}\n","import { DOM_EVENT, addEventListeners, timeStampNow } from '@datadog/browser-core'\nimport type { RumConfiguration } from '@datadog/browser-rum-core'\nimport { RecordType, type FocusRecord } from '../../../types'\nimport type { Tracker } from './tracker.types'\n\nexport type FocusCallback = (data: FocusRecord) => void\n\nexport function trackFocus(configuration: RumConfiguration, focusCb: FocusCallback): Tracker {\n return addEventListeners(configuration, window, [DOM_EVENT.FOCUS, DOM_EVENT.BLUR], () => {\n focusCb({\n data: { has_focus: document.hasFocus() },\n type: RecordType.Focus,\n timestamp: timeStampNow(),\n })\n })\n}\n","import type { LifeCycle } from '@datadog/browser-rum-core'\nimport { ActionType, RumEventType, LifeCycleEventType } from '@datadog/browser-rum-core'\nimport type { FrustrationRecord } from '../../../types'\nimport { RecordType } from '../../../types'\nimport type { RecordIds } from '../recordIds'\nimport type { Tracker } from './tracker.types'\n\nexport type FrustrationCallback = (record: FrustrationRecord) => void\n\nexport function trackFrustration(\n lifeCycle: LifeCycle,\n frustrationCb: FrustrationCallback,\n recordIds: RecordIds\n): Tracker {\n const frustrationSubscription = lifeCycle.subscribe(LifeCycleEventType.RAW_RUM_EVENT_COLLECTED, (data) => {\n if (\n data.rawRumEvent.type === RumEventType.ACTION &&\n data.rawRumEvent.action.type === ActionType.CLICK &&\n data.rawRumEvent.action.frustration?.type?.length &&\n 'events' in data.domainContext &&\n data.domainContext.events &&\n data.domainContext.events.length\n ) {\n frustrationCb({\n timestamp: data.rawRumEvent.date,\n type: RecordType.FrustrationRecord,\n data: {\n frustrationTypes: data.rawRumEvent.action.frustration.type,\n recordIds: data.domainContext.events.map((e) => recordIds.getIdForEvent(e)),\n },\n })\n }\n })\n\n return {\n stop: () => {\n frustrationSubscription.unsubscribe()\n },\n }\n}\n","import { timeStampNow } from '@datadog/browser-core'\nimport type { LifeCycle } from '@datadog/browser-rum-core'\nimport { LifeCycleEventType } from '@datadog/browser-rum-core'\nimport type { ViewEndRecord } from '../../../types'\nimport { RecordType } from '../../../types'\nimport type { Tracker } from './tracker.types'\n\nexport type ViewEndCallback = (record: ViewEndRecord) => void\n\nexport function trackViewEnd(lifeCycle: LifeCycle, viewEndCb: ViewEndCallback): Tracker {\n const viewEndSubscription = lifeCycle.subscribe(LifeCycleEventType.VIEW_ENDED, () => {\n viewEndCb({\n timestamp: timeStampNow(),\n type: RecordType.ViewEnd,\n })\n })\n\n return {\n stop: () => {\n viewEndSubscription.unsubscribe()\n },\n }\n}\n","import { instrumentSetter, DOM_EVENT, addEventListeners, noop } from '@datadog/browser-core'\nimport { NodePrivacyLevel, getNodePrivacyLevel, shouldMaskNode } from '@datadog/browser-rum-core'\nimport type { RumConfiguration } from '@datadog/browser-rum-core'\nimport { IncrementalSource } from '../../../types'\nimport type { BrowserIncrementalSnapshotRecord, InputData, InputState } from '../../../types'\nimport { getEventTarget } from '../eventsUtils'\nimport { getElementInputValue, getSerializedNodeId, hasSerializedNode } from '../serialization'\nimport { assembleIncrementalSnapshot } from '../assembly'\nimport type { Tracker } from './tracker.types'\n\nexport type InputCallback = (incrementalSnapshotRecord: BrowserIncrementalSnapshotRecord) => void\n\nexport function trackInput(\n configuration: RumConfiguration,\n inputCb: InputCallback,\n target: Document | ShadowRoot = document\n): Tracker {\n const defaultPrivacyLevel = configuration.defaultPrivacyLevel\n const lastInputStateMap: WeakMap<Node, InputState> = new WeakMap()\n\n const isShadowRoot = target !== document\n\n const { stop: stopEventListeners } = addEventListeners(\n configuration,\n target,\n // The 'input' event bubbles across shadow roots, so we don't have to listen for it on shadow\n // roots since it will be handled by the event listener that we did add to the document. Only\n // the 'change' event is blocked and needs to be handled on shadow roots.\n isShadowRoot ? [DOM_EVENT.CHANGE] : [DOM_EVENT.INPUT, DOM_EVENT.CHANGE],\n (event) => {\n const target = getEventTarget(event)\n if (\n target instanceof HTMLInputElement ||\n target instanceof HTMLTextAreaElement ||\n target instanceof HTMLSelectElement\n ) {\n onElementChange(target)\n }\n },\n {\n capture: true,\n passive: true,\n }\n )\n\n let stopPropertySetterInstrumentation: () => void\n if (!isShadowRoot) {\n const instrumentationStoppers = [\n instrumentSetter(HTMLInputElement.prototype, 'value', onElementChange),\n instrumentSetter(HTMLInputElement.prototype, 'checked', onElementChange),\n instrumentSetter(HTMLSelectElement.prototype, 'value', onElementChange),\n instrumentSetter(HTMLTextAreaElement.prototype, 'value', onElementChange),\n instrumentSetter(HTMLSelectElement.prototype, 'selectedIndex', onElementChange),\n ]\n stopPropertySetterInstrumentation = () => {\n instrumentationStoppers.forEach((stopper) => stopper.stop())\n }\n } else {\n stopPropertySetterInstrumentation = noop\n }\n\n return {\n stop: () => {\n stopPropertySetterInstrumentation()\n stopEventListeners()\n },\n }\n\n function onElementChange(target: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement) {\n const nodePrivacyLevel = getNodePrivacyLevel(target, defaultPrivacyLevel)\n if (nodePrivacyLevel === NodePrivacyLevel.HIDDEN) {\n return\n }\n\n const type = target.type\n\n let inputState: InputState\n if (type === 'radio' || type === 'checkbox') {\n if (shouldMaskNode(target, nodePrivacyLevel)) {\n return\n }\n inputState = { isChecked: (target as HTMLInputElement).checked }\n } else {\n const value = getElementInputValue(target, nodePrivacyLevel)\n if (value === undefined) {\n return\n }\n inputState = { text: value }\n }\n\n // Can be multiple changes on the same node within the same batched mutation observation.\n cbWithDedup(target, inputState)\n\n // If a radio was checked, other radios with the same name attribute will be unchecked.\n const name = target.name\n if (type === 'radio' && name && (target as HTMLInputElement).checked) {\n document.querySelectorAll(`input[type=\"radio\"][name=\"${CSS.escape(name)}\"]`).forEach((el: Element) => {\n if (el !== target) {\n // TODO: Consider the privacy implications for various differing input privacy levels\n cbWithDedup(el, { isChecked: false })\n }\n })\n }\n }\n\n /**\n * There can be multiple changes on the same node within the same batched mutation observation.\n */\n function cbWithDedup(target: Node, inputState: InputState) {\n if (!hasSerializedNode(target)) {\n return\n }\n const lastInputState = lastInputStateMap.get(target)\n if (\n !lastInputState ||\n (lastInputState as { text?: string }).text !== (inputState as { text?: string }).text ||\n (lastInputState as { isChecked?: boolean }).isChecked !== (inputState as { isChecked?: boolean }).isChecked\n ) {\n lastInputStateMap.set(target, inputState)\n inputCb(\n assembleIncrementalSnapshot<InputData>(IncrementalSource.Input, {\n id: getSerializedNodeId(target),\n ...inputState,\n })\n )\n }\n }\n}\n","import { noop, throttle, requestIdleCallback } from '@datadog/browser-core'\nimport type { RumMutationRecord } from './trackers'\n\n/**\n * Maximum duration to wait before processing mutations. If the browser is idle, mutations will be\n * processed more quickly. If the browser is busy executing small tasks (ex: rendering frames), the\n * mutations will wait MUTATION_PROCESS_MAX_DELAY milliseconds before being processed. If the\n * browser is busy executing a longer task, mutations will be processed after this task.\n */\nconst MUTATION_PROCESS_MAX_DELAY = 100\n/**\n * Minimum duration to wait before processing mutations. This is used to batch mutations together\n * and be able to deduplicate them to save processing time and bandwidth.\n * 16ms is the duration of a frame at 60fps that ensure fluid UI.\n */\nexport const MUTATION_PROCESS_MIN_DELAY = 16\n\nexport function createMutationBatch(processMutationBatch: (mutations: RumMutationRecord[]) => void) {\n let cancelScheduledFlush = noop\n let pendingMutations: RumMutationRecord[] = []\n\n function flush() {\n cancelScheduledFlush()\n processMutationBatch(pendingMutations)\n pendingMutations = []\n }\n\n const { throttled: throttledFlush, cancel: cancelThrottle } = throttle(flush, MUTATION_PROCESS_MIN_DELAY, {\n leading: false,\n })\n\n return {\n addMutations: (mutations: RumMutationRecord[]) => {\n if (pendingMutations.length === 0) {\n cancelScheduledFlush = requestIdleCallback(throttledFlush, { timeout: MUTATION_PROCESS_MAX_DELAY })\n }\n pendingMutations.push(...mutations)\n },\n\n flush,\n\n stop: () => {\n cancelScheduledFlush()\n cancelThrottle()\n },\n }\n}\n","import { monitor, noop } from '@datadog/browser-core'\nimport type { RumConfiguration, NodePrivacyLevelCache } from '@datadog/browser-rum-core'\nimport {\n isNodeShadowHost,\n getMutationObserverConstructor,\n getParentNode,\n forEachChildNodes,\n getNodePrivacyLevel,\n getTextContent,\n NodePrivacyLevel,\n} from '@datadog/browser-rum-core'\nimport { IncrementalSource } from '../../../types'\nimport type {\n BrowserMutationData,\n AddedNodeMutation,\n AttributeMutation,\n RemovedNodeMutation,\n TextMutation,\n BrowserIncrementalSnapshotRecord,\n} from '../../../types'\nimport type { NodeWithSerializedNode } from '../serialization'\nimport {\n getElementInputValue,\n getSerializedNodeId,\n hasSerializedNode,\n nodeAndAncestorsHaveSerializedNode,\n serializeNodeWithId,\n SerializationContextStatus,\n serializeAttribute,\n} from '../serialization'\nimport { createMutationBatch } from '../mutationBatch'\nimport type { ShadowRootCallBack, ShadowRootsController } from '../shadowRootsController'\nimport { assembleIncrementalSnapshot } from '../assembly'\nimport type { Tracker } from './tracker.types'\n\nexport type MutationCallBack = (incrementalSnapshotRecord: BrowserIncrementalSnapshotRecord) => void\n\ntype WithSerializedTarget<T> = T & { target: NodeWithSerializedNode }\n\n// https://dom.spec.whatwg.org/#interface-mutationrecord\ninterface RumCharacterDataMutationRecord {\n type: 'characterData'\n target: Node\n oldValue: string | null\n}\n\ninterface RumAttributesMutationRecord {\n type: 'attributes'\n target: Element\n oldValue: string | null\n attributeName: string | null\n}\n\ninterface RumChildListMutationRecord {\n type: 'childList'\n target: Node\n addedNodes: NodeList\n removedNodes: NodeList\n}\n\nexport type RumMutationRecord =\n | RumCharacterDataMutationRecord\n | RumAttributesMutationRecord\n | RumChildListMutationRecord\n\nexport type MutationTracker = Tracker & { flush: () => void }\n\n/**\n * Buffers and aggregate mutations generated by a MutationObserver into MutationPayload\n */\nexport function trackMutation(\n mutationCallback: MutationCallBack,\n configuration: RumConfiguration,\n shadowRootsController: ShadowRootsController,\n target: Node\n): MutationTracker {\n const MutationObserver = getMutationObserverConstructor()\n if (!MutationObserver) {\n return { stop: noop, flush: noop }\n }\n\n const mutationBatch = createMutationBatch((mutations) => {\n processMutations(\n mutations.concat(observer.takeRecords() as RumMutationRecord[]),\n mutationCallback,\n configuration,\n shadowRootsController\n )\n })\n\n const observer = new MutationObserver(monitor(mutationBatch.addMutations) as (callback: MutationRecord[]) => void)\n\n observer.observe(target, {\n attributeOldValue: true,\n attributes: true,\n characterData: true,\n characterDataOldValue: true,\n childList: true,\n subtree: true,\n })\n\n return {\n stop: () => {\n observer.disconnect()\n mutationBatch.stop()\n },\n flush: () => {\n mutationBatch.flush()\n },\n }\n}\n\nfunction processMutations(\n mutations: RumMutationRecord[],\n mutationCallback: MutationCallBack,\n configuration: RumConfiguration,\n shadowRootsController: ShadowRootsController\n) {\n const nodePrivacyLevelCache: NodePrivacyLevelCache = new Map()\n\n mutations\n .filter((mutation): mutation is RumChildListMutationRecord => mutation.type === 'childList')\n .forEach((mutation) => {\n mutation.removedNodes.forEach((removedNode) => {\n traverseRemovedShadowDom(removedNode, shadowRootsController.removeShadowRoot)\n })\n })\n\n // Discard any mutation with a 'target' node that:\n // * isn't injected in the current document or isn't known/serialized yet: those nodes are likely\n // part of a mutation occurring in a parent Node\n // * should be hidden or ignored\n const filteredMutations = mutations.filter(\n (mutation): mutation is WithSerializedTarget<RumMutationRecord> =>\n mutation.target.isConnected &&\n nodeAndAncestorsHaveSerializedNode(mutation.target) &&\n getNodePrivacyLevel(mutation.target, configuration.defaultPrivacyLevel, nodePrivacyLevelCache) !==\n NodePrivacyLevel.HIDDEN\n )\n\n const { adds, removes, hasBeenSerialized } = processChildListMutations(\n filteredMutations.filter(\n (mutation): mutation is WithSerializedTarget<RumChildListMutationRecord> => mutation.type === 'childList'\n ),\n configuration,\n shadowRootsController,\n nodePrivacyLevelCache\n )\n\n const texts = processCharacterDataMutations(\n filteredMutations.filter(\n (mutation): mutation is WithSerializedTarget<RumCharacterDataMutationRecord> =>\n mutation.type === 'characterData' && !hasBeenSerialized(mutation.target)\n ),\n configuration,\n nodePrivacyLevelCache\n )\n\n const attributes = processAttributesMutations(\n filteredMutations.filter(\n (mutation): mutation is WithSerializedTarget<RumAttributesMutationRecord> =>\n mutation.type === 'attributes' && !hasBeenSerialized(mutation.target)\n ),\n configuration,\n nodePrivacyLevelCache\n )\n\n if (!texts.length && !attributes.length && !removes.length && !adds.length) {\n return\n }\n\n mutationCallback(\n assembleIncrementalSnapshot<BrowserMutationData>(IncrementalSource.Mutation, { adds, removes, texts, attributes })\n )\n}\n\nfunction processChildListMutations(\n mutations: Array<WithSerializedTarget<RumChildListMutationRecord>>,\n configuration: RumConfiguration,\n shadowRootsController: ShadowRootsController,\n nodePrivacyLevelCache: NodePrivacyLevelCache\n) {\n // First, we iterate over mutations to collect:\n //\n // * nodes that have been added in the document and not removed by a subsequent mutation\n // * nodes that have been removed from the document but were not added in a previous mutation\n //\n // For this second category, we also collect their previous parent (mutation.target) because we'll\n // need it to emit a 'remove' mutation.\n //\n // Those two categories may overlap: if a node moved from a position to another, it is reported as\n // two mutation records, one with a \"removedNodes\" and the other with \"addedNodes\". In this case,\n // the node will be in both sets.\n const addedAndMovedNodes = new Set<Node>()\n const removedNodes = new Map<Node, NodeWithSerializedNode>()\n for (const mutation of mutations) {\n mutation.addedNodes.forEach((node) => {\n addedAndMovedNodes.add(node)\n })\n mutation.removedNodes.forEach((node) => {\n if (!addedAndMovedNodes.has(node)) {\n removedNodes.set(node, mutation.target)\n }\n addedAndMovedNodes.delete(node)\n })\n }\n\n // Then, we sort nodes that are still in the document by topological order, for two reasons:\n //\n // * We will serialize each added nodes with their descendants. We don't want to serialize a node\n // twice, so we need to iterate over the parent nodes first and skip any node that is contained in\n // a precedent node.\n //\n // * To emit \"add\" mutations, we need references to the parent and potential next sibling of each\n // added node. So we need to iterate over the parent nodes first, and when multiple nodes are\n // siblings, we want to iterate from last to first. This will ensure that any \"next\" node is\n // already serialized and have an id.\n const sortedAddedAndMovedNodes = Array.from(addedAndMovedNodes)\n sortAddedAndMovedNodes(sortedAddedAndMovedNodes)\n\n // Then, we iterate over our sorted node sets to emit mutations. We collect the newly serialized\n // node ids in a set to be able to skip subsequent related mutations.\n const serializedNodeIds = new Set<number>()\n\n const addedNodeMutations: AddedNodeMutation[] = []\n for (const node of sortedAddedAndMovedNodes) {\n if (hasBeenSerialized(node)) {\n continue\n }\n\n const parentNodePrivacyLevel = getNodePrivacyLevel(\n node.parentNode!,\n configuration.defaultPrivacyLevel,\n nodePrivacyLevelCache\n )\n if (parentNodePrivacyLevel === NodePrivacyLevel.HIDDEN || parentNodePrivacyLevel === NodePrivacyLevel.IGNORE) {\n continue\n }\n\n const serializedNode = serializeNodeWithId(node, {\n serializedNodeIds,\n parentNodePrivacyLevel,\n serializationContext: { status: SerializationContextStatus.MUTATION, shadowRootsController },\n configuration,\n })\n if (!serializedNode) {\n continue\n }\n\n const parentNode = getParentNode(node)!\n addedNodeMutations.push({\n nextId: getNextSibling(node),\n parentId: getSerializedNodeId(parentNode)!,\n node: serializedNode,\n })\n }\n // Finally, we emit remove mutations.\n const removedNodeMutations: RemovedNodeMutation[] = []\n removedNodes.forEach((parent, node) => {\n if (hasSerializedNode(node)) {\n removedNodeMutations.push({\n parentId: getSerializedNodeId(parent),\n id: getSerializedNodeId(node),\n })\n }\n })\n\n return { adds: addedNodeMutations, removes: removedNodeMutations, hasBeenSerialized }\n\n function hasBeenSerialized(node: Node) {\n return hasSerializedNode(node) && serializedNodeIds.has(getSerializedNodeId(node))\n }\n\n function getNextSibling(node: Node): null | number {\n let nextSibling = node.nextSibling\n while (nextSibling) {\n if (hasSerializedNode(nextSibling)) {\n return getSerializedNodeId(nextSibling)\n }\n nextSibling = nextSibling.nextSibling\n }\n\n return null\n }\n}\n\nfunction processCharacterDataMutations(\n mutations: Array<WithSerializedTarget<RumCharacterDataMutationRecord>>,\n configuration: RumConfiguration,\n nodePrivacyLevelCache: NodePrivacyLevelCache\n) {\n const textMutations: TextMutation[] = []\n\n // Deduplicate mutations based on their target node\n const handledNodes = new Set<Node>()\n const filteredMutations = mutations.filter((mutation) => {\n if (handledNodes.has(mutation.target)) {\n return false\n }\n handledNodes.add(mutation.target)\n return true\n })\n\n // Emit mutations\n for (const mutation of filteredMutations) {\n const value = mutation.target.textContent\n if (value === mutation.oldValue) {\n continue\n }\n\n const parentNodePrivacyLevel = getNodePrivacyLevel(\n getParentNode(mutation.target)!,\n configuration.defaultPrivacyLevel,\n nodePrivacyLevelCache\n )\n if (parentNodePrivacyLevel === NodePrivacyLevel.HIDDEN || parentNodePrivacyLevel === NodePrivacyLevel.IGNORE) {\n continue\n }\n\n textMutations.push({\n id: getSerializedNodeId(mutation.target),\n // TODO: pass a valid \"ignoreWhiteSpace\" argument\n value: getTextContent(mutation.target, false, parentNodePrivacyLevel) ?? null,\n })\n }\n\n return textMutations\n}\n\nfunction processAttributesMutations(\n mutations: Array<WithSerializedTarget<RumAttributesMutationRecord>>,\n configuration: RumConfiguration,\n nodePrivacyLevelCache: NodePrivacyLevelCache\n) {\n const attributeMutations: AttributeMutation[] = []\n\n // Deduplicate mutations based on their target node and changed attribute\n const handledElements = new Map<Element, Set<string>>()\n const filteredMutations = mutations.filter((mutation) => {\n const handledAttributes = handledElements.get(mutation.target)\n if (handledAttributes && handledAttributes.has(mutation.attributeName!)) {\n return false\n }\n if (!handledAttributes) {\n handledElements.set(mutation.target, new Set([mutation.attributeName!]))\n } else {\n handledAttributes.add(mutation.attributeName!)\n }\n return true\n })\n\n // Emit mutations\n const emittedMutations = new Map<Element, AttributeMutation>()\n for (const mutation of filteredMutations) {\n const uncensoredValue = mutation.target.getAttribute(mutation.attributeName!)\n if (uncensoredValue === mutation.oldValue) {\n continue\n }\n const privacyLevel = getNodePrivacyLevel(mutation.target, configuration.defaultPrivacyLevel, nodePrivacyLevelCache)\n const attributeValue = serializeAttribute(mutation.target, privacyLevel, mutation.attributeName!, configuration)\n\n let transformedValue: string | null\n if (mutation.attributeName === 'value') {\n const inputValue = getElementInputValue(mutation.target, privacyLevel)\n if (inputValue === undefined) {\n continue\n }\n transformedValue = inputValue\n } else if (typeof attributeValue === 'string') {\n transformedValue = attributeValue\n } else {\n transformedValue = null\n }\n\n let emittedMutation = emittedMutations.get(mutation.target)\n if (!emittedMutation) {\n emittedMutation = {\n id: getSerializedNodeId(mutation.target),\n attributes: {},\n }\n attributeMutations.push(emittedMutation)\n emittedMutations.set(mutation.target, emittedMutation)\n }\n\n emittedMutation.attributes[mutation.attributeName!] = transformedValue\n }\n\n return attributeMutations\n}\n\nexport function sortAddedAndMovedNodes(nodes: Node[]) {\n nodes.sort((a, b) => {\n const position = a.compareDocumentPosition(b)\n /* eslint-disable no-bitwise */\n if (position & Node.DOCUMENT_POSITION_CONTAINED_BY) {\n return -1\n } else if (position & Node.DOCUMENT_POSITION_CONTAINS) {\n return 1\n } else if (position & Node.DOCUMENT_POSITION_FOLLOWING) {\n return 1\n } else if (position & Node.DOCUMENT_POSITION_PRECEDING) {\n return -1\n }\n /* eslint-enable no-bitwise */\n return 0\n })\n}\n\nfunction traverseRemovedShadowDom(removedNode: Node, shadowDomRemovedCallback: ShadowRootCallBack) {\n if (isNodeShadowHost(removedNode)) {\n shadowDomRemovedCallback(removedNode.shadowRoot)\n }\n forEachChildNodes(removedNode, (childNode) => traverseRemovedShadowDom(childNode, shadowDomRemovedCallback))\n}\n","import type { RumConfiguration } from '@datadog/browser-rum-core'\nimport type { BrowserIncrementalSnapshotRecord } from '../../types'\nimport { trackInput, trackMutation, trackScroll } from './trackers'\nimport type { ElementsScrollPositions } from './elementsScrollPositions'\n\ninterface ShadowRootController {\n stop: () => void\n flush: () => void\n}\n\nexport type ShadowRootCallBack = (shadowRoot: ShadowRoot) => void\n\nexport interface ShadowRootsController {\n addShadowRoot: ShadowRootCallBack\n removeShadowRoot: ShadowRootCallBack\n stop: () => void\n flush: () => void\n}\n\nexport const initShadowRootsController = (\n configuration: RumConfiguration,\n callback: (record: BrowserIncrementalSnapshotRecord) => void,\n elementsScrollPositions: ElementsScrollPositions\n): ShadowRootsController => {\n const controllerByShadowRoot = new Map<ShadowRoot, ShadowRootController>()\n\n const shadowRootsController: ShadowRootsController = {\n addShadowRoot: (shadowRoot: ShadowRoot) => {\n if (controllerByShadowRoot.has(shadowRoot)) {\n return\n }\n const mutationTracker = trackMutation(callback, configuration, shadowRootsController, shadowRoot)\n // The change event does not bubble up across the shadow root, we have to listen on the shadow root\n const inputTracker = trackInput(configuration, callback, shadowRoot)\n // The scroll event does not bubble up across the shadow root, we have to listen on the shadow root\n const scrollTracker = trackScroll(configuration, callback, elementsScrollPositions, shadowRoot)\n controllerByShadowRoot.set(shadowRoot, {\n flush: () => mutationTracker.flush(),\n stop: () => {\n mutationTracker.stop()\n inputTracker.stop()\n scrollTracker.stop()\n },\n })\n },\n removeShadowRoot: (shadowRoot: ShadowRoot) => {\n const entry = controllerByShadowRoot.get(shadowRoot)\n if (!entry) {\n // unidentified root cause: observed in some cases with shadow DOM added by browser extensions\n return\n }\n entry.stop()\n controllerByShadowRoot.delete(shadowRoot)\n },\n stop: () => {\n controllerByShadowRoot.forEach(({ stop }) => stop())\n },\n flush: () => {\n controllerByShadowRoot.forEach(({ flush }) => flush())\n },\n }\n return shadowRootsController\n}\n","import { sendToExtension } from '@datadog/browser-core'\nimport type { LifeCycle, RumConfiguration, ViewHistory } from '@datadog/browser-rum-core'\nimport type { BrowserRecord } from '../../types'\nimport * as replayStats from '../replayStats'\nimport type { Tracker } from './trackers'\nimport {\n trackFocus,\n trackFrustration,\n trackInput,\n trackMediaInteraction,\n trackMouseInteraction,\n trackMove,\n trackMutation,\n trackScroll,\n trackStyleSheet,\n trackViewEnd,\n trackViewportResize,\n trackVisualViewportResize,\n} from './trackers'\nimport { createElementsScrollPositions } from './elementsScrollPositions'\nimport type { ShadowRootsController } from './shadowRootsController'\nimport { initShadowRootsController } from './shadowRootsController'\nimport { startFullSnapshots } from './startFullSnapshots'\nimport { initRecordIds } from './recordIds'\n\nexport interface RecordOptions {\n emit?: (record: BrowserRecord) => void\n configuration: RumConfiguration\n lifeCycle: LifeCycle\n viewHistory: ViewHistory\n}\n\nexport interface RecordAPI {\n stop: () => void\n flushMutations: () => void\n shadowRootsController: ShadowRootsController\n}\n\nexport function record(options: RecordOptions): RecordAPI {\n const { emit, configuration, lifeCycle } = options\n // runtime checks for user options\n if (!emit) {\n throw new Error('emit function is required')\n }\n\n const emitAndComputeStats = (record: BrowserRecord) => {\n emit(record)\n sendToExtension('record', { record })\n const view = options.viewHistory.findView()!\n replayStats.addRecord(view.id)\n }\n\n const elementsScrollPositions = createElementsScrollPositions()\n\n const shadowRootsController = initShadowRootsController(configuration, emitAndComputeStats, elementsScrollPositions)\n\n const { stop: stopFullSnapshots } = startFullSnapshots(\n elementsScrollPositions,\n shadowRootsController,\n lifeCycle,\n configuration,\n flushMutations,\n (records) => records.forEach((record) => emitAndComputeStats(record))\n )\n\n function flushMutations() {\n shadowRootsController.flush()\n mutationTracker.flush()\n }\n\n const recordIds = initRecordIds()\n const mutationTracker = trackMutation(emitAndComputeStats, configuration, shadowRootsController, document)\n const trackers: Tracker[] = [\n mutationTracker,\n trackMove(configuration, emitAndComputeStats),\n trackMouseInteraction(configuration, emitAndComputeStats, recordIds),\n trackScroll(configuration, emitAndComputeStats, elementsScrollPositions, document),\n trackViewportResize(configuration, emitAndComputeStats),\n trackInput(configuration, emitAndComputeStats),\n trackMediaInteraction(configuration, emitAndComputeStats),\n trackStyleSheet(emitAndComputeStats),\n trackFocus(configuration, emitAndComputeStats),\n trackVisualViewportResize(configuration, emitAndComputeStats),\n trackFrustration(lifeCycle, emitAndComputeStats, recordIds),\n trackViewEnd(lifeCycle, (viewEndRecord) => {\n flushMutations()\n emitAndComputeStats(viewEndRecord)\n }),\n ]\n\n return {\n stop: () => {\n shadowRootsController.stop()\n trackers.forEach((tracker) => tracker.stop())\n stopFullSnapshots()\n },\n flushMutations,\n shadowRootsController,\n }\n}\n","export type ElementsScrollPositions = ReturnType<typeof createElementsScrollPositions>\nexport type ScrollPositions = { scrollLeft: number; scrollTop: number }\n\nexport function createElementsScrollPositions() {\n const scrollPositionsByElement = new WeakMap<Element, ScrollPositions>()\n return {\n set(element: Element | Document, scrollPositions: ScrollPositions) {\n if (element === document && !document.scrollingElement) {\n // cf https://drafts.csswg.org/cssom-view/#dom-document-scrollingelement,\n // in some cases scrolling elements can not be defined, we don't support those for now\n return\n }\n scrollPositionsByElement.set(\n element === document ? document.scrollingElement! : (element as Element),\n scrollPositions\n )\n },\n get(element: Element) {\n return scrollPositionsByElement.get(element)\n },\n has(element: Element) {\n return scrollPositionsByElement.has(element)\n },\n }\n}\n","import { LifeCycleEventType, getScrollX, getScrollY, getViewportDimension } from '@datadog/browser-rum-core'\nimport type { RumConfiguration, LifeCycle } from '@datadog/browser-rum-core'\nimport { timeStampNow } from '@datadog/browser-core'\nimport type { BrowserRecord } from '../../types'\nimport { RecordType } from '../../types'\nimport type { ElementsScrollPositions } from './elementsScrollPositions'\nimport type { ShadowRootsController } from './shadowRootsController'\nimport { SerializationContextStatus, serializeDocument } from './serialization'\nimport { getVisualViewport } from './viewports'\n\nexport function startFullSnapshots(\n elementsScrollPositions: ElementsScrollPositions,\n shadowRootsController: ShadowRootsController,\n lifeCycle: LifeCycle,\n configuration: RumConfiguration,\n flushMutations: () => void,\n fullSnapshotCallback: (records: BrowserRecord[]) => void\n) {\n const takeFullSnapshot = (\n timestamp = timeStampNow(),\n serializationContext = {\n status: SerializationContextStatus.INITIAL_FULL_SNAPSHOT,\n elementsScrollPositions,\n shadowRootsController,\n }\n ) => {\n const { width, height } = getViewportDimension()\n const records: BrowserRecord[] = [\n {\n data: {\n height,\n href: window.location.href,\n width,\n },\n type: RecordType.Meta,\n timestamp,\n },\n {\n data: {\n has_focus: document.hasFocus(),\n },\n type: RecordType.Focus,\n timestamp,\n },\n {\n data: {\n node: serializeDocument(document, configuration, serializationContext),\n initialOffset: {\n left: getScrollX(),\n top: getScrollY(),\n },\n },\n type: RecordType.FullSnapshot,\n timestamp,\n },\n ]\n\n if (window.visualViewport) {\n records.push({\n data: getVisualViewport(window.visualViewport),\n type: RecordType.VisualViewport,\n timestamp,\n })\n }\n return records\n }\n\n fullSnapshotCallback(takeFullSnapshot())\n\n const { unsubscribe } = lifeCycle.subscribe(LifeCycleEventType.VIEW_CREATED, (view) => {\n flushMutations()\n fullSnapshotCallback(\n takeFullSnapshot(view.startClocks.timeStamp, {\n shadowRootsController,\n status: SerializationContextStatus.SUBSEQUENT_FULL_SNAPSHOT,\n elementsScrollPositions,\n })\n )\n })\n\n return {\n stop: unsubscribe,\n }\n}\n","export type RecordIds = ReturnType<typeof initRecordIds>\n\nexport function initRecordIds() {\n const recordIds = new WeakMap<Event, number>()\n let nextId = 1\n\n return {\n getIdForEvent(event: Event): number {\n if (!recordIds.has(event)) {\n recordIds.set(event, nextId++)\n }\n return recordIds.get(event)!\n },\n }\n}\n","import type { Encoder, EncoderResult } from '@datadog/browser-core'\nimport type { BrowserRecord, BrowserSegmentMetadata, CreationReason, SegmentContext } from '../../types'\nimport { RecordType } from '../../types'\nimport * as replayStats from '../replayStats'\n\nexport type FlushReason = Exclude<CreationReason, 'init'> | 'stop'\nexport type FlushCallback = (metadata: BrowserSegmentMetadata, encoderResult: EncoderResult<Uint8Array>) => void\nexport type AddRecordCallback = (encodedBytesCount: number) => void\n\nexport interface Segment {\n addRecord: (record: BrowserRecord, callback: AddRecordCallback) => void\n flush: (callback: FlushCallback) => void\n}\n\nexport function createSegment({\n context,\n creationReason,\n encoder,\n}: {\n context: SegmentContext\n creationReason: CreationReason\n encoder: Encoder<Uint8Array>\n}): Segment {\n let encodedBytesCount = 0\n const viewId = context.view.id\n const metadata: BrowserSegmentMetadata = {\n start: Infinity,\n end: -Infinity,\n creation_reason: creationReason,\n records_count: 0,\n has_full_snapshot: false,\n index_in_view: replayStats.getSegmentsCount(viewId),\n source: 'browser' as const,\n ...context,\n }\n\n replayStats.addSegment(viewId)\n\n function addRecord(record: BrowserRecord, callback: AddRecordCallback): void {\n metadata.start = Math.min(metadata.start, record.timestamp)\n metadata.end = Math.max(metadata.end, record.timestamp)\n metadata.records_count += 1\n metadata.has_full_snapshot ||= record.type === RecordType.FullSnapshot\n\n const prefix = encoder.isEmpty ? '{\"records\":[' : ','\n encoder.write(prefix + JSON.stringify(record), (additionalEncodedBytesCount) => {\n encodedBytesCount += additionalEncodedBytesCount\n callback(encodedBytesCount)\n })\n }\n\n function flush(callback: FlushCallback) {\n if (encoder.isEmpty) {\n throw new Error('Empty segment flushed')\n }\n\n encoder.write(`],${JSON.stringify(metadata).slice(1)}\\n`)\n encoder.finish((encoderResult) => {\n replayStats.addWroteData(metadata.view.id, encoderResult.rawBytesCount)\n callback(metadata, encoderResult)\n })\n }\n\n return { addRecord, flush }\n}\n","import type { DeflateEncoder, HttpRequest, TimeoutId } from '@datadog/browser-core'\nimport { isPageExitReason, ONE_SECOND, clearTimeout, setTimeout } from '@datadog/browser-core'\nimport type { LifeCycle, ViewHistory, RumSessionManager, RumConfiguration } from '@datadog/browser-rum-core'\nimport { LifeCycleEventType } from '@datadog/browser-rum-core'\nimport type { BrowserRecord, CreationReason, SegmentContext } from '../../types'\nimport { buildReplayPayload } from './buildReplayPayload'\nimport type { FlushReason, Segment } from './segment'\nimport { createSegment } from './segment'\n\nexport const SEGMENT_DURATION_LIMIT = 5 * ONE_SECOND\n/**\n * beacon payload max queue size implementation is 64kb\n * ensure that we leave room for logs, rum and potential other users\n */\nexport let SEGMENT_BYTES_LIMIT = 60_000\n\n// Segments are the main data structure for session replays. They contain context information used\n// for indexing or UI needs, and a list of records (RRWeb 'events', renamed to avoid confusing\n// namings). They are stored without any processing from the intake, and fetched one after the\n// other while a session is being replayed. Their encoding (deflate) are carefully crafted to allow\n// concatenating multiple segments together. Segments have a size overhead (metadata), so our goal is to\n// build segments containing as many records as possible while complying with the various flush\n// strategies to guarantee a good replay quality.\n//\n// When the recording starts, a segment is initially created. The segment is flushed (finalized and\n// sent) based on various events (non-exhaustive list):\n//\n// * the page visibility change or becomes to unload\n// * the segment duration reaches a limit\n// * the encoded segment bytes count reaches a limit\n// * ...\n//\n// A segment cannot be created without its context. If the RUM session ends and no session id is\n// available when creating a new segment, records will be ignored, until the session is renewed and\n// a new session id is available.\n//\n// Empty segments (segments with no record) aren't useful and should be ignored.\n//\n// To help investigate session replays issues, each segment is created with a \"creation reason\",\n// indicating why the session has been created.\n\nexport function startSegmentCollection(\n lifeCycle: LifeCycle,\n configuration: RumConfiguration,\n sessionManager: RumSessionManager,\n viewHistory: ViewHistory,\n httpRequest: HttpRequest,\n encoder: DeflateEncoder\n) {\n return doStartSegmentCollection(\n lifeCycle,\n () => computeSegmentContext(configuration.applicationId, sessionManager, viewHistory),\n httpRequest,\n encoder\n )\n}\n\nconst enum SegmentCollectionStatus {\n WaitingForInitialRecord,\n SegmentPending,\n Stopped,\n}\ntype SegmentCollectionState =\n | {\n status: SegmentCollectionStatus.WaitingForInitialRecord\n nextSegmentCreationReason: CreationReason\n }\n | {\n status: SegmentCollectionStatus.SegmentPending\n segment: Segment\n expirationTimeoutId: TimeoutId\n }\n | {\n status: SegmentCollectionStatus.Stopped\n }\n\nexport function doStartSegmentCollection(\n lifeCycle: LifeCycle,\n getSegmentContext: () => SegmentContext | undefined,\n httpRequest: HttpRequest,\n encoder: DeflateEncoder\n) {\n let state: SegmentCollectionState = {\n status: SegmentCollectionStatus.WaitingForInitialRecord,\n nextSegmentCreationReason: 'init',\n }\n\n const { unsubscribe: unsubscribeViewCreated } = lifeCycle.subscribe(LifeCycleEventType.VIEW_CREATED, () => {\n flushSegment('view_change')\n })\n\n const { unsubscribe: unsubscribePageExited } = lifeCycle.subscribe(\n LifeCycleEventType.PAGE_EXITED,\n (pageExitEvent) => {\n flushSegment(pageExitEvent.reason as FlushReason)\n }\n )\n\n function flushSegment(flushReason: FlushReason) {\n if (state.status === SegmentCollectionStatus.SegmentPending) {\n state.segment.flush((metadata, encoderResult) => {\n const payload = buildReplayPayload(encoderResult.output, metadata, encoderResult.rawBytesCount)\n\n if (isPageExitReason(flushReason)) {\n httpRequest.sendOnExit(payload)\n } else {\n httpRequest.send(payload)\n }\n })\n clearTimeout(state.expirationTimeoutId)\n }\n\n if (flushReason !== 'stop') {\n state = {\n status: SegmentCollectionStatus.WaitingForInitialRecord,\n nextSegmentCreationReason: flushReason,\n }\n } else {\n state = {\n status: SegmentCollectionStatus.Stopped,\n }\n }\n }\n\n return {\n addRecord: (record: BrowserRecord) => {\n if (state.status === SegmentCollectionStatus.Stopped) {\n return\n }\n\n if (state.status === SegmentCollectionStatus.WaitingForInitialRecord) {\n const context = getSegmentContext()\n if (!context) {\n return\n }\n\n state = {\n status: SegmentCollectionStatus.SegmentPending,\n segment: createSegment({ encoder, context, creationReason: state.nextSegmentCreationReason }),\n expirationTimeoutId: setTimeout(() => {\n flushSegment('segment_duration_limit')\n }, SEGMENT_DURATION_LIMIT),\n }\n }\n\n state.segment.addRecord(record, (encodedBytesCount) => {\n if (encodedBytesCount > SEGMENT_BYTES_LIMIT) {\n flushSegment('segment_bytes_limit')\n }\n })\n },\n\n stop: () => {\n flushSegment('stop')\n unsubscribeViewCreated()\n unsubscribePageExited()\n },\n }\n}\n\nexport function computeSegmentContext(\n applicationId: string,\n sessionManager: RumSessionManager,\n viewHistory: ViewHistory\n) {\n const session = sessionManager.findTrackedSession()\n const viewContext = viewHistory.findView()\n if (!session || !viewContext) {\n return undefined\n }\n return {\n application: {\n id: applicationId,\n },\n session: {\n id: session.id,\n },\n view: {\n id: viewContext.id,\n },\n }\n}\n\nexport function setSegmentBytesLimit(newSegmentBytesLimit = 60_000) {\n SEGMENT_BYTES_LIMIT = newSegmentBytesLimit\n}\n","import type { Payload } from '@datadog/browser-core'\nimport type { BrowserSegmentMetadata } from '../../types'\n\nexport type BrowserSegmentMetadataAndSegmentSizes = BrowserSegmentMetadata & {\n raw_segment_size: number\n compressed_segment_size: number\n}\n\nexport function buildReplayPayload(\n data: Uint8Array,\n metadata: BrowserSegmentMetadata,\n rawSegmentBytesCount: number\n): Payload {\n const formData = new FormData()\n\n formData.append(\n 'segment',\n new Blob([data], {\n type: 'application/octet-stream',\n }),\n `${metadata.session.id}-${metadata.start}`\n )\n\n const metadataAndSegmentSizes: BrowserSegmentMetadataAndSegmentSizes = {\n raw_segment_size: rawSegmentBytesCount,\n compressed_segment_size: data.byteLength,\n ...metadata,\n }\n\n const serializedMetadataAndSegmentSizes = JSON.stringify(metadataAndSegmentSizes)\n formData.append('event', new Blob([serializedMetadataAndSegmentSizes], { type: 'application/json' }))\n\n return { data: formData, bytesCount: data.byteLength }\n}\n","import type { RawError, HttpRequest, DeflateEncoder } from '@datadog/browser-core'\nimport { createHttpRequest, addTelemetryDebug, canUseEventBridge } from '@datadog/browser-core'\nimport type { LifeCycle, ViewHistory, RumConfiguration, RumSessionManager } from '@datadog/browser-rum-core'\nimport { LifeCycleEventType } from '@datadog/browser-rum-core'\n\nimport { record } from '../domain/record'\nimport { startSegmentCollection, SEGMENT_BYTES_LIMIT } from '../domain/segmentCollection'\nimport type { BrowserRecord } from '../types'\nimport { startRecordBridge } from '../domain/startRecordBridge'\n\nexport function startRecording(\n lifeCycle: LifeCycle,\n configuration: RumConfiguration,\n sessionManager: RumSessionManager,\n viewHistory: ViewHistory,\n encoder: DeflateEncoder,\n httpRequest?: HttpRequest\n) {\n const cleanupTasks: Array<() => void> = []\n\n const reportError = (error: RawError) => {\n lifeCycle.notify(LifeCycleEventType.RAW_ERROR_COLLECTED, { error })\n addTelemetryDebug('Error reported to customer', { 'error.message': error.message })\n }\n\n const replayRequest =\n httpRequest || createHttpRequest(configuration.sessionReplayEndpointBuilder, SEGMENT_BYTES_LIMIT, reportError)\n\n let addRecord: (record: BrowserRecord) => void\n\n if (!canUseEventBridge()) {\n const segmentCollection = startSegmentCollection(\n lifeCycle,\n configuration,\n sessionManager,\n viewHistory,\n replayRequest,\n encoder\n )\n addRecord = segmentCollection.addRecord\n cleanupTasks.push(segmentCollection.stop)\n } else {\n ;({ addRecord } = startRecordBridge(viewHistory))\n }\n\n const { stop: stopRecording } = record({\n emit: addRecord,\n configuration,\n lifeCycle,\n viewHistory,\n })\n cleanupTasks.push(stopRecording)\n\n return {\n stop: () => {\n cleanupTasks.forEach((task) => task())\n },\n }\n}\n","import { getEventBridge } from '@datadog/browser-core'\nimport type { ViewHistory } from '@datadog/browser-rum-core'\nimport type { BrowserRecord } from '../types'\n\nexport function startRecordBridge(viewHistory: ViewHistory) {\n const bridge = getEventBridge<'record', BrowserRecord>()!\n\n return {\n addRecord: (record: BrowserRecord) => {\n // Get the current active view, not at the time of the record, aligning with the segment logic.\n // This approach could potentially associate the record to an incorrect view, in case the record date is in the past (e.g. frustration records).\n // However the risk is minimal. We could address the issue when potential negative impact are identified.\n const view = viewHistory.findView()!\n bridge.send('record', record, view.id)\n },\n }\n}\n"],"names":["serializedNodeIds","WeakMap","hasSerializedNode","node","has","getSerializedNodeId","get","getElementInputValue","element","nodePrivacyLevel","tagName","value","shouldMaskNode","type","CENSORED_STRING_MARK","URL_IN_CSS_REF","ABSOLUTE_URL","DATA_URI","switchToAbsoluteUrl","cssText","cssHref","replace","matchingSubstring","singleQuote","urlWrappedInSingleQuotes","doubleQuote","urlWrappedInDoubleQuotes","urlNotWrappedInQuotes","url","test","quote","concat","baseUrl","buildUrl","href","_a","makeUrlAbsolute","TAG_NAME_REGEX","getValidTagName","processedTagName","toLowerCase","trim","censoredImageForSize","width","height","RecordType","FullSnapshot","IncrementalSnapshot","Meta","Focus","ViewEnd","VisualViewport","FrustrationRecord","NodeType","Document","DocumentType","Element","Text","CDATA","DocumentFragment","IncrementalSource","Mutation","MouseMove","MouseInteraction","Scroll","ViewportResize","Input","TouchMove","MediaInteraction","StyleSheetRule","MouseInteractionType","MouseUp","MouseDown","Click","ContextMenu","DblClick","Blur","TouchStart","TouchEnd","MediaInteractionType","Play","Pause","serializeStyleSheets","cssStyleSheets","undefined","length","map","cssStyleSheet","rules","cssRules","Array","from","cssRule","disabled","media","serializeAttribute","attributeName","configuration","NodePrivacyLevel","HIDDEN","attributeValue","getAttribute","MASK","PRIVACY_ATTR_NAME","STABLE_ATTRIBUTES","includes","actionNameAttribute","image","naturalWidth","naturalHeight","getBoundingClientRect","CENSORED_IMG_MARK","startsWith","isLongDataUrl","sanitizeDataUrl","getCssRulesString","isSafari","getCssRuleStringForSafari","getCssRuleString","join","rule","isCSSStyleRule","selectorText","escapeColon","isCSSImportRule","styleSheet","serializeNodeWithId","options","serializedNode","nodeType","DOCUMENT_NODE","document","childNodes","serializeChildNodes","adoptedStyleSheets","serializeDocumentNode","DOCUMENT_FRAGMENT_NODE","isShadowRoot","isNodeShadowRoot","serializationContext","shadowRootsController","addShadowRoot","serializeDocumentFragmentNode","DOCUMENT_TYPE_NODE","documentType","name","publicId","systemId","ELEMENT_NODE","isSVG","el","SVGElement","reducePrivacyLevel","getNodeSelfPrivacyLevel","parentNodePrivacyLevel","attributes","rr_width","rr_height","PRIVACY_ATTR_VALUE_HIDDEN","IGNORE","safeAttrs","doc","ownerDocument","i","item","formValue","ALLOW","optionElement","selected","stylesheet","styleSheets","find","s","_cssText","sheet","inputElement","checked","mediaElement","rr_mediaState","paused","scrollTop","scrollLeft","status","Math","round","elementsScrollPositions","set","rr_scrollLeft","rr_scrollTop","serializeAttributes","hasChildNodes","childNodesSerializationOptions","ignoreWhiteSpace","serializeElementNode","TEXT_NODE","textNode","textContent","getTextContent","serializeTextNode","CDATA_SECTION_NODE","serializeNode","id","_nextId","serializedNodeWithId","serializeNodeId","setSerializedNodeId","add","result","forEachChildNodes","childNode","serializedChildNode","push","serializeDocument","defaultPrivacyLevel","isTouchEvent","event","Boolean","changedTouches","getEventTarget","composed","isNodeShadowHost","target","composedPath","convertMouseEventToLayoutCoordinates","clientX","clientY","visualViewport","window","normalized","layoutViewportX","layoutViewportY","visualViewportX","visualViewportY","abs","pageTop","offsetTop","scrollY","pageLeft","offsetLeft","scrollX","isVisualViewportFactoredIn","getVisualViewport","scale","assembleIncrementalSnapshot","source","data","timestamp","timeStampNow","MOUSE_MOVE_OBSERVER_THRESHOLD","trackMove","moveCb","throttled","updatePosition","cancel","cancelThrottle","throttle","coordinates","tryToComputeCoordinates","position","timeOffset","x","y","positions","trailing","stop","removeListener","addEventListeners","capture","passive","Number","isFinite","isTrusted","addTelemetryDebug","eventTypeToMouseInteraction","trackMouseInteraction","mouseInteractionCb","recordIds","Object","keys","getNodePrivacyLevel","interaction","record","getIdForEvent","SCROLL_OBSERVER_THRESHOLD","trackScroll","scrollCb","arguments","scrollPositions","getScrollY","getScrollX","addEventListener","VISUAL_VIEWPORT_OBSERVER_THRESHOLD","trackViewportResize","viewportResizeCb","viewportResizeSubscription","initViewportObservable","subscribe","unsubscribe","trackVisualViewportResize","visualViewportResizeCb","noop","updateDimension","trackMediaInteraction","mediaInteractionCb","trackStyleSheet","styleSheetCb","checkStyleSheetAndCallback","callback","ownerNode","instrumentationStoppers","instrumentMethod","CSSStyleSheet","prototype","_ref","parameters","index","adds","_ref2","removes","instrumentGroupingCSSRuleClass","cls","_ref3","parentStyleSheet","path","getPathToNestedCSSRule","_ref4","CSSGroupingRule","CSSMediaRule","CSSSupportsRule","forEach","stopper","currentRule","parentRule","indexOf","unshift","trackFocus","focusCb","has_focus","hasFocus","trackFrustration","lifeCycle","frustrationCb","frustrationSubscription","rawRumEvent","action","_b","frustration","domainContext","events","date","frustrationTypes","e","trackViewEnd","viewEndCb","viewEndSubscription","trackInput","inputCb","lastInputStateMap","stopEventListeners","HTMLInputElement","HTMLTextAreaElement","HTMLSelectElement","onElementChange","stopPropertySetterInstrumentation","instrumentSetter","inputState","isChecked","text","cbWithDedup","querySelectorAll","CSS","escape","lastInputState","MUTATION_PROCESS_MAX_DELAY","MUTATION_PROCESS_MIN_DELAY","trackMutation","mutationCallback","MutationObserver","getMutationObserverConstructor","flush","mutationBatch","processMutationBatch","cancelScheduledFlush","pendingMutations","throttledFlush","leading","addMutations","mutations","requestIdleCallback","timeout","createMutationBatch","nodePrivacyLevelCache","Map","filter","mutation","removedNodes","removedNode","traverseRemovedShadowDom","removeShadowRoot","filteredMutations","isConnected","current","getParentNode","nodeAndAncestorsHaveSerializedNode","hasBeenSerialized","addedAndMovedNodes","Set","addedNodes","delete","sortedAddedAndMovedNodes","nodes","sort","a","b","compareDocumentPosition","Node","DOCUMENT_POSITION_CONTAINED_BY","DOCUMENT_POSITION_CONTAINS","DOCUMENT_POSITION_FOLLOWING","DOCUMENT_POSITION_PRECEDING","addedNodeMutations","parentNode","nextId","getNextSibling","parentId","removedNodeMutations","parent","nextSibling","processChildListMutations","texts","textMutations","handledNodes","oldValue","processCharacterDataMutations","attributeMutations","handledElements","handledAttributes","emittedMutations","privacyLevel","transformedValue","inputValue","emittedMutation","processAttributesMutations","processMutations","observer","takeRecords","monitor","observe","attributeOldValue","characterData","characterDataOldValue","childList","subtree","disconnect","shadowDomRemovedCallback","shadowRoot","initShadowRootsController","controllerByShadowRoot","mutationTracker","inputTracker","scrollTracker","entry","emit","Error","emitAndComputeStats","sendToExtension","view","viewHistory","findView","replayStats","scrollPositionsByElement","scrollingElement","createElementsScrollPositions","stopFullSnapshots","flushMutations","fullSnapshotCallback","takeFullSnapshot","getViewportDimension","records","location","initialOffset","left","top","startClocks","timeStamp","startFullSnapshots","initRecordIds","trackers","viewEndRecord","tracker","createSegment","context","creationReason","encoder","encodedBytesCount","viewId","metadata","start","Infinity","end","creation_reason","records_count","has_full_snapshot","index_in_view","addRecord","min","max","prefix","isEmpty","write","JSON","stringify","additionalEncodedBytesCount","slice","finish","encoderResult","rawBytesCount","SEGMENT_DURATION_LIMIT","ONE_SECOND","SEGMENT_BYTES_LIMIT","startSegmentCollection","sessionManager","httpRequest","getSegmentContext","state","nextSegmentCreationReason","unsubscribeViewCreated","flushSegment","unsubscribePageExited","pageExitEvent","reason","flushReason","segment","payload","rawSegmentBytesCount","formData","FormData","append","Blob","session","metadataAndSegmentSizes","raw_segment_size","compressed_segment_size","byteLength","serializedMetadataAndSegmentSizes","bytesCount","buildReplayPayload","output","isPageExitReason","sendOnExit","send","clearTimeout","expirationTimeoutId","setTimeout","doStartSegmentCollection","applicationId","findTrackedSession","viewContext","application","computeSegmentContext","startRecording","cleanupTasks","replayRequest","createHttpRequest","sessionReplayEndpointBuilder","error","notify","message","canUseEventBridge","bridge","getEventBridge","startRecordBridge","segmentCollection","stopRecording","task"],"sourceRoot":""}