UNPKG

@mixpanel/rrweb-utils

Version:

This package contains the shared utility functions used across rrweb packages. See the [guide](../../guide.md) for more info on rrweb.

191 lines (190 loc) 5.58 kB
const testableAccessors = { Node: ["childNodes", "parentNode", "parentElement", "textContent"], ShadowRoot: ["host", "styleSheets"], Element: ["shadowRoot", "querySelector", "querySelectorAll"], MutationObserver: [] }; const testableMethods = { Node: ["contains", "getRootNode"], ShadowRoot: ["getSelection"], Element: [], MutationObserver: ["constructor"] }; const untaintedBasePrototype = {}; const isAngularZonePresent = () => { return !!globalThis.Zone; }; function getUntaintedPrototype(key) { if (untaintedBasePrototype[key]) return untaintedBasePrototype[key]; const defaultObj = globalThis[key]; const defaultPrototype = defaultObj.prototype; const accessorNames = key in testableAccessors ? testableAccessors[key] : void 0; const isUntaintedAccessors = Boolean( accessorNames && // @ts-expect-error 2345 accessorNames.every( (accessor) => { var _a, _b; return Boolean( (_b = (_a = Object.getOwnPropertyDescriptor(defaultPrototype, accessor)) == null ? void 0 : _a.get) == null ? void 0 : _b.toString().includes("[native code]") ); } ) ); const methodNames = key in testableMethods ? testableMethods[key] : void 0; const isUntaintedMethods = Boolean( methodNames && methodNames.every( // @ts-expect-error 2345 (method) => { var _a; return typeof defaultPrototype[method] === "function" && ((_a = defaultPrototype[method]) == null ? void 0 : _a.toString().includes("[native code]")); } ) ); if (isUntaintedAccessors && isUntaintedMethods && !isAngularZonePresent()) { untaintedBasePrototype[key] = defaultObj.prototype; return defaultObj.prototype; } try { const iframeEl = document.createElement("iframe"); document.body.appendChild(iframeEl); const win = iframeEl.contentWindow; if (!win) return defaultObj.prototype; const untaintedObject = win[key].prototype; document.body.removeChild(iframeEl); if (!untaintedObject) return defaultPrototype; return untaintedBasePrototype[key] = untaintedObject; } catch { return defaultPrototype; } } const untaintedAccessorCache = {}; function getUntaintedAccessor(key, instance, accessor) { var _a; const cacheKey = `${key}.${String(accessor)}`; if (untaintedAccessorCache[cacheKey]) return untaintedAccessorCache[cacheKey].call( instance ); const untaintedPrototype = getUntaintedPrototype(key); const untaintedAccessor = (_a = Object.getOwnPropertyDescriptor( untaintedPrototype, accessor )) == null ? void 0 : _a.get; if (!untaintedAccessor) return instance[accessor]; untaintedAccessorCache[cacheKey] = untaintedAccessor; return untaintedAccessor.call(instance); } const untaintedMethodCache = {}; function getUntaintedMethod(key, instance, method) { const cacheKey = `${key}.${String(method)}`; if (untaintedMethodCache[cacheKey]) return untaintedMethodCache[cacheKey].bind( instance ); const untaintedPrototype = getUntaintedPrototype(key); const untaintedMethod = untaintedPrototype[method]; if (typeof untaintedMethod !== "function") return instance[method]; untaintedMethodCache[cacheKey] = untaintedMethod; return untaintedMethod.bind(instance); } function childNodes(n) { return getUntaintedAccessor("Node", n, "childNodes"); } function parentNode(n) { return getUntaintedAccessor("Node", n, "parentNode"); } function parentElement(n) { return getUntaintedAccessor("Node", n, "parentElement"); } function textContent(n) { return getUntaintedAccessor("Node", n, "textContent"); } function contains(n, other) { return getUntaintedMethod("Node", n, "contains")(other); } function getRootNode(n) { return getUntaintedMethod("Node", n, "getRootNode")(); } function host(n) { if (!n || !("host" in n)) return null; return getUntaintedAccessor("ShadowRoot", n, "host"); } function styleSheets(n) { return n.styleSheets; } function shadowRoot(n) { if (!n || !("shadowRoot" in n)) return null; return getUntaintedAccessor("Element", n, "shadowRoot"); } function querySelector(n, selectors) { return getUntaintedAccessor("Element", n, "querySelector")(selectors); } function querySelectorAll(n, selectors) { return getUntaintedAccessor("Element", n, "querySelectorAll")(selectors); } function mutationObserverCtor() { return getUntaintedPrototype("MutationObserver").constructor; } function patch(source, name, replacement) { try { if (!(name in source)) { return () => { }; } const original = source[name]; const wrapped = replacement(original); if (typeof wrapped === "function") { wrapped.prototype = wrapped.prototype || {}; Object.defineProperties(wrapped, { __rrweb_original__: { enumerable: false, value: original } }); } source[name] = wrapped; return () => { source[name] = original; }; } catch { return () => { }; } } const index = { childNodes, parentNode, parentElement, textContent, contains, getRootNode, host, styleSheets, shadowRoot, querySelector, querySelectorAll, mutationObserver: mutationObserverCtor, patch }; export { childNodes, contains, index as default, getRootNode, getUntaintedAccessor, getUntaintedMethod, getUntaintedPrototype, host, isAngularZonePresent, mutationObserverCtor, parentElement, parentNode, patch, querySelector, querySelectorAll, shadowRoot, styleSheets, textContent }; //# sourceMappingURL=rrweb-utils.js.map