From 4dcdcf7ec448758a9f7e49df4a8e1d8e46f5ca43 Mon Sep 17 00:00:00 2001 From: Ben White Date: Mon, 15 May 2023 14:19:42 +0200 Subject: [PATCH 001/123] fix: Rrror parser throw (#1225) * Warn instead of throwing error when parsing for console logs * Added error to warning --- .../rrweb/src/plugins/console/record/error-stack-parser.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/rrweb/src/plugins/console/record/error-stack-parser.ts b/packages/rrweb/src/plugins/console/record/error-stack-parser.ts index 4c0e49c309..b34487935e 100644 --- a/packages/rrweb/src/plugins/console/record/error-stack-parser.ts +++ b/packages/rrweb/src/plugins/console/record/error-stack-parser.ts @@ -71,7 +71,11 @@ export const ErrorStackParser = { } else if (error.stack) { return this.parseFFOrSafari(error as { stack: string }); } else { - throw new Error('Cannot parse given Error object'); + console.warn( + '[console-record-plugin]: Failed to parse error object:', + error, + ); + return []; } }, // Separate line and column numbers from a string of the form: (URI:Line:Column) From a1ec9a273e6634eec67098fdd880ee681648fbbd Mon Sep 17 00:00:00 2001 From: fukang wang Date: Mon, 22 May 2023 10:19:28 +0800 Subject: [PATCH 002/123] perf: optimize performance of the DoubleLinkedList get (#1220) * perf: optimize performance of the DoubleLinkedList get * fix: delete addedNodeIndexArr --- .changeset/gold-terms-look.md | 5 +++ packages/rrweb/src/record/mutation.ts | 14 ++++++- .../rrweb/test/benchmark/dom-mutation.test.ts | 6 +++ .../benchmark-dom-mutation-add-and-move.html | 37 +++++++++++++++++++ 4 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 .changeset/gold-terms-look.md create mode 100644 packages/rrweb/test/html/benchmark-dom-mutation-add-and-move.html diff --git a/.changeset/gold-terms-look.md b/.changeset/gold-terms-look.md new file mode 100644 index 0000000000..4ad333341c --- /dev/null +++ b/.changeset/gold-terms-look.md @@ -0,0 +1,5 @@ +--- +'rrweb': patch +--- + +perf: optimize performance of the DoubleLinkedList get diff --git a/packages/rrweb/src/record/mutation.ts b/packages/rrweb/src/record/mutation.ts index e0b03eb1dd..337394acf1 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -48,6 +48,7 @@ function isNodeInLinkedList(n: Node | NodeInLinkedList): n is NodeInLinkedList { class DoubleLinkedList { public length = 0; public head: DoubleLinkedListNode | null = null; + public tail: DoubleLinkedListNode | null = null; public get(position: number) { if (position >= this.length) { @@ -95,6 +96,9 @@ class DoubleLinkedList { node.next = this.head; this.head = node; } + if (node.next === null) { + this.tail = node; + } this.length++; } @@ -108,11 +112,15 @@ class DoubleLinkedList { this.head = current.next; if (this.head) { this.head.previous = null; + } else { + this.tail = null; } } else { current.previous.next = current.next; if (current.next) { current.next.previous = current.previous; + } else { + this.tail = current.previous; } } if (n.__ln) { @@ -368,8 +376,10 @@ export default class MutationBuffer { } } if (!node) { - for (let index = addList.length - 1; index >= 0; index--) { - const _node = addList.get(index); + let tailNode = addList.tail; + while (tailNode) { + const _node = tailNode; + tailNode = tailNode.previous; // ensure _node is defined before attempting to find value if (_node) { const parentId = this.mirror.getId(_node.value.parentNode); diff --git a/packages/rrweb/test/benchmark/dom-mutation.test.ts b/packages/rrweb/test/benchmark/dom-mutation.test.ts index 57050fb400..3da794db45 100644 --- a/packages/rrweb/test/benchmark/dom-mutation.test.ts +++ b/packages/rrweb/test/benchmark/dom-mutation.test.ts @@ -36,6 +36,12 @@ const suites: Array< eval: 'window.workload()', times: 5, }, + { + title: 'create 10000 DOM nodes and move it to new container', + html: 'benchmark-dom-mutation-add-and-move.html', + eval: 'window.workload()', + times: 5, + }, ]; function avg(v: number[]): number { diff --git a/packages/rrweb/test/html/benchmark-dom-mutation-add-and-move.html b/packages/rrweb/test/html/benchmark-dom-mutation-add-and-move.html new file mode 100644 index 0000000000..922b8c9ffc --- /dev/null +++ b/packages/rrweb/test/html/benchmark-dom-mutation-add-and-move.html @@ -0,0 +1,37 @@ + + +
+ + + From aca67a06cdf6577fafcc27357eb9503c4d344866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Stipi=C4=87?= Date: Mon, 22 May 2023 04:20:56 +0200 Subject: [PATCH 003/123] docs: add analyzee to readme (#1227) Added analyzee as one of the SaaS that use rrweb in one of their products --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 69f6a9560b..491b7fb217 100644 --- a/README.md +++ b/README.md @@ -213,5 +213,10 @@ In addition to adding integration tests and unit tests, rrweb also provides a RE The open source, fullstack Monitoring Platform. + + + Comprehensive data analytics platform that empowers businesses to gain valuable insights and make data-driven decisions. + + From a6ce7182ce59da8a565b12f7dfcb87eb10ec7ca4 Mon Sep 17 00:00:00 2001 From: Eoghan Murray Date: Mon, 22 May 2023 03:53:36 +0100 Subject: [PATCH 004/123] Avoid triggering a CSP (content security policy) error (#846) * Fix for #816 - avoid triggering a CSP (content security policy) error with `.setAttribute('style')` * The bare unattachedDoc that I previously naively created didn't have a doctype and wasn't a HTML document, so the child style element didn't have the `old.style` attribute available * Add a try/catch to provide some robustness in case `document.implementation.createHTMLDocument` isn't available --- packages/rrweb/src/record/mutation.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/rrweb/src/record/mutation.ts b/packages/rrweb/src/record/mutation.ts index 337394acf1..f352424b5f 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -472,6 +472,14 @@ export default class MutationBuffer { if (isIgnored(m.target, this.mirror)) { return; } + let unattachedDoc; + try { + // avoid upsetting original document from a Content Security point of view + unattachedDoc = document.implementation.createHTMLDocument(); + } catch (e) { + // fallback to more direct method + unattachedDoc = this.doc; + } switch (m.type) { case 'characterData': { const value = m.target.textContent; @@ -554,7 +562,7 @@ export default class MutationBuffer { } if (attributeName === 'style') { - const old = this.doc.createElement('span'); + const old = unattachedDoc.createElement('span'); if (m.oldValue) { old.setAttribute('style', m.oldValue); } From a606109519d9f834d34a2356deb6723f543a0caa Mon Sep 17 00:00:00 2001 From: Yun Feng Date: Fri, 2 Jun 2023 19:25:49 +1000 Subject: [PATCH 005/123] fix turbo dev command errors (#1229) * fix turbo dev command errors * Create forty-elephants-attack.md --------- Co-authored-by: Justin Halsall --- .changeset/forty-elephants-attack.md | 2 ++ turbo.json | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 .changeset/forty-elephants-attack.md diff --git a/.changeset/forty-elephants-attack.md b/.changeset/forty-elephants-attack.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/forty-elephants-attack.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/turbo.json b/turbo.json index 3908cac7ef..c14def8617 100644 --- a/turbo.json +++ b/turbo.json @@ -7,8 +7,13 @@ "outputs": ["lib/**", "es/**", "dist/**", "typings/**"] }, "test": {}, - "test:watch": {}, - "dev": {}, + "test:watch": { + "persistent": true + }, + "dev": { + "dependsOn": ["^prepublish"], + "persistent": true + }, "lint": {}, "check-types": {} } From b798f2dbc07b5a24dcaf40d164159200b6c0679d Mon Sep 17 00:00:00 2001 From: Yun Feng Date: Fri, 2 Jun 2023 19:44:00 +1000 Subject: [PATCH 006/123] Fix rrdom bugs (#1222) * fix: rrdom bug 1. fix one bug of the diff algorithm 2. omit srcdoc attribute of iframe * use linked list to iterate children * fix the bug that the children of shadowRoot don't get diffed * add test cases * add change log --- .changeset/cold-eyes-hunt.md | 8 ++++ packages/rrdom/src/diff.ts | 76 ++++++++++++++------------------ packages/rrdom/test/diff.test.ts | 74 +++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+), 43 deletions(-) create mode 100644 .changeset/cold-eyes-hunt.md diff --git a/.changeset/cold-eyes-hunt.md b/.changeset/cold-eyes-hunt.md new file mode 100644 index 0000000000..ac3a8be10d --- /dev/null +++ b/.changeset/cold-eyes-hunt.md @@ -0,0 +1,8 @@ +--- +'rrdom': patch +--- + +Fix: rrdom bugs + +1. Fix a bug in the diff algorithm. +2. Omit the 'srcdoc' attribute of iframes to avoid overwriting content. diff --git a/packages/rrdom/src/diff.ts b/packages/rrdom/src/diff.ts index 78628988e0..f37f298106 100644 --- a/packages/rrdom/src/diff.ts +++ b/packages/rrdom/src/diff.ts @@ -116,17 +116,7 @@ export function diff( rrnodeMirror, ); - const oldChildren = oldTree.childNodes; - const newChildren = newTree.childNodes; - if (oldChildren.length > 0 || newChildren.length > 0) { - diffChildren( - Array.from(oldChildren), - newChildren, - oldTree, - replayer, - rrnodeMirror, - ); - } + diffChildren(oldTree, newTree, replayer, rrnodeMirror); diffAfterUpdatingChildren(oldTree, newTree, replayer, rrnodeMirror); } @@ -196,18 +186,13 @@ function diffBeforeUpdatingChildren( } if (newRRElement.shadowRoot) { if (!oldElement.shadowRoot) oldElement.attachShadow({ mode: 'open' }); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const oldChildren = oldElement.shadowRoot!.childNodes; - const newChildren = newRRElement.shadowRoot.childNodes; - if (oldChildren.length > 0 || newChildren.length > 0) - diffChildren( - Array.from(oldChildren), - newChildren, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - oldElement.shadowRoot!, - replayer, - rrnodeMirror, - ); + diffChildren( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + oldElement.shadowRoot!, + newRRElement.shadowRoot, + replayer, + rrnodeMirror, + ); } break; } @@ -335,7 +320,8 @@ function diffProps( ctx.drawImage(image, 0, 0, image.width, image.height); } }; - } else oldTree.setAttribute(name, newValue); + } else if (newTree.tagName === 'IFRAME' && name === 'srcdoc') continue; + else oldTree.setAttribute(name, newValue); } for (const { name } of Array.from(oldAttributes)) @@ -346,12 +332,14 @@ function diffProps( } function diffChildren( - oldChildren: (Node | undefined)[], - newChildren: IRRNode[], - parentNode: Node, + oldTree: Node, + newTree: IRRNode, replayer: ReplayerHandler, rrnodeMirror: Mirror, ) { + const oldChildren: (Node | undefined)[] = Array.from(oldTree.childNodes); + const newChildren = newTree.childNodes; + if (oldChildren.length === 0 && newChildren.length === 0) return; let oldStartIndex = 0, oldEndIndex = oldChildren.length - 1, newStartIndex = 0, @@ -371,14 +359,12 @@ function diffChildren( // same first node? nodeMatching(oldStartNode, newStartNode, replayer.mirror, rrnodeMirror) ) { - diff(oldStartNode, newStartNode, replayer, rrnodeMirror); oldStartNode = oldChildren[++oldStartIndex]; newStartNode = newChildren[++newStartIndex]; } else if ( // same last node? nodeMatching(oldEndNode, newEndNode, replayer.mirror, rrnodeMirror) ) { - diff(oldEndNode, newEndNode, replayer, rrnodeMirror); oldEndNode = oldChildren[--oldEndIndex]; newEndNode = newChildren[--newEndIndex]; } else if ( @@ -386,11 +372,10 @@ function diffChildren( nodeMatching(oldStartNode, newEndNode, replayer.mirror, rrnodeMirror) ) { try { - parentNode.insertBefore(oldStartNode, oldEndNode.nextSibling); + oldTree.insertBefore(oldStartNode, oldEndNode.nextSibling); } catch (e) { console.warn(e); } - diff(oldStartNode, newEndNode, replayer, rrnodeMirror); oldStartNode = oldChildren[++oldStartIndex]; newEndNode = newChildren[--newEndIndex]; } else if ( @@ -398,11 +383,10 @@ function diffChildren( nodeMatching(oldEndNode, newStartNode, replayer.mirror, rrnodeMirror) ) { try { - parentNode.insertBefore(oldEndNode, oldStartNode); + oldTree.insertBefore(oldEndNode, oldStartNode); } catch (e) { console.warn(e); } - diff(oldEndNode, newStartNode, replayer, rrnodeMirror); oldEndNode = oldChildren[--oldEndIndex]; newStartNode = newChildren[++newStartIndex]; } else { @@ -424,11 +408,10 @@ function diffChildren( nodeMatching(nodeToMove, newStartNode, replayer.mirror, rrnodeMirror) ) { try { - parentNode.insertBefore(nodeToMove, oldStartNode); + oldTree.insertBefore(nodeToMove, oldStartNode); } catch (e) { console.warn(e); } - diff(nodeToMove, newStartNode, replayer, rrnodeMirror); oldChildren[indexInOld] = undefined; } else { const newNode = createOrGetNode( @@ -438,7 +421,7 @@ function diffChildren( ); if ( - parentNode.nodeName === '#document' && + oldTree.nodeName === '#document' && oldStartNode && /** * Special case 1: one document isn't allowed to have two doctype nodes at the same time, so we need to remove the old one first before inserting the new one. @@ -453,14 +436,13 @@ function diffChildren( (newNode.nodeType === newNode.ELEMENT_NODE && oldStartNode.nodeType === oldStartNode.ELEMENT_NODE)) ) { - parentNode.removeChild(oldStartNode); + oldTree.removeChild(oldStartNode); replayer.mirror.removeNodeFromMap(oldStartNode); oldStartNode = oldChildren[++oldStartIndex]; } try { - parentNode.insertBefore(newNode, oldStartNode || null); - diff(newNode, newStartNode, replayer, rrnodeMirror); + oldTree.insertBefore(newNode, oldStartNode || null); } catch (e) { console.warn(e); } @@ -482,8 +464,7 @@ function diffChildren( rrnodeMirror, ); try { - parentNode.insertBefore(newNode, referenceNode); - diff(newNode, newChildren[newStartIndex], replayer, rrnodeMirror); + oldTree.insertBefore(newNode, referenceNode); } catch (e) { console.warn(e); } @@ -491,15 +472,24 @@ function diffChildren( } else if (newStartIndex > newEndIndex) { for (; oldStartIndex <= oldEndIndex; oldStartIndex++) { const node = oldChildren[oldStartIndex]; - if (!node || node.parentNode !== parentNode) continue; + if (!node || node.parentNode !== oldTree) continue; try { - parentNode.removeChild(node); + oldTree.removeChild(node); replayer.mirror.removeNodeFromMap(node); } catch (e) { console.warn(e); } } } + + // Recursively diff the children of the old tree and the new tree with their props and deeper structures. + let oldChild = oldTree.firstChild; + let newChild = newTree.firstChild; + while (oldChild !== null && newChild !== null) { + diff(oldChild, newChild, replayer, rrnodeMirror); + oldChild = oldChild.nextSibling; + newChild = newChild.nextSibling; + } } export function createOrGetNode( diff --git a/packages/rrdom/test/diff.test.ts b/packages/rrdom/test/diff.test.ts index 04d638c314..3f18a6ee7e 100644 --- a/packages/rrdom/test/diff.test.ts +++ b/packages/rrdom/test/diff.test.ts @@ -15,6 +15,7 @@ import { Mirror as RRNodeMirror, RRDocument, RRMediaElement, + printRRDom, } from '../src'; import { createOrGetNode, @@ -106,6 +107,7 @@ function shuffle(list: number[]) { describe('diff algorithm for rrdom', () => { let mirror: NodeMirror; let replayer: ReplayerHandler; + let warn: jest.SpyInstance; beforeEach(() => { mirror = createMirror(); @@ -118,6 +120,14 @@ describe('diff algorithm for rrdom', () => { afterAppend: () => {}, }; document.write(''); + // Mock the original console.warn function to make the test fail once console.warn is called. + warn = jest.spyOn(console, 'warn'); + }); + + afterEach(() => { + // Check that warn was not called (fail on warning) + expect(warn).not.toBeCalled(); + warn.mockRestore(); }); describe('diff single node', () => { @@ -437,6 +447,19 @@ describe('diff algorithm for rrdom', () => { expect(document.createElement).toHaveBeenCalledWith('img'); jest.restoreAllMocks(); }); + + it('can omit srcdoc attribute of iframe element', () => { + // If srcdoc attribute is set, the content of iframe recorded by rrweb will be override. + const element = document.createElement('iframe'); + const rrDocument = new RRDocument(); + const rrIframe = rrDocument.createElement('iframe'); + const sn = Object.assign({}, elementSn, { tagName: 'iframe' }); + rrDocument.mirror.add(rrIframe, sn); + rrIframe.attributes['srcdoc'] = ''; + + diff(element, rrIframe, replayer); + expect(element.getAttribute('srcdoc')).toBe(null); + }); }); describe('diff children', () => { @@ -1054,6 +1077,57 @@ describe('diff algorithm for rrdom', () => { const liChild = spanChild.childNodes[0] as HTMLElement; expect(liChild.tagName).toEqual('LI'); }); + + it('should handle corner case with children removed during diff process', () => { + /** + * This test case is to simulate the following scenario: + * The old tree structure: + * 0 P + * 1 SPAN + * 2 SPAN + * The new tree structure: + * 0 P + * 1 SPAN + * 2 SPAN + * 3 SPAN + */ + const node = createTree( + { + tagName: 'p', + id: 0, + children: [1, 2].map((c) => ({ tagName: 'span', id: c })), + }, + undefined, + mirror, + ) as Node; + expect(node.childNodes.length).toEqual(2); + const rrdom = new RRDocument(); + const rrNode = createTree( + { + tagName: 'p', + id: 0, + children: [ + { tagName: 'span', id: 1, children: [{ tagName: 'span', id: 2 }] }, + { tagName: 'span', id: 3 }, + ], + }, + rrdom, + ) as RRNode; + expect(printRRDom(rrNode, rrdom.mirror)).toMatchInlineSnapshot(` + "0 P + 1 SPAN + 2 SPAN + 3 SPAN + " + `); + diff(node, rrNode, replayer); + + expect(node.childNodes.length).toEqual(2); + expect(node.childNodes[0].childNodes.length).toEqual(1); + expect(mirror.getId(node.childNodes[1])).toEqual(3); + expect(node.childNodes[0].childNodes.length).toEqual(1); + expect(mirror.getId(node.childNodes[0].childNodes[0])).toEqual(2); + }); }); describe('diff shadow dom', () => { From d7c72bff0724b46a6fa94af455220626a27104fe Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Fri, 2 Jun 2023 12:16:37 +0200 Subject: [PATCH 007/123] fix: Ensure attributes are lowercased when checking (#1183) * fix: Ensure attributes are lowercased when checking * add changeset * fix to lower case * Apply formatting changes --------- Co-authored-by: mydea --- .changeset/lovely-students-boil.md | 6 ++++++ packages/rrweb-snapshot/src/snapshot.ts | 11 ++++++----- packages/rrweb-snapshot/src/utils.ts | 8 ++++++-- packages/rrweb/src/record/mutation.ts | 5 +++-- packages/rrweb/src/record/observer.ts | 8 ++++++-- packages/rrweb/src/replay/index.ts | 3 ++- 6 files changed, 29 insertions(+), 12 deletions(-) create mode 100644 .changeset/lovely-students-boil.md diff --git a/.changeset/lovely-students-boil.md b/.changeset/lovely-students-boil.md new file mode 100644 index 0000000000..9c710bf1c6 --- /dev/null +++ b/.changeset/lovely-students-boil.md @@ -0,0 +1,6 @@ +--- +'rrweb-snapshot': patch +'rrweb': patch +--- + +fix: Ensure attributes are lowercased when checking diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index 0eeb289b4f..51f76f46f8 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -21,6 +21,7 @@ import { isNativeShadowDom, getCssRulesString, getInputType, + toLowerCase, } from './utils'; let _id = 1; @@ -32,12 +33,12 @@ export function genId(): number { return _id++; } -function getValidTagName(element: HTMLElement): string { +function getValidTagName(element: HTMLElement): Lowercase { if (element instanceof HTMLFormElement) { return 'form'; } - const processedTagName = element.tagName.toLowerCase().trim(); + const processedTagName = toLowerCase(element.tagName); if (tagNameRegex.test(processedTagName)) { // if the tag name is odd and we cannot extract @@ -222,8 +223,8 @@ function getHref() { export function transformAttribute( doc: Document, - tagName: string, - name: string, + tagName: Lowercase, + name: Lowercase, value: string | null, ): string | null { if (!value) { @@ -638,7 +639,7 @@ function serializeElementNode( attributes[attr.name] = transformAttribute( doc, tagName, - attr.name, + toLowerCase(attr.name), attr.value, ); } diff --git a/packages/rrweb-snapshot/src/utils.ts b/packages/rrweb-snapshot/src/utils.ts index c2f85e6e08..b124680b57 100644 --- a/packages/rrweb-snapshot/src/utils.ts +++ b/packages/rrweb-snapshot/src/utils.ts @@ -169,7 +169,7 @@ export function maskInputValue({ maskInputFn?: MaskInputFn; }): string { let text = value || ''; - const actualType = type && type.toLowerCase(); + const actualType = type && toLowerCase(type); if ( maskInputOptions[tagName.toLowerCase() as keyof MaskInputOptions] || @@ -184,6 +184,10 @@ export function maskInputValue({ return text; } +export function toLowerCase(str: T): Lowercase { + return str.toLowerCase() as unknown as Lowercase; +} + const ORIGINAL_ATTRIBUTE_NAME = '__rrweb_original__'; type PatchedGetImageData = { [ORIGINAL_ATTRIBUTE_NAME]: CanvasImageData['getImageData']; @@ -265,6 +269,6 @@ export function getInputType(element: HTMLElement): Lowercase | null { ? 'password' : type ? // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - (type.toLowerCase() as Lowercase) + toLowerCase(type) : null; } diff --git a/packages/rrweb/src/record/mutation.ts b/packages/rrweb/src/record/mutation.ts index f352424b5f..39a6107635 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -9,6 +9,7 @@ import { Mirror, isNativeShadowDom, getInputType, + toLowerCase, } from 'rrweb-snapshot'; import type { observerParam, MutationBufferParam } from '../types'; import type { @@ -597,8 +598,8 @@ export default class MutationBuffer { // overwrite attribute if the mutations was triggered in same time item.attributes[attributeName] = transformAttribute( this.doc, - target.tagName, - attributeName, + toLowerCase(target.tagName), + toLowerCase(attributeName), value, ); } diff --git a/packages/rrweb/src/record/observer.ts b/packages/rrweb/src/record/observer.ts index afd68f1864..754f92400b 100644 --- a/packages/rrweb/src/record/observer.ts +++ b/packages/rrweb/src/record/observer.ts @@ -3,6 +3,7 @@ import { maskInputValue, Mirror, getInputType, + toLowerCase, } from 'rrweb-snapshot'; import type { FontFaceSet } from 'css-font-loading-module'; import { @@ -309,13 +310,16 @@ function initMouseInteractionObserver({ disableMap[key] !== false, ) .forEach((eventKey: keyof typeof MouseInteractions) => { - let eventName = eventKey.toLowerCase(); + let eventName = toLowerCase(eventKey); const handler = getHandler(eventKey); if (window.PointerEvent) { switch (MouseInteractions[eventKey]) { case MouseInteractions.MouseDown: case MouseInteractions.MouseUp: - eventName = eventName.replace('mouse', 'pointer'); + eventName = eventName.replace( + 'mouse', + 'pointer', + ) as unknown as typeof eventName; break; case MouseInteractions.TouchStart: case MouseInteractions.TouchEnd: diff --git a/packages/rrweb/src/replay/index.ts b/packages/rrweb/src/replay/index.ts index 1bc9c6a6a1..aac84c2783 100644 --- a/packages/rrweb/src/replay/index.ts +++ b/packages/rrweb/src/replay/index.ts @@ -8,6 +8,7 @@ import { createMirror, attributes, serializedElementNodeWithId, + toLowerCase, } from 'rrweb-snapshot'; import { RRDocument, @@ -1120,7 +1121,7 @@ export class Replayer { if (d.id === -1) { break; } - const event = new Event(MouseInteractions[d.type].toLowerCase()); + const event = new Event(toLowerCase(MouseInteractions[d.type])); const target = this.mirror.getNode(d.id); if (!target) { return this.debugNodeNotFound(d, d.id); From 325a9f093ebf9e5a6d0b0ad7620260df9fc2e202 Mon Sep 17 00:00:00 2001 From: Eoghan Murray Date: Fri, 2 Jun 2023 11:19:35 +0100 Subject: [PATCH 008/123] Update test commands (#1205) * As per @Yun Feng: everyone has npm installed globally but maybe not yarn * Add command to enable test result updating * Default to running tests HEADLESS on rrweb * Add command to build:all in a low memory environment * Add a 'retest' command for when the code hasn't changed, but you are working on the test cases * Add commands to reformat according to prettier. Named 'reformat' to indicate that we are doing a `--write` * Update package.json Co-authored-by: Yun Feng * Apply suggestions from code review Co-authored-by: Yun Feng * Create few-turkeys-reflect.md * Apply formatting changes --------- Co-authored-by: Justin Halsall Co-authored-by: Yun Feng --- .changeset/few-turkeys-reflect.md | 2 ++ README.md | 5 +++-- package.json | 4 +++- packages/rrweb-snapshot/package.json | 3 ++- packages/rrweb/package.json | 12 ++++++++---- turbo.json | 1 + 6 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 .changeset/few-turkeys-reflect.md diff --git a/.changeset/few-turkeys-reflect.md b/.changeset/few-turkeys-reflect.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/few-turkeys-reflect.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/README.md b/README.md index 491b7fb217..697cbcdabb 100644 --- a/README.md +++ b/README.md @@ -64,8 +64,9 @@ Since we want the record and replay sides to share a strongly typed data structu 2. Run `yarn install` in the root to install required dependencies for all sub-packages (note: `npm install` is _not_ recommended). 3. Run `yarn dev` in the root to get auto-building for all the sub-packages whenever you modify anything. 4. Navigate to one of the sub-packages (in the `packages` folder) where you'd like to make a change. -5. Patch the code and run `yarn test` to run the tests, make sure they pass before you commit anything. -6. Push the code and create a pull request. +5. Patch the code and run `yarn test` to run the tests, make sure they pass before you commit anything. Add test cases in order to avoid future regression. +6. If tests are failing, but the change in output is desirable, run `yarn test:update` and carefully commit the changes in test output. +7. Push the code and create a pull request. Protip: You can run `yarn test` in the root folder to run all the tests. diff --git a/package.json b/package.json index 60096855a9..3e7cb6027c 100644 --- a/package.json +++ b/package.json @@ -36,9 +36,11 @@ "typescript": "^4.7.3" }, "scripts": { - "build:all": "yarn run concurrently --success=all -r -m=1 'yarn workspaces-to-typescript-project-references' 'yarn turbo run prepublish'", + "build:all": "NODE_OPTIONS='--max-old-space-size=4096' yarn run concurrently --success=all -r -m=1 'yarn workspaces-to-typescript-project-references' 'yarn turbo run prepublish'", "test": "yarn run concurrently --success=all -r -m=1 'yarn workspaces-to-typescript-project-references --check' 'yarn turbo run test'", "test:watch": "yarn turbo run test:watch", + "test:update": "yarn turbo run test:update", + "format": "yarn prettier --write '**/*.{ts,md}'", "dev": "yarn turbo run dev", "repl": "cd packages/rrweb && npm run repl", "live-stream": "cd packages/rrweb && yarn live-stream", diff --git a/packages/rrweb-snapshot/package.json b/packages/rrweb-snapshot/package.json index e4d8f3b766..7dc4c4397a 100644 --- a/packages/rrweb-snapshot/package.json +++ b/packages/rrweb-snapshot/package.json @@ -7,11 +7,12 @@ "prepack": "npm run bundle && npm run typings", "test": "jest", "test:watch": "jest --watch", + "test:update": "jest --updateSnapshot", "bundle": "rollup --config", "bundle:es-only": "cross-env ES_ONLY=true rollup --config", "dev": "yarn bundle:es-only --watch", "typings": "tsc -d --declarationDir typings", - "prepublish": "npm run typings && npm run bundle", + "prepublish": "yarn typings && yarn bundle", "lint": "yarn eslint src" }, "type": "module", diff --git a/packages/rrweb/package.json b/packages/rrweb/package.json index 9064f03e93..42d092aeed 100644 --- a/packages/rrweb/package.json +++ b/packages/rrweb/package.json @@ -5,10 +5,14 @@ "scripts": { "prepare": "npm run prepack", "prepack": "npm run bundle", - "test": "npm run bundle:browser && jest --testPathIgnorePatterns test/benchmark", - "test:headless": "PUPPETEER_HEADLESS=true npm run test", - "test:watch": "PUPPETEER_HEADLESS=true npm run test -- --watch", - "repl": "npm run bundle:browser && node scripts/repl.js", + "retest": "jest --testPathIgnorePatterns test/benchmark", + "build-and-test": "yarn bundle:browser && yarn retest", + "test:headless": "PUPPETEER_HEADLESS=true yarn build-and-test", + "test:headful": "PUPPETEER_HEADLESS=false yarn build-and-test", + "test": "yarn test:headless", + "test:watch": "yarn test:headless -- --watch", + "test:update": "yarn test:headless -- --updateSnapshot", + "repl": "yarn bundle:browser && node scripts/repl.js", "live-stream": "yarn bundle:browser && node scripts/stream.js", "dev": "yarn bundle:browser --watch", "bundle:browser": "cross-env BROWSER_ONLY=true rollup --config", diff --git a/turbo.json b/turbo.json index c14def8617..70ca7bb533 100644 --- a/turbo.json +++ b/turbo.json @@ -10,6 +10,7 @@ "test:watch": { "persistent": true }, + "test:update": {}, "dev": { "dependsOn": ["^prepublish"], "persistent": true From 490b3e2b62b62d61e6f6f5391d5b879194c9a221 Mon Sep 17 00:00:00 2001 From: Eoghan Murray Date: Fri, 2 Jun 2023 11:20:14 +0100 Subject: [PATCH 009/123] Guard against redefinition of Date.now (#1196) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Guard against presence of likely older third party libraries which (re)define Date.now, e.g. https://github.com/datejs/Datejs/issues/92 * Apply formatting changes * (remove nowTimestamp import where Date.now() is not used) * Add a PURE marker so an empty `ìf` statement doesn't show up in the rrweb-replay output * Update packages/rrweb/src/utils.ts Fix typing issue with regex against `Date.now()` Co-authored-by: Justin Halsall * Create little-radios-thank.md * Apply formatting changes * Update .changeset/little-radios-thank.md * Apply formatting changes --------- Co-authored-by: eoghanmurray Co-authored-by: Justin Halsall --- .changeset/date-now-guard.md | 5 +++++ .changeset/little-radios-thank.md | 5 +++++ packages/rrweb/src/record/index.ts | 3 ++- packages/rrweb/src/record/observer.ts | 5 +++-- packages/rrweb/src/utils.ts | 9 +++++++++ 5 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 .changeset/date-now-guard.md create mode 100644 .changeset/little-radios-thank.md diff --git a/.changeset/date-now-guard.md b/.changeset/date-now-guard.md new file mode 100644 index 0000000000..2e0ac5e711 --- /dev/null +++ b/.changeset/date-now-guard.md @@ -0,0 +1,5 @@ +--- +'rrweb': patch +--- + +Guard against presence of older 3rd party javascript libraries which redefine Date.now() diff --git a/.changeset/little-radios-thank.md b/.changeset/little-radios-thank.md new file mode 100644 index 0000000000..ea9c3f609d --- /dev/null +++ b/.changeset/little-radios-thank.md @@ -0,0 +1,5 @@ +--- +'rrweb': patch +--- + +Guard against redefinition of Date.now by third party libraries which are also present on a page alongside rrweb diff --git a/packages/rrweb/src/record/index.ts b/packages/rrweb/src/record/index.ts index c0e69a025f..563942312f 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -14,6 +14,7 @@ import { hasShadowRoot, isSerializedIframe, isSerializedStylesheet, + nowTimestamp, } from '../utils'; import type { recordOptions } from '../types'; import { @@ -42,7 +43,7 @@ import { function wrapEvent(e: event): eventWithTime { return { ...e, - timestamp: Date.now(), + timestamp: nowTimestamp(), }; } diff --git a/packages/rrweb/src/record/observer.ts b/packages/rrweb/src/record/observer.ts index 754f92400b..78690578ad 100644 --- a/packages/rrweb/src/record/observer.ts +++ b/packages/rrweb/src/record/observer.ts @@ -17,6 +17,7 @@ import { legacy_isTouchEvent, patch, StyleSheetMirror, + nowTimestamp, } from '../utils'; import type { observerParam, MutationBufferParam } from '../types'; import { @@ -181,13 +182,13 @@ function initMoveObserver({ ? evt.changedTouches[0] : evt; if (!timeBaseline) { - timeBaseline = Date.now(); + timeBaseline = nowTimestamp(); } positions.push({ x: clientX, y: clientY, id: mirror.getId(target as Node), - timeOffset: Date.now() - timeBaseline, + timeOffset: nowTimestamp() - timeBaseline, }); // it is possible DragEvent is undefined even on devices // that support event 'drag' diff --git a/packages/rrweb/src/utils.ts b/packages/rrweb/src/utils.ts index 2197796258..604c8810e2 100644 --- a/packages/rrweb/src/utils.ts +++ b/packages/rrweb/src/utils.ts @@ -168,6 +168,15 @@ export function patch( } } +// guard against old third party libraries which redefine Date.now +let nowTimestamp = Date.now; + +if (!(/*@__PURE__*/ /[1-9][0-9]{12}/.test(Date.now().toString()))) { + // they have already redefined it! use a fallback + nowTimestamp = () => new Date().getTime(); +} +export { nowTimestamp }; + export function getWindowScroll(win: Window) { const doc = win.document; return { From a01a12ef6769f26aa922ccd6ac76499f0837f0c2 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Fri, 30 Jun 2023 02:35:38 +0200 Subject: [PATCH 010/123] Fix types in rrwebPlayer (#1247) * Export correct mirror in player Was using DeprecatedMirror in its types, that shouldn't be used anymore. * Add playRange to types * Create smooth-poems-bake.md * Apply formatting changes * Add $set to player type * Update smooth-poems-bake.md * Apply formatting changes * Last two arguments of playRange are optional --- .changeset/smooth-poems-bake.md | 5 +++++ packages/rrweb-player/typings/index.d.ts | 12 ++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 .changeset/smooth-poems-bake.md diff --git a/.changeset/smooth-poems-bake.md b/.changeset/smooth-poems-bake.md new file mode 100644 index 0000000000..9d4fac8ff6 --- /dev/null +++ b/.changeset/smooth-poems-bake.md @@ -0,0 +1,5 @@ +--- +'rrweb-player': patch +--- + +Fix `player.getMirror`, `player.playRange`, `player.$set` types in rrwebPlayer diff --git a/packages/rrweb-player/typings/index.d.ts b/packages/rrweb-player/typings/index.d.ts index b27799aa88..e76b493e6f 100755 --- a/packages/rrweb-player/typings/index.d.ts +++ b/packages/rrweb-player/typings/index.d.ts @@ -1,6 +1,7 @@ import { playerConfig } from 'rrweb/typings/types'; import { eventWithTime } from '@rrweb/types'; -import { Replayer, mirror } from 'rrweb'; +import { Replayer } from 'rrweb'; +import { Mirror } from 'rrweb-snapshot'; import { SvelteComponent } from 'svelte'; export type RRwebPlayerOptions = { @@ -67,13 +68,20 @@ export default class rrwebPlayer extends SvelteComponent { addEvent(event: eventWithTime): void; getMetaData: Replayer['getMetaData']; getReplayer: () => Replayer; - getMirror: () => typeof mirror; + getMirror: () => Mirror; toggle: () => void; setSpeed: (speed: number) => void; toggleSkipInactive: () => void; triggerResize: () => void; + $set: (options: { width: number; height: number }) => void; play: () => void; pause: () => void; goto: (timeOffset: number, play?: boolean) => void; + playRange: ( + timeOffset: number, + endTimeOffset: number, + startLooping?: boolean, + afterHook?: undefined | (() => void), + ) => void; } From 46df5cd988357eee1ebc4f86e27ac47608b30f1d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 30 Jun 2023 10:54:51 +0200 Subject: [PATCH 011/123] Version Packages (alpha) (#1216) Co-authored-by: github-actions[bot] --- .changeset/pre.json | 13 +++++++++++++ packages/rrdom-nodejs/CHANGELOG.md | 8 ++++++++ packages/rrdom-nodejs/package.json | 6 +++--- packages/rrdom/CHANGELOG.md | 12 ++++++++++++ packages/rrdom/package.json | 6 +++--- packages/rrvideo/CHANGELOG.md | 9 +++++++++ packages/rrvideo/package.json | 6 +++--- packages/rrweb-player/CHANGELOG.md | 9 +++++++++ packages/rrweb-player/package.json | 6 +++--- packages/rrweb-snapshot/CHANGELOG.md | 6 ++++++ packages/rrweb-snapshot/package.json | 2 +- packages/rrweb/CHANGELOG.md | 19 +++++++++++++++++++ packages/rrweb/package.json | 8 ++++---- packages/types/CHANGELOG.md | 7 +++++++ packages/types/package.json | 4 ++-- packages/web-extension/CHANGELOG.md | 8 ++++++++ packages/web-extension/package.json | 8 ++++---- 17 files changed, 114 insertions(+), 23 deletions(-) diff --git a/.changeset/pre.json b/.changeset/pre.json index c0b7958b10..c9cc65e0ca 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -12,20 +12,31 @@ "rrvideo": "2.0.0-alpha.6" }, "changesets": [ + "brave-numbers-joke", "calm-bulldogs-speak", "chatty-cherries-train", + "cold-eyes-hunt", "controller-finish-flag", + "date-now-guard", "eight-terms-hunt", "empty-bikes-cheer", "fair-dragons-greet", "fast-chefs-smell", + "few-turkeys-reflect", "five-peas-lay", + "forty-elephants-attack", + "fresh-cars-impress", "fresh-spoons-drive", + "gold-terms-look", "grumpy-ways-own", "large-ants-prove", + "lazy-toes-confess", + "little-radios-thank", "little-suits-leave", "loud-seals-raise", "lovely-pears-cross", + "lovely-students-boil", + "mean-tips-impress", "mighty-frogs-sparkle", "nervous-poets-grin", "nervous-tables-travel", @@ -37,9 +48,11 @@ "proud-experts-jam", "real-masks-explode", "real-trains-switch", + "rich-crews-protect", "serious-ants-juggle", "sixty-impalas-laugh", "small-olives-arrive", + "smooth-poems-bake", "stupid-ghosts-help", "swift-peas-film", "tidy-yaks-joke", diff --git a/packages/rrdom-nodejs/CHANGELOG.md b/packages/rrdom-nodejs/CHANGELOG.md index 594a60a69b..4fe4518e12 100644 --- a/packages/rrdom-nodejs/CHANGELOG.md +++ b/packages/rrdom-nodejs/CHANGELOG.md @@ -1,5 +1,13 @@ # rrdom-nodejs +## 2.0.0-alpha.9 + +### Patch Changes + +- Updated dependencies [[`b798f2d`](https://github.com/rrweb-io/rrweb/commit/b798f2dbc07b5a24dcaf40d164159200b6c0679d), [`d7c72bf`](https://github.com/rrweb-io/rrweb/commit/d7c72bff0724b46a6fa94af455220626a27104fe)]: + - rrdom@2.0.0-alpha.9 + - rrweb-snapshot@2.0.0-alpha.9 + ## 2.0.0-alpha.8 ### Patch Changes diff --git a/packages/rrdom-nodejs/package.json b/packages/rrdom-nodejs/package.json index eee9d733e5..9e2b8d23b2 100644 --- a/packages/rrdom-nodejs/package.json +++ b/packages/rrdom-nodejs/package.json @@ -1,6 +1,6 @@ { "name": "rrdom-nodejs", - "version": "2.0.0-alpha.8", + "version": "2.0.0-alpha.9", "scripts": { "dev": "rollup -c -w", "bundle": "rollup --config", @@ -48,8 +48,8 @@ "cssom": "^0.5.0", "cssstyle": "^2.3.0", "nwsapi": "^2.2.0", - "rrdom": "^2.0.0-alpha.8", - "rrweb-snapshot": "^2.0.0-alpha.8" + "rrdom": "^2.0.0-alpha.9", + "rrweb-snapshot": "^2.0.0-alpha.9" }, "browserslist": [ "supports es6-class" diff --git a/packages/rrdom/CHANGELOG.md b/packages/rrdom/CHANGELOG.md index a1675cb13d..fcfd27dd0c 100644 --- a/packages/rrdom/CHANGELOG.md +++ b/packages/rrdom/CHANGELOG.md @@ -1,5 +1,17 @@ # rrdom +## 2.0.0-alpha.9 + +### Patch Changes + +- [#1222](https://github.com/rrweb-io/rrweb/pull/1222) [`b798f2d`](https://github.com/rrweb-io/rrweb/commit/b798f2dbc07b5a24dcaf40d164159200b6c0679d) Thanks [@YunFeng0817](https://github.com/YunFeng0817)! - Fix: rrdom bugs + + 1. Fix a bug in the diff algorithm. + 2. Omit the 'srcdoc' attribute of iframes to avoid overwriting content. + +- Updated dependencies [[`d7c72bf`](https://github.com/rrweb-io/rrweb/commit/d7c72bff0724b46a6fa94af455220626a27104fe)]: + - rrweb-snapshot@2.0.0-alpha.9 + ## 2.0.0-alpha.8 ### Patch Changes diff --git a/packages/rrdom/package.json b/packages/rrdom/package.json index b554693602..04bbbbad0a 100644 --- a/packages/rrdom/package.json +++ b/packages/rrdom/package.json @@ -1,6 +1,6 @@ { "name": "rrdom", - "version": "2.0.0-alpha.8", + "version": "2.0.0-alpha.9", "homepage": "https://github.com/rrweb-io/rrweb/tree/main/packages/rrdom#readme", "license": "MIT", "main": "lib/rrdom.cjs", @@ -32,7 +32,7 @@ }, "devDependencies": { "@rollup/plugin-commonjs": "^20.0.0", - "@rrweb/types": "^2.0.0-alpha.8", + "@rrweb/types": "^2.0.0-alpha.9", "@types/jest": "^27.4.1", "@types/puppeteer": "^5.4.4", "@typescript-eslint/eslint-plugin": "^5.23.0", @@ -47,6 +47,6 @@ "ts-jest": "^27.1.3" }, "dependencies": { - "rrweb-snapshot": "^2.0.0-alpha.8" + "rrweb-snapshot": "^2.0.0-alpha.9" } } diff --git a/packages/rrvideo/CHANGELOG.md b/packages/rrvideo/CHANGELOG.md index 10a4f5e0da..c603c1d329 100644 --- a/packages/rrvideo/CHANGELOG.md +++ b/packages/rrvideo/CHANGELOG.md @@ -1,5 +1,14 @@ # rrvideo +## 2.0.0-alpha.9 + +### Patch Changes + +- [#1197](https://github.com/rrweb-io/rrweb/pull/1197) [`23d0138`](https://github.com/rrweb-io/rrweb/commit/23d01387f439db68d2874879242b6ade3e103f75) Thanks [@YunFeng0817](https://github.com/YunFeng0817)! - Refactor: Improve the video quality and add a progress bar for the CLI tool + +- Updated dependencies [[`a01a12e`](https://github.com/rrweb-io/rrweb/commit/a01a12ef6769f26aa922ccd6ac76499f0837f0c2)]: + - rrweb-player@2.0.0-alpha.9 + ## 2.0.0-alpha.8 ### Patch Changes diff --git a/packages/rrvideo/package.json b/packages/rrvideo/package.json index df6d5b37c0..c654da461f 100644 --- a/packages/rrvideo/package.json +++ b/packages/rrvideo/package.json @@ -1,6 +1,6 @@ { "name": "rrvideo", - "version": "2.0.0-alpha.8", + "version": "2.0.0-alpha.9", "description": "transform rrweb session into video", "main": "build/index.js", "bin": { @@ -26,13 +26,13 @@ "@types/node": "^18.15.11", "jest": "^27.5.1", "ts-jest": "^27.1.3", - "@rrweb/types": "^2.0.0-alpha.8" + "@rrweb/types": "^2.0.0-alpha.9" }, "dependencies": { "@open-tech-world/cli-progress-bar": "^2.0.2", "fs-extra": "^11.1.1", "minimist": "^1.2.5", "playwright": "^1.32.1", - "rrweb-player": "^2.0.0-alpha.8" + "rrweb-player": "^2.0.0-alpha.9" } } diff --git a/packages/rrweb-player/CHANGELOG.md b/packages/rrweb-player/CHANGELOG.md index 04e03595b1..6c5cfe50fe 100644 --- a/packages/rrweb-player/CHANGELOG.md +++ b/packages/rrweb-player/CHANGELOG.md @@ -1,5 +1,14 @@ # rrweb-player +## 2.0.0-alpha.9 + +### Patch Changes + +- [#1247](https://github.com/rrweb-io/rrweb/pull/1247) [`a01a12e`](https://github.com/rrweb-io/rrweb/commit/a01a12ef6769f26aa922ccd6ac76499f0837f0c2) Thanks [@Juice10](https://github.com/Juice10)! - Fix `player.getMirror`, `player.playRange`, `player.$set` types in rrwebPlayer + +- Updated dependencies [[`490b3e2`](https://github.com/rrweb-io/rrweb/commit/490b3e2b62b62d61e6f6f5391d5b879194c9a221), [`a1ec9a2`](https://github.com/rrweb-io/rrweb/commit/a1ec9a273e6634eec67098fdd880ee681648fbbd), [`490b3e2`](https://github.com/rrweb-io/rrweb/commit/490b3e2b62b62d61e6f6f5391d5b879194c9a221), [`d7c72bf`](https://github.com/rrweb-io/rrweb/commit/d7c72bff0724b46a6fa94af455220626a27104fe), [`ebcbe8b`](https://github.com/rrweb-io/rrweb/commit/ebcbe8b0d746a0a4c07d3530387f920900f35215)]: + - rrweb@2.0.0-alpha.9 + ## 2.0.0-alpha.8 ### Patch Changes diff --git a/packages/rrweb-player/package.json b/packages/rrweb-player/package.json index e8d61cd44f..5536cc6b12 100644 --- a/packages/rrweb-player/package.json +++ b/packages/rrweb-player/package.json @@ -1,10 +1,10 @@ { "name": "rrweb-player", - "version": "2.0.0-alpha.8", + "version": "2.0.0-alpha.9", "devDependencies": { "@rollup/plugin-commonjs": "^22.0.0", "@rollup/plugin-node-resolve": "^13.2.1", - "@rrweb/types": "^2.0.0-alpha.8", + "@rrweb/types": "^2.0.0-alpha.9", "@types/offscreencanvas": "^2019.6.4", "eslint-config-google": "^0.14.0", "eslint-plugin-svelte3": "^4.0.0", @@ -24,7 +24,7 @@ }, "dependencies": { "@tsconfig/svelte": "^1.0.0", - "rrweb": "^2.0.0-alpha.8" + "rrweb": "^2.0.0-alpha.9" }, "scripts": { "build": "rollup -c", diff --git a/packages/rrweb-snapshot/CHANGELOG.md b/packages/rrweb-snapshot/CHANGELOG.md index 408bbeaebe..3ac44a0032 100644 --- a/packages/rrweb-snapshot/CHANGELOG.md +++ b/packages/rrweb-snapshot/CHANGELOG.md @@ -1,5 +1,11 @@ # rrweb-snapshot +## 2.0.0-alpha.9 + +### Patch Changes + +- [#1183](https://github.com/rrweb-io/rrweb/pull/1183) [`d7c72bf`](https://github.com/rrweb-io/rrweb/commit/d7c72bff0724b46a6fa94af455220626a27104fe) Thanks [@mydea](https://github.com/mydea)! - fix: Ensure attributes are lowercased when checking + ## 2.0.0-alpha.8 ### Minor Changes diff --git a/packages/rrweb-snapshot/package.json b/packages/rrweb-snapshot/package.json index 7dc4c4397a..4fc2fda5d6 100644 --- a/packages/rrweb-snapshot/package.json +++ b/packages/rrweb-snapshot/package.json @@ -1,6 +1,6 @@ { "name": "rrweb-snapshot", - "version": "2.0.0-alpha.8", + "version": "2.0.0-alpha.9", "description": "rrweb's component to take a snapshot of DOM, aka DOM serializer", "scripts": { "prepare": "npm run prepack", diff --git a/packages/rrweb/CHANGELOG.md b/packages/rrweb/CHANGELOG.md index aeb7c4dbbc..7eed53c2b3 100644 --- a/packages/rrweb/CHANGELOG.md +++ b/packages/rrweb/CHANGELOG.md @@ -1,5 +1,24 @@ # rrweb +## 2.0.0-alpha.9 + +### Patch Changes + +- [#1196](https://github.com/rrweb-io/rrweb/pull/1196) [`490b3e2`](https://github.com/rrweb-io/rrweb/commit/490b3e2b62b62d61e6f6f5391d5b879194c9a221) Thanks [@eoghanmurray](https://github.com/eoghanmurray)! - Guard against presence of older 3rd party javascript libraries which redefine Date.now() + +- [#1220](https://github.com/rrweb-io/rrweb/pull/1220) [`a1ec9a2`](https://github.com/rrweb-io/rrweb/commit/a1ec9a273e6634eec67098fdd880ee681648fbbd) Thanks [@wfk007](https://github.com/wfk007)! - perf: optimize performance of the DoubleLinkedList get + +- [#1196](https://github.com/rrweb-io/rrweb/pull/1196) [`490b3e2`](https://github.com/rrweb-io/rrweb/commit/490b3e2b62b62d61e6f6f5391d5b879194c9a221) Thanks [@eoghanmurray](https://github.com/eoghanmurray)! - Guard against redefinition of Date.now by third party libraries which are also present on a page alongside rrweb + +- [#1183](https://github.com/rrweb-io/rrweb/pull/1183) [`d7c72bf`](https://github.com/rrweb-io/rrweb/commit/d7c72bff0724b46a6fa94af455220626a27104fe) Thanks [@mydea](https://github.com/mydea)! - fix: Ensure attributes are lowercased when checking + +- [#1214](https://github.com/rrweb-io/rrweb/pull/1214) [`ebcbe8b`](https://github.com/rrweb-io/rrweb/commit/ebcbe8b0d746a0a4c07d3530387f920900f35215) Thanks [@wfk007](https://github.com/wfk007)! - perf: optimize the performance of record in processMutation phase + +- Updated dependencies [[`b798f2d`](https://github.com/rrweb-io/rrweb/commit/b798f2dbc07b5a24dcaf40d164159200b6c0679d), [`d7c72bf`](https://github.com/rrweb-io/rrweb/commit/d7c72bff0724b46a6fa94af455220626a27104fe)]: + - rrdom@2.0.0-alpha.9 + - rrweb-snapshot@2.0.0-alpha.9 + - @rrweb/types@2.0.0-alpha.9 + ## 2.0.0-alpha.8 ### Minor Changes diff --git a/packages/rrweb/package.json b/packages/rrweb/package.json index 42d092aeed..9b50b2fdb4 100644 --- a/packages/rrweb/package.json +++ b/packages/rrweb/package.json @@ -1,6 +1,6 @@ { "name": "rrweb", - "version": "2.0.0-alpha.8", + "version": "2.0.0-alpha.9", "description": "record and replay the web", "scripts": { "prepare": "npm run prepack", @@ -81,13 +81,13 @@ "tslib": "^2.3.1" }, "dependencies": { - "@rrweb/types": "^2.0.0-alpha.8", + "@rrweb/types": "^2.0.0-alpha.9", "@types/css-font-loading-module": "0.0.7", "@xstate/fsm": "^1.4.0", "base64-arraybuffer": "^1.0.1", "fflate": "^0.4.4", "mitt": "^3.0.0", - "rrdom": "^2.0.0-alpha.8", - "rrweb-snapshot": "^2.0.0-alpha.8" + "rrdom": "^2.0.0-alpha.9", + "rrweb-snapshot": "^2.0.0-alpha.9" } } diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index 7ce37d89b6..c25deee87b 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -1,5 +1,12 @@ # @rrweb/types +## 2.0.0-alpha.9 + +### Patch Changes + +- Updated dependencies [[`d7c72bf`](https://github.com/rrweb-io/rrweb/commit/d7c72bff0724b46a6fa94af455220626a27104fe)]: + - rrweb-snapshot@2.0.0-alpha.9 + ## 2.0.0-alpha.8 ### Minor Changes diff --git a/packages/types/package.json b/packages/types/package.json index d06eb0c01b..c438396a99 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@rrweb/types", - "version": "2.0.0-alpha.8", + "version": "2.0.0-alpha.9", "publishConfig": { "access": "public" }, @@ -43,7 +43,7 @@ "vite-plugin-dts": "^1.6.6" }, "dependencies": { - "rrweb-snapshot": "^2.0.0-alpha.8" + "rrweb-snapshot": "^2.0.0-alpha.9" }, "browserslist": [ "supports es6-class" diff --git a/packages/web-extension/CHANGELOG.md b/packages/web-extension/CHANGELOG.md index 7959bf4399..92661a43ac 100644 --- a/packages/web-extension/CHANGELOG.md +++ b/packages/web-extension/CHANGELOG.md @@ -1,5 +1,13 @@ # @rrweb/web-extension +## 2.0.0-alpha.9 + +### Patch Changes + +- Updated dependencies [[`490b3e2`](https://github.com/rrweb-io/rrweb/commit/490b3e2b62b62d61e6f6f5391d5b879194c9a221), [`a1ec9a2`](https://github.com/rrweb-io/rrweb/commit/a1ec9a273e6634eec67098fdd880ee681648fbbd), [`490b3e2`](https://github.com/rrweb-io/rrweb/commit/490b3e2b62b62d61e6f6f5391d5b879194c9a221), [`d7c72bf`](https://github.com/rrweb-io/rrweb/commit/d7c72bff0724b46a6fa94af455220626a27104fe), [`ebcbe8b`](https://github.com/rrweb-io/rrweb/commit/ebcbe8b0d746a0a4c07d3530387f920900f35215), [`a01a12e`](https://github.com/rrweb-io/rrweb/commit/a01a12ef6769f26aa922ccd6ac76499f0837f0c2)]: + - rrweb@2.0.0-alpha.9 + - rrweb-player@2.0.0-alpha.9 + ## 2.0.0-alpha.8 ### Patch Changes diff --git a/packages/web-extension/package.json b/packages/web-extension/package.json index 9d1666ab2c..2e438d485a 100644 --- a/packages/web-extension/package.json +++ b/packages/web-extension/package.json @@ -1,7 +1,7 @@ { "name": "@rrweb/web-extension", "private": true, - "version": "2.0.0-alpha.8", + "version": "2.0.0-alpha.9", "description": "The web extension of rrweb which helps to run rrweb on any website out of box", "author": "rrweb-io", "license": "MIT", @@ -16,7 +16,7 @@ "prepublish": "npm run pack:chrome && npm run pack:firefox" }, "devDependencies": { - "@rrweb/types": "^2.0.0-alpha.8", + "@rrweb/types": "^2.0.0-alpha.9", "@types/react-dom": "^18.0.6", "@types/webextension-polyfill": "^0.9.1", "@vitejs/plugin-react": "^2.1.0", @@ -40,7 +40,7 @@ "react-dom": "^18.2.0", "react-icons": "^4.4.0", "react-router-dom": "^6.4.1", - "rrweb": "^2.0.0-alpha.8", - "rrweb-player": "^2.0.0-alpha.8" + "rrweb": "^2.0.0-alpha.9", + "rrweb-player": "^2.0.0-alpha.9" } } From bbbfa226fc5882a01ecc1607b713f0caf797775e Mon Sep 17 00:00:00 2001 From: fukang wang Date: Fri, 7 Jul 2023 17:57:37 +0800 Subject: [PATCH 012/123] fix: Resize and MediaInteraction events repeat generated after the iframe appeared (#1251) * fix: Resize and MediaInteraction events repeat generated after the iframe appeared * Create nervous-buses-pump.md * Apply formatting changes --------- Co-authored-by: wangfukang Co-authored-by: wfk007 --- .changeset/nervous-buses-pump.md | 5 +++++ packages/rrweb/src/record/observer.ts | 24 ++++++++++++++---------- 2 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 .changeset/nervous-buses-pump.md diff --git a/.changeset/nervous-buses-pump.md b/.changeset/nervous-buses-pump.md new file mode 100644 index 0000000000..49b7617159 --- /dev/null +++ b/.changeset/nervous-buses-pump.md @@ -0,0 +1,5 @@ +--- +'rrweb': patch +--- + +fix: Resize and MediaInteraction events repeat generated after the iframe appeared diff --git a/packages/rrweb/src/record/observer.ts b/packages/rrweb/src/record/observer.ts index 78690578ad..0da565f085 100644 --- a/packages/rrweb/src/record/observer.ts +++ b/packages/rrweb/src/record/observer.ts @@ -378,9 +378,10 @@ export function initScrollObserver({ return on('scroll', updatePosition, doc); } -function initViewportResizeObserver({ - viewportResizeCb, -}: observerParam): listenerHandler { +function initViewportResizeObserver( + { viewportResizeCb }: observerParam, + { win }: { win: IWindow }, +): listenerHandler { let lastH = -1; let lastW = -1; const updateDimension = callbackWrapper( @@ -400,7 +401,7 @@ function initViewportResizeObserver({ 200, ), ); - return on('resize', updateDimension, window); + return on('resize', updateDimension, win); } function wrapEventWithUserTriggeredFlag( @@ -1035,6 +1036,7 @@ function initMediaInteractionObserver({ blockSelector, mirror, sampling, + doc, }: observerParam): listenerHandler { const handler = callbackWrapper((type: MediaInteractions) => throttle( @@ -1061,11 +1063,11 @@ function initMediaInteractionObserver({ ), ); const handlers = [ - on('play', handler(MediaInteractions.Play)), - on('pause', handler(MediaInteractions.Pause)), - on('seeked', handler(MediaInteractions.Seeked)), - on('volumechange', handler(MediaInteractions.VolumeChange)), - on('ratechange', handler(MediaInteractions.RateChange)), + on('play', handler(MediaInteractions.Play), doc), + on('pause', handler(MediaInteractions.Pause), doc), + on('seeked', handler(MediaInteractions.Seeked), doc), + on('volumechange', handler(MediaInteractions.VolumeChange), doc), + on('ratechange', handler(MediaInteractions.RateChange), doc), ]; return callbackWrapper(() => { handlers.forEach((h) => h()); @@ -1279,7 +1281,9 @@ export function initObservers( const mousemoveHandler = initMoveObserver(o); const mouseInteractionHandler = initMouseInteractionObserver(o); const scrollHandler = initScrollObserver(o); - const viewportResizeHandler = initViewportResizeObserver(o); + const viewportResizeHandler = initViewportResizeObserver(o, { + win: currentWindow, + }); const inputHandler = initInputObserver(o); const mediaInteractionHandler = initMediaInteractionObserver(o); From d0fbe23c632021410a6dd45f9028a9a012467261 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Fri, 7 Jul 2023 15:22:54 +0200 Subject: [PATCH 013/123] fix: Handle case where `event` is null/undefined (#1254) * fix: Handle case where `event` is null/undefined * add changeset --- .changeset/tiny-buckets-love.md | 5 +++++ packages/rrweb/src/record/observer.ts | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 .changeset/tiny-buckets-love.md diff --git a/.changeset/tiny-buckets-love.md b/.changeset/tiny-buckets-love.md new file mode 100644 index 0000000000..1f67b3f465 --- /dev/null +++ b/.changeset/tiny-buckets-love.md @@ -0,0 +1,5 @@ +--- +'rrweb': patch +--- + +Handle case where `event` is null/undefined diff --git a/packages/rrweb/src/record/observer.ts b/packages/rrweb/src/record/observer.ts index 0da565f085..9a02c4adcc 100644 --- a/packages/rrweb/src/record/observer.ts +++ b/packages/rrweb/src/record/observer.ts @@ -76,10 +76,11 @@ function getEventTarget(event: Event | NonStandardEvent): EventTarget | null { } else if ('path' in event && event.path.length) { return event.path[0]; } - return event.target; } catch { - return event.target; + // fallback to `event.target` below } + + return event && event.target; } export function initMutationObserver( From c6600e742b8ec0b6295816bb5de9edcd624d975e Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Fri, 7 Jul 2023 15:23:38 +0200 Subject: [PATCH 014/123] fix: Fix CSS rules captured in Safari (#1253) * fix: Fix CSS rules captured in Safari * Apply formatting changes * add changeset * fix --------- Co-authored-by: mydea --- .changeset/thirty-baboons-punch.md | 5 +++++ packages/rrweb-snapshot/src/snapshot.ts | 5 ++++- packages/rrweb-snapshot/src/utils.ts | 11 +++++++++++ packages/rrweb-snapshot/test/css.test.ts | 14 ++++++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 .changeset/thirty-baboons-punch.md diff --git a/.changeset/thirty-baboons-punch.md b/.changeset/thirty-baboons-punch.md new file mode 100644 index 0000000000..1dd1c36fad --- /dev/null +++ b/.changeset/thirty-baboons-punch.md @@ -0,0 +1,5 @@ +--- +'rrweb-snapshot': patch +--- + +Fix CSS rules captured in Safari diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index 51f76f46f8..bb18542d26 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -22,6 +22,7 @@ import { getCssRulesString, getInputType, toLowerCase, + validateStringifiedCssRule, } from './utils'; let _id = 1; @@ -53,7 +54,9 @@ function getValidTagName(element: HTMLElement): Lowercase { function stringifyStyleSheet(sheet: CSSStyleSheet): string { return sheet.cssRules ? Array.from(sheet.cssRules) - .map((rule) => rule.cssText || '') + .map((rule) => + rule.cssText ? validateStringifiedCssRule(rule.cssText) : '', + ) .join('') : ''; } diff --git a/packages/rrweb-snapshot/src/utils.ts b/packages/rrweb-snapshot/src/utils.ts index b124680b57..06e3b7a010 100644 --- a/packages/rrweb-snapshot/src/utils.ts +++ b/packages/rrweb-snapshot/src/utils.ts @@ -76,6 +76,17 @@ export function getCssRuleString(rule: CSSRule): string { // ignore } } + return validateStringifiedCssRule(cssStringified); +} + +export function validateStringifiedCssRule(cssStringified: string): string { + // Safari does not escape selectors with : properly + if (cssStringified.includes(':')) { + // Replace e.g. [aa:bb] with [aa\\:bb] + const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm; + return cssStringified.replace(regex, '$1\\$2'); + } + return cssStringified; } diff --git a/packages/rrweb-snapshot/test/css.test.ts b/packages/rrweb-snapshot/test/css.test.ts index 4461022beb..328ecc77d6 100644 --- a/packages/rrweb-snapshot/test/css.test.ts +++ b/packages/rrweb-snapshot/test/css.test.ts @@ -1,4 +1,5 @@ import { parse, Rule, Media } from '../src/css'; +import { validateStringifiedCssRule } from './../src/utils'; describe('css parser', () => { it('should save the filename and source', () => { @@ -106,4 +107,17 @@ describe('css parser', () => { decl = rule.declarations![0]; expect(decl.parent).toEqual(rule); }); + + it('parses : in attribute selectors correctly', () => { + const out1 = validateStringifiedCssRule('[data-foo] { color: red; }'); + expect(out1).toEqual('[data-foo] { color: red; }'); + + const out2 = validateStringifiedCssRule('[data-foo:other] { color: red; }'); + expect(out2).toEqual('[data-foo\\:other] { color: red; }'); + + const out3 = validateStringifiedCssRule( + '[data-aa\\:other] { color: red; }', + ); + expect(out3).toEqual('[data-aa\\:other] { color: red; }'); + }); }); From d872d2809e3ec8d6ff5d3d5f43bc81aff70e7548 Mon Sep 17 00:00:00 2001 From: Eoghan Murray Date: Thu, 3 Aug 2023 13:56:31 +0100 Subject: [PATCH 015/123] Compact style mutation fixes and improvements (#1268) * Don't use the CSSOM when there's `var()` present as it fails badly https://github.com/rrweb-io/rrweb/pull/1246 * As the CSS Object Model expands out shorthand properties, do a check on the string length before choosing which format to go for - this approach allows 'var()' in a styleOMValue as it's only a problem when combined with a shorthand property - before this change background:black; was getting expaned to 10 OM properties as follows: 'style': { 'background-color': 'black', 'background-image': false, 'background-position-x': false, 'background-position-y': false, 'background-size': false, 'background-repeat-x': false, 'background-repeat-y': false, 'background-attachment': false, 'background-origin': false, 'background-clip': false } * Updates to remainder of tests based on refined compact style mutations * Apply suggestions from code review by: Justin Halsall --------- Authored-by: eoghanmurray --- .changeset/clean-plants-play.md | 9 + packages/rrweb/src/record/mutation.ts | 93 ++++--- .../__snapshots__/integration.test.ts.snap | 240 +++++++++++++++++- packages/rrweb/test/integration.test.ts | 50 ++++ .../cross-origin-iframes.test.ts.snap | 5 +- packages/rrweb/test/utils.ts | 33 +-- packages/types/src/index.ts | 8 +- 7 files changed, 366 insertions(+), 72 deletions(-) create mode 100644 .changeset/clean-plants-play.md diff --git a/.changeset/clean-plants-play.md b/.changeset/clean-plants-play.md new file mode 100644 index 0000000000..809dae8d86 --- /dev/null +++ b/.changeset/clean-plants-play.md @@ -0,0 +1,9 @@ +--- +'rrweb': patch +'@rrweb/types': patch +--- + +Compact style mutation fixes and improvements + +- fixes when style updates contain a 'var()' on a shorthand property #1246 +- further ensures that style mutations are compact by reverting to string method if it is shorter diff --git a/packages/rrweb/src/record/mutation.ts b/packages/rrweb/src/record/mutation.ts index 39a6107635..0eea35c073 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -18,7 +18,6 @@ import type { attributeCursor, removedNodeMutation, addedNodeMutation, - styleAttributeValue, Optional, } from '@rrweb/types'; import { @@ -438,10 +437,29 @@ export default class MutationBuffer { // text mutation's id was not in the mirror map means the target node has been removed .filter((text) => this.mirror.has(text.id)), attributes: this.attributes - .map((attribute) => ({ - id: this.mirror.getId(attribute.node), - attributes: attribute.attributes, - })) + .map((attribute) => { + const { attributes } = attribute; + if (typeof attributes.style === 'string') { + const diffAsStr = JSON.stringify(attribute.styleDiff); + const unchangedAsStr = JSON.stringify(attribute._unchangedStyles); + // check if the style diff is actually shorter than the regular string based mutation + // (which was the whole point of #464 'compact style mutation'). + if (diffAsStr.length < attributes.style.length) { + // also: CSSOM fails badly when var() is present on shorthand properties, so only proceed with + // the compact style mutation if these have all been accounted for + if ( + (diffAsStr + unchangedAsStr).split('var(').length === + attributes.style.split('var(').length + ) { + attributes.style = attribute.styleDiff; + } + } + } + return { + id: this.mirror.getId(attribute.node), + attributes: attributes, + }; + }) // attribute mutation's id was not in the mirror map means the target node has been removed .filter((attribute) => this.mirror.has(attribute.id)), removes: this.removes, @@ -548,6 +566,8 @@ export default class MutationBuffer { item = { node: m.target, attributes: {}, + styleDiff: {}, + _unchangedStyles: {}, }; this.attributes.push(item); } @@ -562,39 +582,7 @@ export default class MutationBuffer { target.setAttribute('data-rr-is-password', 'true'); } - if (attributeName === 'style') { - const old = unattachedDoc.createElement('span'); - if (m.oldValue) { - old.setAttribute('style', m.oldValue); - } - if ( - item.attributes.style === undefined || - item.attributes.style === null - ) { - item.attributes.style = {}; - } - const styleObj = item.attributes.style as styleAttributeValue; - for (const pname of Array.from(target.style)) { - const newValue = target.style.getPropertyValue(pname); - const newPriority = target.style.getPropertyPriority(pname); - if ( - newValue !== old.style.getPropertyValue(pname) || - newPriority !== old.style.getPropertyPriority(pname) - ) { - if (newPriority === '') { - styleObj[pname] = newValue; - } else { - styleObj[pname] = [newValue, newPriority]; - } - } - } - for (const pname of Array.from(old.style)) { - if (target.style.getPropertyValue(pname) === '') { - // "if not set, returns the empty string" - styleObj[pname] = false; // delete - } - } - } else if (!ignoreAttribute(target.tagName, attributeName, value)) { + if (!ignoreAttribute(target.tagName, attributeName, value)) { // overwrite attribute if the mutations was triggered in same time item.attributes[attributeName] = transformAttribute( this.doc, @@ -602,6 +590,35 @@ export default class MutationBuffer { toLowerCase(attributeName), value, ); + if (attributeName === 'style') { + const old = unattachedDoc.createElement('span'); + if (m.oldValue) { + old.setAttribute('style', m.oldValue); + } + for (const pname of Array.from(target.style)) { + const newValue = target.style.getPropertyValue(pname); + const newPriority = target.style.getPropertyPriority(pname); + if ( + newValue !== old.style.getPropertyValue(pname) || + newPriority !== old.style.getPropertyPriority(pname) + ) { + if (newPriority === '') { + item.styleDiff[pname] = newValue; + } else { + item.styleDiff[pname] = [newValue, newPriority]; + } + } else { + // for checking + item._unchangedStyles[pname] = [newValue, newPriority]; + } + } + for (const pname of Array.from(old.style)) { + if (target.style.getPropertyValue(pname) === '') { + // "if not set, returns the empty string" + item.styleDiff[pname] = false; // delete + } + } + } } break; } diff --git a/packages/rrweb/test/__snapshots__/integration.test.ts.snap b/packages/rrweb/test/__snapshots__/integration.test.ts.snap index f244948b67..773d2351b4 100644 --- a/packages/rrweb/test/__snapshots__/integration.test.ts.snap +++ b/packages/rrweb/test/__snapshots__/integration.test.ts.snap @@ -2933,24 +2933,14 @@ exports[`record integration tests can record node mutations 1`] = ` \\"id\\": 36, \\"attributes\\": { \\"id\\": \\"select2-drop\\", - \\"style\\": { - \\"left\\": \\"Npx\\", - \\"width\\": \\"Npx\\", - \\"top\\": \\"Npx\\", - \\"bottom\\": \\"auto\\", - \\"display\\": \\"block\\", - \\"position\\": false, - \\"visibility\\": false - }, + \\"style\\": \\"left: Npx; width: Npx; top: Npx; bottom: auto; display: block;\\", \\"class\\": \\"select2-drop select2-display-none select2-with-searchbox select2-drop-active\\" } }, { \\"id\\": 70, \\"attributes\\": { - \\"style\\": { - \\"display\\": false - } + \\"style\\": \\"\\" } }, { @@ -3391,6 +3381,232 @@ exports[`record integration tests can record node mutations 1`] = ` ]" `; +exports[`record integration tests can record style changes compactly and preserve css var() functions 1`] = ` +"[ + { + \\"type\\": 0, + \\"data\\": {} + }, + { + \\"type\\": 1, + \\"data\\": {} + }, + { + \\"type\\": 4, + \\"data\\": { + \\"href\\": \\"about:blank\\", + \\"width\\": 1920, + \\"height\\": 1080 + } + }, + { + \\"type\\": 2, + \\"data\\": { + \\"node\\": { + \\"type\\": 0, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"html\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"head\\", + \\"attributes\\": {}, + \\"childNodes\\": [], + \\"id\\": 3 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"body\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 5 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"script\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", + \\"id\\": 7 + } + ], + \\"id\\": 6 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", + \\"id\\": 8 + } + ], + \\"id\\": 4 + } + ], + \\"id\\": 2 + } + ], + \\"compatMode\\": \\"BackCompat\\", + \\"id\\": 1 + }, + \\"initialOffset\\": { + \\"left\\": 0, + \\"top\\": 0 + } + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [ + { + \\"id\\": 4, + \\"attributes\\": { + \\"style\\": \\"background: var(--mystery)\\" + } + } + ], + \\"removes\\": [], + \\"adds\\": [] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [ + { + \\"id\\": 4, + \\"attributes\\": { + \\"style\\": \\"background: var(--mystery); background-color: black\\" + } + } + ], + \\"removes\\": [], + \\"adds\\": [] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [ + { + \\"id\\": 4, + \\"attributes\\": { + \\"style\\": \\"\\" + } + } + ], + \\"removes\\": [], + \\"adds\\": [] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [ + { + \\"id\\": 4, + \\"attributes\\": { + \\"style\\": \\"display:block\\" + } + } + ], + \\"removes\\": [], + \\"adds\\": [] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [ + { + \\"id\\": 4, + \\"attributes\\": { + \\"style\\": { + \\"color\\": \\"var(--mystery-color)\\" + } + } + } + ], + \\"removes\\": [], + \\"adds\\": [] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [ + { + \\"id\\": 4, + \\"attributes\\": { + \\"style\\": \\"color:var(--mystery-color);display:block;margin:10px\\" + } + } + ], + \\"removes\\": [], + \\"adds\\": [] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [ + { + \\"id\\": 4, + \\"attributes\\": { + \\"style\\": { + \\"margin-left\\": \\"Npx\\" + } + } + } + ], + \\"removes\\": [], + \\"adds\\": [] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [ + { + \\"id\\": 4, + \\"attributes\\": { + \\"style\\": { + \\"margin-top\\": \\"Npx\\", + \\"color\\": false + } + } + } + ], + \\"removes\\": [], + \\"adds\\": [] + } + } +]" +`; + exports[`record integration tests can use maskInputOptions to configure which type of inputs should be masked 1`] = ` "[ { diff --git a/packages/rrweb/test/integration.test.ts b/packages/rrweb/test/integration.test.ts index 39e32dbcd6..b61f76ece5 100644 --- a/packages/rrweb/test/integration.test.ts +++ b/packages/rrweb/test/integration.test.ts @@ -209,6 +209,56 @@ describe('record integration tests', function (this: ISuite) { assertSnapshot(snapshots); }); + it('can record style changes compactly and preserve css var() functions', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent(getHtml.call(this, 'blank.html'), { + waitUntil: 'networkidle0', + }); + + // goal here is to ensure var(--mystery) ends up in the mutations (CSSOM fails in this case) + await page.evaluate( + 'document.body.setAttribute("style", "background: var(--mystery)")', + ); + await waitForRAF(page); + // and in this change we can't use the shorter styleObj format either + await page.evaluate( + 'document.body.setAttribute("style", "background: var(--mystery); background-color: black")', + ); + + // reset is always shorter to be recorded as a sting rather than a styleObj + await page.evaluate('document.body.setAttribute("style", "")'); + await waitForRAF(page); + + await page.evaluate('document.body.setAttribute("style", "display:block")'); + await waitForRAF(page); + // following should be recorded as an update of `{ color: 'var(--mystery-color)' }` without needing to include the display + await page.evaluate( + 'document.body.setAttribute("style", "color:var(--mystery-color);display:block")', + ); + await waitForRAF(page); + // whereas this case, it's shorter to record the entire string than the longhands for margin + await page.evaluate( + 'document.body.setAttribute("style", "color:var(--mystery-color);display:block;margin:10px")', + ); + await waitForRAF(page); + // and in this case, it's shorter to record just the change to the longhand margin-left; + await page.evaluate( + 'document.body.setAttribute("style", "color:var(--mystery-color);display:block;margin:10px 10px 10px 0px;")', + ); + await waitForRAF(page); + // see what happens when we manipulate the style object directly (expecting a compact mutation with just these two changes) + await page.evaluate( + 'document.body.style.marginTop = 0; document.body.style.color = null', + ); + await waitForRAF(page); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + it('can freeze mutations', async () => { const page: puppeteer.Page = await browser.newPage(); await page.goto('about:blank'); diff --git a/packages/rrweb/test/record/__snapshots__/cross-origin-iframes.test.ts.snap b/packages/rrweb/test/record/__snapshots__/cross-origin-iframes.test.ts.snap index 48d4bdb33a..5caabe69ee 100644 --- a/packages/rrweb/test/record/__snapshots__/cross-origin-iframes.test.ts.snap +++ b/packages/rrweb/test/record/__snapshots__/cross-origin-iframes.test.ts.snap @@ -2625,10 +2625,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = { \\"id\\": 9, \\"attributes\\": { - \\"style\\": { - \\"width\\": \\"Npx\\", - \\"height\\": \\"Npx\\" - } + \\"style\\": \\"width: Npx; height: Npx;\\" } } ], diff --git a/packages/rrweb/test/utils.ts b/packages/rrweb/test/utils.ts index dd5a8cf7cc..0d1e6400c6 100644 --- a/packages/rrweb/test/utils.ts +++ b/packages/rrweb/test/utils.ts @@ -133,23 +133,26 @@ function stringifySnapshots(snapshots: eventWithTime[]): string { s.data.source === IncrementalSource.Mutation ) { s.data.attributes.forEach((a) => { - if ( - 'style' in a.attributes && - a.attributes.style && - typeof a.attributes.style === 'object' - ) { - for (const [k, v] of Object.entries(a.attributes.style)) { - if (Array.isArray(v)) { - if (coordinatesReg.test(k + ': ' + v[0])) { - // TODO: could round the number here instead depending on what's coming out of various test envs - a.attributes.style[k] = ['Npx', v[1]]; - } - } else if (typeof v === 'string') { - if (coordinatesReg.test(k + ': ' + v)) { - a.attributes.style[k] = 'Npx'; + if ('style' in a.attributes && a.attributes.style) { + if (typeof a.attributes.style === 'object') { + for (const [k, v] of Object.entries(a.attributes.style)) { + if (Array.isArray(v)) { + if (coordinatesReg.test(k + ': ' + v[0])) { + // TODO: could round the number here instead depending on what's coming out of various test envs + a.attributes.style[k] = ['Npx', v[1]]; + } + } else if (typeof v === 'string') { + if (coordinatesReg.test(k + ': ' + v)) { + a.attributes.style[k] = 'Npx'; + } } + coordinatesReg.lastIndex = 0; // wow, a real wart in ECMAScript } - coordinatesReg.lastIndex = 0; // wow, a real wart in ECMAScript + } else if (coordinatesReg.test(a.attributes.style)) { + a.attributes.style = a.attributes.style.replace( + coordinatesReg, + '$1: Npx', + ); } } diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 6601457291..e6f6f15cd3 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -283,7 +283,7 @@ export type textMutation = { value: string | null; }; -export type styleAttributeValue = { +export type styleOMValue = { [key: string]: styleValueWithPriority | string | false; }; @@ -292,13 +292,15 @@ export type styleValueWithPriority = [string, string]; export type attributeCursor = { node: Node; attributes: { - [key: string]: string | styleAttributeValue | null; + [key: string]: string | styleOMValue | null; }; + styleDiff: styleOMValue; + _unchangedStyles: styleOMValue; }; export type attributeMutation = { id: number; attributes: { - [key: string]: string | styleAttributeValue | null; + [key: string]: string | styleOMValue | null; }; }; From 7103625b4683cbd75732ee03973e38f573847b1c Mon Sep 17 00:00:00 2001 From: Eoghan Murray Date: Thu, 3 Aug 2023 17:11:43 +0100 Subject: [PATCH 016/123] Mutation (attribute & text) duplicate info elimination (#1269) * Add a test which demonstrates how no mutations are generated when an element is created & destroyed in the same 'cycle' (a cylce here being enforced by freezePage) * Test demonstrating current behaviour I'm about to modify; the data-test="x" attribute is present twice in the mutation, as is the textContent value of 'y' * Attribute or text modifications on just-added nodes are redundant as demonstrated in test case * Some correct test changes from other tests; I've manually inspected each of these mutation removals and confirmed that the attribute values are already present in the newly added nodes elsewhere in the same mutation * Improve reliability of test case as per Justin's advice --- .changeset/attribute-text-reductions.md | 5 + packages/rrweb/src/record/mutation.ts | 6 + .../__snapshots__/integration.test.ts.snap | 43 +--- .../test/__snapshots__/record.test.ts.snap | 206 ++++++++++++++++++ packages/rrweb/test/record.test.ts | 87 ++++++++ 5 files changed, 305 insertions(+), 42 deletions(-) create mode 100644 .changeset/attribute-text-reductions.md diff --git a/.changeset/attribute-text-reductions.md b/.changeset/attribute-text-reductions.md new file mode 100644 index 0000000000..648e0d81b9 --- /dev/null +++ b/.changeset/attribute-text-reductions.md @@ -0,0 +1,5 @@ +--- +'rrweb': patch +--- + +Don't include redundant data from text/attribute mutations on just-added nodes diff --git a/packages/rrweb/src/record/mutation.ts b/packages/rrweb/src/record/mutation.ts index 0eea35c073..097d1a8fd5 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -265,6 +265,7 @@ export default class MutationBuffer { // so that the mirror for takeFullSnapshot doesn't get mutated while it's event is being processed const adds: addedNodeMutation[] = []; + const addedIds = new Set(); /** * Sometimes child node may be pushed before its newly added @@ -335,6 +336,7 @@ export default class MutationBuffer { nextId, node: sn, }); + addedIds.add(sn.id); } }; @@ -434,6 +436,8 @@ export default class MutationBuffer { id: this.mirror.getId(text.node), value: text.value, })) + // no need to include them on added elements, as they have just been serialized with up to date attribubtes + .filter((text) => !addedIds.has(text.id)) // text mutation's id was not in the mirror map means the target node has been removed .filter((text) => this.mirror.has(text.id)), attributes: this.attributes @@ -460,6 +464,8 @@ export default class MutationBuffer { attributes: attributes, }; }) + // no need to include them on added elements, as they have just been serialized with up to date attribubtes + .filter((attribute) => !addedIds.has(attribute.id)) // attribute mutation's id was not in the mirror map means the target node has been removed .filter((attribute) => this.mirror.has(attribute.id)), removes: this.removes, diff --git a/packages/rrweb/test/__snapshots__/integration.test.ts.snap b/packages/rrweb/test/__snapshots__/integration.test.ts.snap index 773d2351b4..fe33ef3c7d 100644 --- a/packages/rrweb/test/__snapshots__/integration.test.ts.snap +++ b/packages/rrweb/test/__snapshots__/integration.test.ts.snap @@ -566,12 +566,6 @@ exports[`record integration tests can freeze mutations 1`] = ` \\"source\\": 0, \\"texts\\": [], \\"attributes\\": [ - { - \\"id\\": 20, - \\"attributes\\": { - \\"foo\\": \\"bar\\" - } - }, { \\"id\\": 5, \\"attributes\\": { @@ -2929,38 +2923,11 @@ exports[`record integration tests can record node mutations 1`] = ` \\"class\\": \\"select2-container select2-dropdown-open select2-container-active\\" } }, - { - \\"id\\": 36, - \\"attributes\\": { - \\"id\\": \\"select2-drop\\", - \\"style\\": \\"left: Npx; width: Npx; top: Npx; bottom: auto; display: block;\\", - \\"class\\": \\"select2-drop select2-display-none select2-with-searchbox select2-drop-active\\" - } - }, - { - \\"id\\": 70, - \\"attributes\\": { - \\"style\\": \\"\\" - } - }, - { - \\"id\\": 42, - \\"attributes\\": { - \\"class\\": \\"select2-input select2-focused\\", - \\"aria-activedescendant\\": \\"select2-result-label-2\\" - } - }, { \\"id\\": 35, \\"attributes\\": { \\"disabled\\": \\"\\" } - }, - { - \\"id\\": 72, - \\"attributes\\": { - \\"class\\": \\"select2-results-dept-0 select2-result select2-result-selectable select2-highlighted\\" - } } ], \\"removes\\": [ @@ -4615,15 +4582,7 @@ exports[`record integration tests handles null attribute values 1`] = ` \\"data\\": { \\"source\\": 0, \\"texts\\": [], - \\"attributes\\": [ - { - \\"id\\": 20, - \\"attributes\\": { - \\"aria-label\\": \\"label\\", - \\"id\\": \\"test-li\\" - } - } - ], + \\"attributes\\": [], \\"removes\\": [], \\"adds\\": [ { diff --git a/packages/rrweb/test/__snapshots__/record.test.ts.snap b/packages/rrweb/test/__snapshots__/record.test.ts.snap index ad9b438600..cb40f3328d 100644 --- a/packages/rrweb/test/__snapshots__/record.test.ts.snap +++ b/packages/rrweb/test/__snapshots__/record.test.ts.snap @@ -1,5 +1,91 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`record aggregates mutations 1`] = ` +"[ + { + \\"type\\": 4, + \\"data\\": { + \\"href\\": \\"about:blank\\", + \\"width\\": 1920, + \\"height\\": 1080 + } + }, + { + \\"type\\": 2, + \\"data\\": { + \\"node\\": { + \\"type\\": 0, + \\"childNodes\\": [ + { + \\"type\\": 1, + \\"name\\": \\"html\\", + \\"publicId\\": \\"\\", + \\"systemId\\": \\"\\", + \\"id\\": 2 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"html\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"head\\", + \\"attributes\\": {}, + \\"childNodes\\": [], + \\"id\\": 4 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"body\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 6 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"text\\", + \\"size\\": \\"40\\" + }, + \\"childNodes\\": [], + \\"id\\": 7 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\\\n \\", + \\"id\\": 8 + } + ], + \\"id\\": 5 + } + ], + \\"id\\": 3 + } + ], + \\"id\\": 1 + }, + \\"initialOffset\\": { + \\"left\\": 0, + \\"top\\": 0 + } + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 2, + \\"id\\": 5 + } + } +]" +`; + exports[`record can add custom event 1`] = ` "[ { @@ -3349,6 +3435,126 @@ exports[`record loading stylesheets captures stylesheets that are still loading ]" `; +exports[`record no need for attribute mutations on adds 1`] = ` +"[ + { + \\"type\\": 4, + \\"data\\": { + \\"href\\": \\"about:blank\\", + \\"width\\": 1920, + \\"height\\": 1080 + } + }, + { + \\"type\\": 2, + \\"data\\": { + \\"node\\": { + \\"type\\": 0, + \\"childNodes\\": [ + { + \\"type\\": 1, + \\"name\\": \\"html\\", + \\"publicId\\": \\"\\", + \\"systemId\\": \\"\\", + \\"id\\": 2 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"html\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"head\\", + \\"attributes\\": {}, + \\"childNodes\\": [], + \\"id\\": 4 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"body\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 6 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"text\\", + \\"size\\": \\"40\\" + }, + \\"childNodes\\": [], + \\"id\\": 7 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\\\n \\", + \\"id\\": 8 + } + ], + \\"id\\": 5 + } + ], + \\"id\\": 3 + } + ], + \\"id\\": 1 + }, + \\"initialOffset\\": { + \\"left\\": 0, + \\"top\\": 0 + } + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [], + \\"removes\\": [], + \\"adds\\": [ + { + \\"parentId\\": 5, + \\"nextId\\": null, + \\"node\\": { + \\"type\\": 2, + \\"tagName\\": \\"div\\", + \\"attributes\\": { + \\"id\\": \\"here\\", + \\"data-test\\": \\"x\\" + }, + \\"childNodes\\": [], + \\"id\\": 9 + } + }, + { + \\"parentId\\": 9, + \\"nextId\\": null, + \\"node\\": { + \\"type\\": 3, + \\"textContent\\": \\"y\\", + \\"id\\": 10 + } + } + ] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 2, + \\"id\\": 5 + } + } +]" +`; + exports[`record should record scroll position 1`] = ` "[ { diff --git a/packages/rrweb/test/record.test.ts b/packages/rrweb/test/record.test.ts index 1a0a87421f..51e7ad2342 100644 --- a/packages/rrweb/test/record.test.ts +++ b/packages/rrweb/test/record.test.ts @@ -35,6 +35,7 @@ interface IWindow extends Window { takeFullSnapshot: (isCheckout?: boolean | undefined) => void; }; + freezePage(): void; addCustomEvent(tag: string, payload: T): void; }; emit: (e: eventWithTime) => undefined; @@ -651,6 +652,92 @@ describe('record', function (this: ISuite) { assertSnapshot(ctx.events); }); + it('aggregates mutations', async () => { + await ctx.page.evaluate(() => { + return new Promise((resolve) => { + const { record, freezePage } = (window as unknown as IWindow).rrweb; + record({ + emit: (window as unknown as IWindow).emit, + }); + freezePage(); + setTimeout(() => { + const div = document.createElement('div'); + div.setAttribute('id', 'here-and-gone'); + document.body.appendChild(div); + }, 0); + setTimeout(() => { + const div = document.getElementById('here-and-gone'); + if (div) { + div.setAttribute('data-test', 'x'); + } + }, 10); + setTimeout(() => { + const div = document.getElementById('here-and-gone'); + if (div) { + div.parentNode?.removeChild(div as HTMLElement); + } + }, 15); + setTimeout(() => { + // 'unfreeze' happens upon a user event + // however, we expect none of the above mutations to produce any effect + document.body.click(); + }, 20); + setTimeout(() => { + resolve(null); + }, 25); + }); + }); + await waitForRAF(ctx.page); // wait till events get sent + + const mutationEvents = ctx.events.filter( + (e) => + e.type === EventType.IncrementalSnapshot && + e.data.source === IncrementalSource.Mutation, + ); + expect(mutationEvents.length).toEqual(0); // there was no aggregate effect + + assertSnapshot(ctx.events); + }); + + it('no need for attribute mutations on adds', async () => { + await ctx.page.evaluate(() => { + const { record, freezePage } = (window as unknown as IWindow).rrweb; + record({ + emit: (window as unknown as IWindow).emit, + }); + freezePage(); + setTimeout(() => { + const div = document.createElement('div'); + div.setAttribute('id', 'here'); + div.innerText = 'as-created'; + div.setAttribute('data-test', 'as-created'); + document.body.appendChild(div); + }, 0); + setTimeout(() => { + const div = document.getElementById('here'); + if (div) { + div.setAttribute('data-test', 'x'); + (div.childNodes[0] as Text).replaceData(0, 'as-created'.length, 'y'); + } + }, 10); + setTimeout(() => { + // 'unfreeze' happens upon a user event + document.body.click(); + }, 20); + }); + await ctx.page.waitForTimeout(50); // wait till setTimeout is called + await waitForRAF(ctx.page); // wait till events get sent + + const mutationEvents = ctx.events.filter( + (e) => + e.type === EventType.IncrementalSnapshot && + e.data.source === IncrementalSource.Mutation, + ); + expect(mutationEvents.length).toEqual(1); + + assertSnapshot(ctx.events); + }); + describe('loading stylesheets', () => { let server: Server; let serverURL: string; From 36da39db366a9f80c28549771ed331090a1c6647 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Fri, 4 Aug 2023 04:30:03 -0400 Subject: [PATCH 017/123] feat: Add `ignoreSelector` option (#1262) * feat: Add `ignoreSelector` option Similar to `ignoreClass`, but accepts a CSS selector so that you can use any CSS selector. * Apply formatting changes * Create clean-shrimps-lay.md * Apply formatting changes --- .changeset/clean-shrimps-lay.md | 7 +++++++ guide.md | 1 + packages/rrweb/src/record/index.ts | 2 ++ packages/rrweb/src/record/observer.ts | 6 +++++- packages/rrweb/src/types.ts | 2 ++ packages/rrweb/test/html/ignore.html | 1 + packages/rrweb/test/integration.test.ts | 7 ++++++- packages/rrweb/test/utils.ts | 1 + 8 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 .changeset/clean-shrimps-lay.md diff --git a/.changeset/clean-shrimps-lay.md b/.changeset/clean-shrimps-lay.md new file mode 100644 index 0000000000..01c2d6b73b --- /dev/null +++ b/.changeset/clean-shrimps-lay.md @@ -0,0 +1,7 @@ +--- +'rrweb': patch +--- + +feat: Add `ignoreSelector` option + +Similar to ignoreClass, but accepts a CSS selector so that you can use any CSS selector. diff --git a/guide.md b/guide.md index e2dbf0d23f..d7807bf00d 100644 --- a/guide.md +++ b/guide.md @@ -143,6 +143,7 @@ The parameter of `rrweb.record` accepts the following options. | blockClass | 'rr-block' | Use a string or RegExp to configure which elements should be blocked, refer to the [privacy](#privacy) chapter | | blockSelector | null | Use a string to configure which selector should be blocked, refer to the [privacy](#privacy) chapter | | ignoreClass | 'rr-ignore' | Use a string or RegExp to configure which elements should be ignored, refer to the [privacy](#privacy) chapter | +| ignoreSelector | null | Use a string to configure which selector should be ignored, refer to the [privacy](#privacy) chapter | | ignoreCSSAttributes | null | array of CSS attributes that should be ignored | | maskTextClass | 'rr-mask' | Use a string or RegExp to configure which elements should be masked, refer to the [privacy](#privacy) chapter | | maskTextSelector | null | Use a string to configure which selector should be masked, refer to the [privacy](#privacy) chapter | diff --git a/packages/rrweb/src/record/index.ts b/packages/rrweb/src/record/index.ts index 563942312f..1c2141bfef 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -64,6 +64,7 @@ function record( blockClass = 'rr-block', blockSelector = null, ignoreClass = 'rr-ignore', + ignoreSelector = null, maskTextClass = 'rr-mask', maskTextSelector = null, inlineStylesheet = true, @@ -522,6 +523,7 @@ function record( }, blockClass, ignoreClass, + ignoreSelector, maskTextClass, maskTextSelector, maskInputOptions, diff --git a/packages/rrweb/src/record/observer.ts b/packages/rrweb/src/record/observer.ts index 9a02c4adcc..428cce1a4e 100644 --- a/packages/rrweb/src/record/observer.ts +++ b/packages/rrweb/src/record/observer.ts @@ -423,6 +423,7 @@ function initInputObserver({ blockClass, blockSelector, ignoreClass, + ignoreSelector, maskInputOptions, maskInputFn, sampling, @@ -449,7 +450,10 @@ function initInputObserver({ return; } - if (target.classList.contains(ignoreClass)) { + if ( + target.classList.contains(ignoreClass) || + (ignoreSelector && target.matches(ignoreSelector)) + ) { return; } let text = (target as HTMLInputElement).value; diff --git a/packages/rrweb/src/types.ts b/packages/rrweb/src/types.ts index dd9a516709..17ed750e68 100644 --- a/packages/rrweb/src/types.ts +++ b/packages/rrweb/src/types.ts @@ -46,6 +46,7 @@ export type recordOptions = { blockClass?: blockClass; blockSelector?: string; ignoreClass?: string; + ignoreSelector?: string; maskTextClass?: maskTextClass; maskTextSelector?: string; maskAllInputs?: boolean; @@ -84,6 +85,7 @@ export type observerParam = { blockClass: blockClass; blockSelector: string | null; ignoreClass: string; + ignoreSelector: string | null; maskTextClass: maskTextClass; maskTextSelector: string | null; maskInputOptions: MaskInputOptions; diff --git a/packages/rrweb/test/html/ignore.html b/packages/rrweb/test/html/ignore.html index f46c2efd00..2575bc20b0 100644 --- a/packages/rrweb/test/html/ignore.html +++ b/packages/rrweb/test/html/ignore.html @@ -10,6 +10,7 @@
+
diff --git a/packages/rrweb/test/integration.test.ts b/packages/rrweb/test/integration.test.ts index b61f76ece5..8496304d8d 100644 --- a/packages/rrweb/test/integration.test.ts +++ b/packages/rrweb/test/integration.test.ts @@ -298,9 +298,14 @@ describe('record integration tests', function (this: ISuite) { it('should not record input events on ignored elements', async () => { const page: puppeteer.Page = await browser.newPage(); await page.goto('about:blank'); - await page.setContent(getHtml.call(this, 'ignore.html')); + await page.setContent( + getHtml.call(this, 'ignore.html', { + ignoreSelector: '[data-rr-ignore]', + }), + ); await page.type('.rr-ignore', 'secret'); + await page.type('[data-rr-ignore]', 'secret'); const snapshots = (await page.evaluate( 'window.snapshots', diff --git a/packages/rrweb/test/utils.ts b/packages/rrweb/test/utils.ts index 0d1e6400c6..fb769135af 100644 --- a/packages/rrweb/test/utils.ts +++ b/packages/rrweb/test/utils.ts @@ -597,6 +597,7 @@ export function generateRecordSnippet(options: recordOptions) { emit: event => { window.snapshots.push(event); }, + ignoreSelector: ${options.ignoreSelector}, maskTextSelector: ${JSON.stringify(options.maskTextSelector)}, maskAllInputs: ${options.maskAllInputs}, maskInputOptions: ${JSON.stringify(options.maskAllInputs)}, From a3de582e9c32be9e0ccd84bb7df756af6b0594f7 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Fri, 4 Aug 2023 18:35:49 +0200 Subject: [PATCH 018/123] Canvas recording: Preserve drawing buffer (#1273) * Upgrade jest to 29 and puppeteer to 16 in rrweb * Apply formatting changes * Upgrade rrweb's puppeteer to v20 * Apply formatting changes * Canvas: Reduce flickering and capturing of empty canvas elements Turn on `preserveDrawingBuffer` by default for canvas FPS recording. Has some negative performance implications, but really helps when capturing canvas. * Apply formatting changes * Include all test image snapshots in ci * Apply formatting changes * Allow more flexibility when capturing hover * Apply formatting changes * Create tiny-chairs-build.md * Apply formatting changes * Update hover.test.ts * Apply formatting changes * Document snapshotFormat jest config * Freeze `yarn.lock` in ci for reproducible dependencies * Apply formatting changes * Apply formatting changes * Revert to old style of puppeteer evaluation script notation * Apply formatting changes * Make test less flaky * Apply formatting changes * Apply formatting changes * Make tests less flaky * Apply formatting changes * Make test more robust * Apply formatting changes * Apply formatting changes * Add debugging code for test * Apply formatting changes * Also test not ignored input * Apply formatting changes * Apply formatting changes * Apply formatting changes * escape ignoreSelector * Apply formatting changes * Apply formatting changes --- .changeset/tiny-chairs-build.md | 7 + .github/workflows/ci-cd.yml | 4 +- .github/workflows/release.yml | 4 +- .github/workflows/style-check.yml | 2 +- packages/rrweb/jest.config.js | 9 + packages/rrweb/package.json | 16 +- .../record/observers/canvas/canvas-manager.ts | 9 +- .../src/record/observers/canvas/canvas.ts | 24 +- packages/rrweb/src/replay/canvas/2d.ts | 79 +- packages/rrweb/src/replay/canvas/index.ts | 17 +- .../__snapshots__/integration.test.ts.snap | 206 ++- packages/rrweb/test/html/canvas.html | 1 + packages/rrweb/test/html/ignore.html | 11 +- packages/rrweb/test/integration.test.ts | 33 +- .../cross-origin-iframes.test.ts.snap | 62 +- .../rrweb/test/replay/2d-mutation.test.ts | 81 + ...uld-trigger-hover-on-mouse-down-1-snap.png | Bin 11774 -> 11597 bytes packages/rrweb/test/replay/hover.test.ts | 4 +- packages/rrweb/test/utils.ts | 101 +- yarn.lock | 1634 ++++++++++++++++- 20 files changed, 2103 insertions(+), 201 deletions(-) create mode 100644 .changeset/tiny-chairs-build.md create mode 100644 packages/rrweb/test/replay/2d-mutation.test.ts diff --git a/.changeset/tiny-chairs-build.md b/.changeset/tiny-chairs-build.md new file mode 100644 index 0000000000..0e76e26814 --- /dev/null +++ b/.changeset/tiny-chairs-build.md @@ -0,0 +1,7 @@ +--- +'rrweb': patch +--- + +Canvas FPS recording: override `preserveDrawingBuffer: true` on canvas creation. +Canvas replay: fix flickering canvas elemenrs. +Canvas FPS recording: fix bug that wipes webgl(2) canvas backgrounds while recording. diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index a1ad8e81cf..cf64ccca07 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -21,7 +21,7 @@ jobs: node-version: lts/* - name: Install Dependencies - run: yarn + run: yarn install --frozen-lockfile - name: Build Project run: NODE_OPTIONS='--max-old-space-size=4096' yarn build:all @@ -37,5 +37,5 @@ jobs: if: failure() with: name: image-diff - path: packages/rrweb/test/e2e/__image_snapshots__/__diff_output__/*.png + path: packages/rrweb/test/*/__image_snapshots__/__diff_output__/*.png if-no-files-found: ignore diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1e895be580..f870937fd3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: node-version: lts/* - name: Install Dependencies - run: yarn + run: yarn install --frozen-lockfile - name: Create Release Pull Request or Publish to npm id: changesets @@ -29,7 +29,7 @@ jobs: with: publish: yarn run release env: - NODE_OPTIONS: "--max-old-space-size=4096" + NODE_OPTIONS: '--max-old-space-size=4096' GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/style-check.yml b/.github/workflows/style-check.yml index 79320836dc..53748056f8 100644 --- a/.github/workflows/style-check.yml +++ b/.github/workflows/style-check.yml @@ -18,7 +18,7 @@ jobs: node-version: 16 cache: 'yarn' - name: Install Dependencies - run: yarn + run: yarn install --frozen-lockfile - name: Build Packages run: NODE_OPTIONS='--max-old-space-size=4096' yarn build:all - name: Eslint Check diff --git a/packages/rrweb/jest.config.js b/packages/rrweb/jest.config.js index 8ebc7349c3..1d88a78e2b 100644 --- a/packages/rrweb/jest.config.js +++ b/packages/rrweb/jest.config.js @@ -6,4 +6,13 @@ export default { moduleNameMapper: { '\\.css$': 'identity-obj-proxy', }, + /** + * Keeps old (pre-jest 29) snapshot format + * its a bit ugly and harder to read than the new format, + * so we might want to remove this in its own PR + */ + snapshotFormat: { + escapeString: true, + printBasicPrototype: true, + }, }; diff --git a/packages/rrweb/package.json b/packages/rrweb/package.json index 9b50b2fdb4..ebca356d79 100644 --- a/packages/rrweb/package.json +++ b/packages/rrweb/package.json @@ -53,11 +53,10 @@ "@types/chai": "^4.1.6", "@types/dom-mediacapture-transform": "^0.1.3", "@types/inquirer": "^8.2.1", - "@types/jest": "^27.4.1", - "@types/jest-image-snapshot": "^5.1.0", + "@types/jest": "^29.5.0", + "@types/jest-image-snapshot": "^6.1.0", "@types/node": "^18.15.11", "@types/offscreencanvas": "^2019.6.4", - "@types/puppeteer": "^5.4.4", "construct-style-sheets-polyfill": "^3.1.0", "cross-env": "^5.2.0", "esbuild": "^0.14.38", @@ -65,10 +64,11 @@ "identity-obj-proxy": "^3.0.0", "ignore-styles": "^5.0.1", "inquirer": "^9.0.0", - "jest": "^27.5.1", - "jest-image-snapshot": "^5.2.0", - "jest-snapshot": "^23.6.0", - "puppeteer": "^11.0.0", + "jest": "^29.6.0", + "jest-environment-jsdom": "^29.6.0", + "jest-image-snapshot": "^6.2.0", + "jest-snapshot": "^29.6.2", + "puppeteer": "^20.9.0", "rollup": "^2.68.0", "rollup-plugin-esbuild": "^4.9.1", "rollup-plugin-postcss": "^3.1.1", @@ -76,7 +76,7 @@ "rollup-plugin-typescript2": "^0.31.2", "rollup-plugin-web-worker-loader": "^1.6.1", "simple-peer-light": "^9.10.0", - "ts-jest": "^27.1.3", + "ts-jest": "^29.1.1", "ts-node": "^10.9.1", "tslib": "^2.3.1" }, diff --git a/packages/rrweb/src/record/observers/canvas/canvas-manager.ts b/packages/rrweb/src/record/observers/canvas/canvas-manager.ts index ad6781dd58..a8e06e468b 100644 --- a/packages/rrweb/src/record/observers/canvas/canvas-manager.ts +++ b/packages/rrweb/src/record/observers/canvas/canvas-manager.ts @@ -114,6 +114,7 @@ export class CanvasManager { win, blockClass, blockSelector, + true, ); const snapshotInProgressMap: Map = new Map(); const worker = @@ -198,9 +199,12 @@ export class CanvasManager { ) { // Hack to load canvas back into memory so `createImageBitmap` can grab it's contents. // Context: https://twitter.com/Juice10/status/1499775271758704643 - // This hack might change the background color of the canvas in the unlikely event that + // Preferably we set `preserveDrawingBuffer` to true, but that's not always possible, + // especially when canvas is loaded before rrweb. + // This hack can wipe the background color of the canvas in the (unlikely) event that // the canvas background was changed but clear was not called directly afterwards. - context?.clear(context.COLOR_BUFFER_BIT); + // Example of this hack having negative side effect: https://visgl.github.io/react-map-gl/examples/layers + context.clear(context.COLOR_BUFFER_BIT); } } const bitmap = await createImageBitmap(canvas); @@ -238,6 +242,7 @@ export class CanvasManager { win, blockClass, blockSelector, + false, ); const canvas2DReset = initCanvas2DMutationObserver( this.processMutation.bind(this), diff --git a/packages/rrweb/src/record/observers/canvas/canvas.ts b/packages/rrweb/src/record/observers/canvas/canvas.ts index 36408ec8cb..4ab79af2e4 100644 --- a/packages/rrweb/src/record/observers/canvas/canvas.ts +++ b/packages/rrweb/src/record/observers/canvas/canvas.ts @@ -2,10 +2,15 @@ import type { ICanvas } from 'rrweb-snapshot'; import type { blockClass, IWindow, listenerHandler } from '@rrweb/types'; import { isBlocked, patch } from '../../../utils'; +function getNormalizedContextName(contextType: string) { + return contextType === 'experimental-webgl' ? 'webgl' : contextType; +} + export default function initCanvasContextObserver( win: IWindow, blockClass: blockClass, blockSelector: string | null, + setPreserveDrawingBufferToTrue: boolean, ): listenerHandler { const handlers: listenerHandler[] = []; try { @@ -25,7 +30,24 @@ export default function initCanvasContextObserver( ...args: Array ) { if (!isBlocked(this, blockClass, blockSelector, true)) { - if (!('__context' in this)) this.__context = contextType; + const ctxName = getNormalizedContextName(contextType); + if (!('__context' in this)) this.__context = ctxName; + + if ( + setPreserveDrawingBufferToTrue && + ['webgl', 'webgl2'].includes(ctxName) + ) { + if (args[0] && typeof args[0] === 'object') { + const contextAttributes = args[0] as WebGLContextAttributes; + if (!contextAttributes.preserveDrawingBuffer) { + contextAttributes.preserveDrawingBuffer = true; + } + } else { + args.splice(0, 1, { + preserveDrawingBuffer: true, + }); + } + } } return original.apply(this, [contextType, ...args]); }; diff --git a/packages/rrweb/src/replay/canvas/2d.ts b/packages/rrweb/src/replay/canvas/2d.ts index f9fefba226..93d852399d 100644 --- a/packages/rrweb/src/replay/canvas/2d.ts +++ b/packages/rrweb/src/replay/canvas/2d.ts @@ -4,48 +4,63 @@ import { deserializeArg } from './deserialize-args'; export default async function canvasMutation({ event, - mutation, + mutations, target, imageMap, errorHandler, }: { event: Parameters[0]; - mutation: canvasMutationCommand; + mutations: canvasMutationCommand[]; target: HTMLCanvasElement; imageMap: Replayer['imageMap']; errorHandler: Replayer['warnCanvasMutationFailed']; }): Promise { - try { - const ctx = target.getContext('2d')!; + const ctx = target.getContext('2d'); - if (mutation.setter) { - // skip some read-only type checks - (ctx as unknown as Record)[mutation.property] = - mutation.args[0]; - return; - } - const original = ctx[ - mutation.property as Exclude - ] as (ctx: CanvasRenderingContext2D, args: unknown[]) => void; + if (!ctx) { + errorHandler(mutations[0], new Error('Canvas context is null')); + return; + } + + // step 1, deserialize args, they may be async + const mutationArgsPromises = mutations.map( + async (mutation: canvasMutationCommand): Promise => { + return Promise.all(mutation.args.map(deserializeArg(imageMap, ctx))); + }, + ); + const args = await Promise.all(mutationArgsPromises); + // step 2 apply all mutations + args.forEach((args, index) => { + const mutation = mutations[index]; + try { + if (mutation.setter) { + // skip some read-only type checks + (ctx as unknown as Record)[mutation.property] = + mutation.args[0]; + return; + } + const original = ctx[ + mutation.property as Exclude + ] as (ctx: CanvasRenderingContext2D, args: unknown[]) => void; - /** - * We have serialized the image source into base64 string during recording, - * which has been preloaded before replay. - * So we can get call drawImage SYNCHRONOUSLY which avoid some fragile cast. - */ - if ( - mutation.property === 'drawImage' && - typeof mutation.args[0] === 'string' - ) { - imageMap.get(event); - original.apply(ctx, mutation.args); - } else { - const args = await Promise.all( - mutation.args.map(deserializeArg(imageMap, ctx)), - ); - original.apply(ctx, args); + /** + * We have serialized the image source into base64 string during recording, + * which has been preloaded before replay. + * So we can get call drawImage SYNCHRONOUSLY which avoid some fragile cast. + */ + if ( + mutation.property === 'drawImage' && + typeof mutation.args[0] === 'string' + ) { + imageMap.get(event); + original.apply(ctx, mutation.args); + } else { + original.apply(ctx, args); + } + } catch (error) { + errorHandler(mutation, error); } - } catch (error) { - errorHandler(mutation, error); - } + + return; + }); } diff --git a/packages/rrweb/src/replay/canvas/index.ts b/packages/rrweb/src/replay/canvas/index.ts index 27cd165cd4..e4c346d6bc 100644 --- a/packages/rrweb/src/replay/canvas/index.ts +++ b/packages/rrweb/src/replay/canvas/index.ts @@ -46,16 +46,13 @@ export default async function canvasMutation({ return; } // default is '2d' for backwards compatibility (rrweb below 1.1.x) - for (let i = 0; i < commands.length; i++) { - const command = commands[i]; - await canvas2DMutation({ - event, - mutation: command, - target, - imageMap, - errorHandler, - }); - } + await canvas2DMutation({ + event, + mutations: commands, + target, + imageMap, + errorHandler, + }); } catch (error) { errorHandler(mutation, error); } diff --git a/packages/rrweb/test/__snapshots__/integration.test.ts.snap b/packages/rrweb/test/__snapshots__/integration.test.ts.snap index fe33ef3c7d..c95ec53a5f 100644 --- a/packages/rrweb/test/__snapshots__/integration.test.ts.snap +++ b/packages/rrweb/test/__snapshots__/integration.test.ts.snap @@ -8712,13 +8712,11 @@ exports[`record integration tests should not record input events on ignored elem { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"ignore text\\" - }, + \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\" \\", + \\"textContent\\": \\"Input ignored here: \\", \\"id\\": 21 }, { @@ -8733,7 +8731,7 @@ exports[`record integration tests should not record input events on ignored elem }, { \\"type\\": 3, - \\"textContent\\": \\" \\", + \\"textContent\\": \\"\\\\n \\", \\"id\\": 23 } ], @@ -8741,8 +8739,74 @@ exports[`record integration tests should not record input events on ignored elem }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", + \\"textContent\\": \\"\\\\n \\", \\"id\\": 24 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"Input ignored by selector here: \\", + \\"id\\": 26 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"text\\", + \\"data-rr-ignore\\": \\"\\" + }, + \\"childNodes\\": [], + \\"id\\": 27 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 28 + } + ], + \\"id\\": 25 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 29 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"Input not ignored here: \\", + \\"id\\": 31 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"text\\", + \\"class\\": \\"dont-ignore\\" + }, + \\"childNodes\\": [], + \\"id\\": 32 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 33 + } + ], + \\"id\\": 30 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 34 } ], \\"id\\": 18 @@ -8750,7 +8814,7 @@ exports[`record integration tests should not record input events on ignored elem { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\", - \\"id\\": 25 + \\"id\\": 35 }, { \\"type\\": 2, @@ -8760,15 +8824,15 @@ exports[`record integration tests should not record input events on ignored elem { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 27 + \\"id\\": 37 } ], - \\"id\\": 26 + \\"id\\": 36 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 28 + \\"id\\": 38 } ], \\"id\\": 16 @@ -8792,6 +8856,128 @@ exports[`record integration tests should not record input events on ignored elem \\"type\\": 5, \\"id\\": 22 } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 6, + \\"id\\": 22 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 27 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 6, + \\"id\\": 27 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 32 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"n\\", + \\"isChecked\\": false, + \\"id\\": 32 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"no\\", + \\"isChecked\\": false, + \\"id\\": 32 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"not\\", + \\"isChecked\\": false, + \\"id\\": 32 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"not \\", + \\"isChecked\\": false, + \\"id\\": 32 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"not s\\", + \\"isChecked\\": false, + \\"id\\": 32 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"not se\\", + \\"isChecked\\": false, + \\"id\\": 32 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"not sec\\", + \\"isChecked\\": false, + \\"id\\": 32 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"not secr\\", + \\"isChecked\\": false, + \\"id\\": 32 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"not secre\\", + \\"isChecked\\": false, + \\"id\\": 32 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"not secret\\", + \\"isChecked\\": false, + \\"id\\": 32 + } } ]" `; diff --git a/packages/rrweb/test/html/canvas.html b/packages/rrweb/test/html/canvas.html index 3aac8d8085..be07d8fd39 100644 --- a/packages/rrweb/test/html/canvas.html +++ b/packages/rrweb/test/html/canvas.html @@ -28,6 +28,7 @@ ctx.moveTo(0, 0); ctx.lineTo(200, 100); ctx.stroke(); + window.canvasMutationApplied = true; }, 10); diff --git a/packages/rrweb/test/html/ignore.html b/packages/rrweb/test/html/ignore.html index 2575bc20b0..bb057c681d 100644 --- a/packages/rrweb/test/html/ignore.html +++ b/packages/rrweb/test/html/ignore.html @@ -9,8 +9,15 @@
- - + + +
diff --git a/packages/rrweb/test/integration.test.ts b/packages/rrweb/test/integration.test.ts index 8496304d8d..edfc8a97af 100644 --- a/packages/rrweb/test/integration.test.ts +++ b/packages/rrweb/test/integration.test.ts @@ -7,6 +7,7 @@ import { getServerURL, launchPuppeteer, waitForRAF, + waitForIFrameLoad, replaceLast, generateRecordSnippet, ISuite, @@ -71,7 +72,7 @@ describe('record integration tests', function (this: ISuite) { // also tap on the span const span = await page.waitForSelector('span'); const center = await page.evaluate((el) => { - const { x, y, width, height } = el.getBoundingClientRect(); + const { x, y, width, height } = el!.getBoundingClientRect(); return { x: Math.round(x + width / 2), y: Math.round(y + height / 2), @@ -81,7 +82,9 @@ describe('record integration tests', function (this: ISuite) { await page.click('a'); - const snapshots = await page.evaluate('window.snapshots'); + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; assertSnapshot(snapshots); }); @@ -186,7 +189,9 @@ describe('record integration tests', function (this: ISuite) { li.removeAttribute('aria-label'); }); - const snapshots = await page.evaluate('window.snapshots'); + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; assertSnapshot(snapshots); }); @@ -306,11 +311,9 @@ describe('record integration tests', function (this: ISuite) { await page.type('.rr-ignore', 'secret'); await page.type('[data-rr-ignore]', 'secret'); + await page.type('.dont-ignore', 'not secret'); - const snapshots = (await page.evaluate( - 'window.snapshots', - )) as eventWithTime[]; - assertSnapshot(snapshots); + await assertSnapshot(page); }); it('should not record input values if maskAllInputs is enabled', async () => { @@ -547,6 +550,7 @@ describe('record integration tests', function (this: ISuite) { recordCanvas: true, }), ); + await page.waitForFunction('window.canvasMutationApplied'); await waitForRAF(page); const snapshots = (await page.evaluate( 'window.snapshots', @@ -581,10 +585,7 @@ describe('record integration tests', function (this: ISuite) { await page.type('#input', 'moo'); - const snapshots = (await page.evaluate( - 'window.snapshots', - )) as eventWithTime[]; - assertSnapshot(snapshots); + await assertSnapshot(page); }); it('should record webgl canvas mutations', async () => { @@ -757,13 +758,9 @@ describe('record integration tests', function (this: ISuite) { await page.goto(`${serverURL}/html`); await page.setContent(getHtml.call(this, 'main.html')); - await page.waitForSelector('#two'); - const frameIdTwo = await page.frames()[2]; - await frameIdTwo.waitForSelector('#four'); - const frameIdFour = frameIdTwo.childFrames()[1]; - await frameIdFour.waitForSelector('#five'); - - await page.waitForTimeout(50); + const frameIdTwo = await waitForIFrameLoad(page, '#two'); + const frameIdFour = await waitForIFrameLoad(frameIdTwo, '#four'); + await waitForIFrameLoad(frameIdFour, '#five'); const snapshots = (await page.evaluate( 'window.snapshots', diff --git a/packages/rrweb/test/record/__snapshots__/cross-origin-iframes.test.ts.snap b/packages/rrweb/test/record/__snapshots__/cross-origin-iframes.test.ts.snap index 5caabe69ee..07d4f53363 100644 --- a/packages/rrweb/test/record/__snapshots__/cross-origin-iframes.test.ts.snap +++ b/packages/rrweb/test/record/__snapshots__/cross-origin-iframes.test.ts.snap @@ -37,7 +37,7 @@ exports[`cross origin iframes audio.html should emit contents of iframe once 1`] \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -202,7 +202,7 @@ exports[`cross origin iframes audio.html should emit contents of iframe once 1`] \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -370,7 +370,7 @@ exports[`cross origin iframes blank.html should filter out forwarded cross origi \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -448,7 +448,7 @@ exports[`cross origin iframes blank.html should filter out forwarded cross origi \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -544,7 +544,7 @@ exports[`cross origin iframes blank.html should filter out forwarded cross origi \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -632,7 +632,7 @@ exports[`cross origin iframes blank.html should record same-origin iframe in cro \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -710,7 +710,7 @@ exports[`cross origin iframes blank.html should record same-origin iframe in cro \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -877,7 +877,7 @@ exports[`cross origin iframes blank.html should support packFn option in record( \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -956,7 +956,7 @@ exports[`cross origin iframes blank.html should support packFn option in record( \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -1045,7 +1045,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -1211,7 +1211,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -2042,7 +2042,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -2208,7 +2208,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -2682,7 +2682,7 @@ exports[`cross origin iframes move-node.html captures mutations on adopted style \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -2768,7 +2768,7 @@ exports[`cross origin iframes move-node.html captures mutations on adopted style \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -3096,7 +3096,7 @@ exports[`cross origin iframes move-node.html captures mutations on stylesheets 1 \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -3182,7 +3182,7 @@ exports[`cross origin iframes move-node.html captures mutations on stylesheets 1 \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -3515,7 +3515,7 @@ exports[`cross origin iframes move-node.html should record DOM attribute changes \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -3601,7 +3601,7 @@ exports[`cross origin iframes move-node.html should record DOM attribute changes \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -3803,7 +3803,7 @@ exports[`cross origin iframes move-node.html should record DOM node movement 1`] \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -3889,7 +3889,7 @@ exports[`cross origin iframes move-node.html should record DOM node movement 1`] \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -4188,7 +4188,7 @@ exports[`cross origin iframes move-node.html should record DOM node removal 1`] \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -4274,7 +4274,7 @@ exports[`cross origin iframes move-node.html should record DOM node removal 1`] \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -4474,7 +4474,7 @@ exports[`cross origin iframes move-node.html should record DOM text changes 1`] \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -4560,7 +4560,7 @@ exports[`cross origin iframes move-node.html should record DOM text changes 1`] \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -4760,7 +4760,7 @@ exports[`cross origin iframes move-node.html should record canvas elements 1`] = \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -4846,7 +4846,7 @@ exports[`cross origin iframes move-node.html should record canvas elements 1`] = \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -5083,7 +5083,7 @@ exports[`cross origin iframes move-node.html should record custom events 1`] = ` \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -5169,7 +5169,7 @@ exports[`cross origin iframes move-node.html should record custom events 1`] = ` \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -5365,7 +5365,7 @@ exports[`same origin iframes should emit contents of iframe once 1`] = ` \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [ { @@ -5479,7 +5479,7 @@ exports[`same origin iframes should emit contents of iframe once 1`] = ` \\"type\\": 2, \\"tagName\\": \\"script\\", \\"attributes\\": { - \\"type\\": \\"\\" + \\"type\\": \\"text/javascript\\" }, \\"childNodes\\": [], \\"rootId\\": 11, diff --git a/packages/rrweb/test/replay/2d-mutation.test.ts b/packages/rrweb/test/replay/2d-mutation.test.ts new file mode 100644 index 0000000000..1ff0b10af9 --- /dev/null +++ b/packages/rrweb/test/replay/2d-mutation.test.ts @@ -0,0 +1,81 @@ +/** + * @jest-environment jsdom + */ + +import { polyfillWebGLGlobals } from '../utils'; +polyfillWebGLGlobals(); + +import canvas2DMutation from '../../src/replay/canvas/2d'; +import type { Replayer } from '../../src/replay'; + +let canvas: HTMLCanvasElement; +describe('canvas2DMutation', () => { + beforeEach(() => { + jest.useFakeTimers(); + canvas = document.createElement('canvas'); + }); + afterEach(() => { + jest.clearAllMocks(); + jest.useRealTimers(); + }); + + it('should execute all mutations after args are parsed', async () => { + let resolve: (value: unknown) => void; + const promise = new Promise((r) => { + resolve = r; + }); + const context = { + clearRect: jest.fn(), + drawImage: jest.fn(), + } as unknown as CanvasRenderingContext2D; + jest.spyOn(canvas, 'getContext').mockImplementation(() => { + return context; + }); + + const createImageBitmapMock = jest.fn(() => { + return new Promise((r) => { + setTimeout(r, 1000); + }); + }); + + (global as any).createImageBitmap = createImageBitmapMock; + + const mutation = canvas2DMutation({ + event: {} as Parameters[0], + mutations: [ + { + property: 'clearRect', + args: [0, 0, 1000, 1000], + }, + { + property: 'drawImage', + args: [ + { + rr_type: 'ImageBitmap', + args: [], + }, + 0, + 0, + ], + }, + ], + target: canvas, + imageMap: new Map(), + errorHandler: () => {}, + }); + + await jest.advanceTimersByTimeAsync(100); + + await expect(createImageBitmapMock).toHaveBeenCalled(); + + expect(context.clearRect).not.toBeCalled(); + expect(context.drawImage).not.toBeCalled(); + + await jest.advanceTimersByTimeAsync(1000); + + await mutation; + + expect(context.clearRect).toHaveBeenCalledWith(0, 0, 1000, 1000); + expect(context.drawImage).toHaveBeenCalled(); + }); +}); diff --git a/packages/rrweb/test/replay/__image_snapshots__/hover-test-ts-replayer-hover-should-trigger-hover-on-mouse-down-1-snap.png b/packages/rrweb/test/replay/__image_snapshots__/hover-test-ts-replayer-hover-should-trigger-hover-on-mouse-down-1-snap.png index 4142d17a7fdf077bec94553adcd307f87ef00652..7d7faa8104cc2f3bf5c6260601b4d4e31a395700 100644 GIT binary patch delta 1526 zcmX|BZBP?e6y1=3ND#1$5>(8fs2vJ~G)SlrQblSRJ2DoBQoxXwL5d2&I+AD-mX@(! z25`(2OOeou3`J3B7ZEfxK{P3q00l&Wgam^Dq$ETMS;$uxckTPJ^Y-3z?z#88x9iMM zrC;0w_Fvd?EKqLd<|IG^ck5fqTKQ=|tiSskFOR}#?F{9mQW%!2?k>Pr;gTm<21}=| z1?(j}%y_nYB0cX{_nyzTUnAyK9{IWbyd|I__0}H~Dd--MpY)UifH-ke^x+39r9M*2NXDzDD3Bdo#N{dvQaW2_b_2)muVcTa zuyf{(#&V5Dlh}-lr1?s5ah8?2W@aw~Eod;-Rm7(+dI7ZO9^$S|3A>y6j}MHEjWvBh zO+Z?>z`~)ppTt$}I;tY(9H(*!25&NCGwaYq$=R2LDDm%sAAxfhSnT62Ha}BlUW8$T zA;!MANXiza%+Zzl2496ZSrF3}ZQUphMv3ye{7D>d6+g<1EeI+QOhO>JKy>2U&HAyj z=CXHexk@O5?Ae8)0c*%{V6U?Vu@A%N2ruUGi+RXz^wRfxW3zp5v%u5i4t< zP{mXj8Y#)4TLD3)Ny=1kT&*+VZ>UP7Sfiy{8E>=tDqv^Du3)%;3WvNY{lc)dgv=Bc zHl5b4D5m|G?niXBzw9#9}tv+Qeqefhj1%bs+BxJq1Iy+MuRk{Onys~$n z+X5mN^J@5cb}iCdzthp1a#@Lla*MeLvwWi3E-(+ylimn~8k~g1;l3)al9Zj<*>+lc zx)$_UK{zfe$E2VQpnb@%r~kE1*H}X{l}}5~^5cqLh(W%j>Km={knmjz-!N}eXd7o$ zSyU2=PuoGfhl{&?yMvBgL4~txsl8Y~Yc{J?r{LLHs)E!o!YNlKlSQ@8neJ1Lu?e{E z2{|s=j`^GV_&$DNIEtWEjm}e9!hF#uEUC-e9Dvo%Aqw4Au7MG(yRKZ&Q4M2WH{GgV zD`&cTNHX}bhIx;d_hl^nJYXmNJmyX6KZ67vpWzZ1RY{8st6^%X*%Nc2={iD9;l|?` zjy`Rj)oHUs|EF5&z2vKzGTD&H-dV^ZV3!h19sk%}H%l9+t&pW`i^R_B@5)f1g4*F8 zrwGuShNrhLknWUH(cJr^D^~+z8j)Fq{xB=zO0C*1wA}6q*YO{Ijv`7f)f45)Gm~~w z0EH2=5&OW7glYT-b_F}#P|%H#ppw;zR=rC79{P&JblWipZE0Jwhc#f67QRIz%8|bb zv-<01;zubfr%Sg6UwGBG# zMfdcE^kgpp@U|uG-+KgFPfYWOdS+48RdtM{Cvz|%om@%ORdpOQ1Z1Gi0WpQ9POIzy z_Ey+OhNyv$2v7;>AkNRU^zZwt=CLozEQ~(~zZ0Jc-@kznYW2q#9W^*sDM^Wk_TSpa G{`x;!i;$WC delta 1766 zcmYLIYfuwc6yER*Dj>BMTV6h@!3t6)N>B;Wg0<8sv}1knkl-kZHXu555X@skl>wwy zZHD3sBsz?PS`EPzA@WENi)~5RIx5geOau+eBbyjV2;|X?ySC@YoxS(_&iTGQ=U!EY zGxPjrF!slAeY(Q*pxQrfV@pHE@zo)+8y}4elc%nGaMWr0)ncqoe%a2_W9tk z-+|b;MFFhx_w}EjUc3A5vK3_&Uo8D4Z$;+d#fI2sPERZ+G$o_4NDW&x4#b+7s^ub` z)=97vVdt>W0I(P`C$@|e-hO)lz`g*%wgsENj-S2e9V55DNmXKq{FjvtyZfuW{4P15s;n%2%&%GT5}D(O%sZmy;MvUkO;B}{(^6Oc7pf2cLz%H zxucJVxyWnT3D;2G(QqLIC6ycChdm*M_E+_rj!zDpA)&wEjv>vSaQ+}A6;{o}^q*3# zk{dPXYBuOElvtUf+S&jc#A73ImCM-qC;%!ITa)* zpg#W-#EBMRbtl1|GJ=$Ay4Z}P!`W<)CAing{B?eciI7I{>TLUzMMIW$9sjQKKah)p zltFphX{s>&-p6>guq|&*s@w)GiGgwF;=LDPkZ}bHAzjvK@$f?T396sd^wb1!5NGp# zSujRYWVenIiVMv~oP=}iZO$1jGkgA_veT75^G=K1(_QZ@FAva&d~0`v%MAT#Ox|p- zlGYJtF4ID`Q-x$XXb84?V5M^oJV*l~s2!$#6GAGb5CI*K++l`jcC|8Okm;OmVmJ-+ zRq^%|3!X3(SY-Dyni@{%H6pIz!bGAYlT44Nngz90qMDd!o~r?bY|mWVbz?EZ5Y5@E zG{Fhaui&k-@WW^X&dAU$+u0<9HlSw0uzi$8v$hwKLDMZr?v#SoF-oB3(!v^s&}A99 zaTs&ScjP_rG%DSrOc=P!griddnzE+9gIq(uD07Z0wONp@k;3e!(ab7DnFX>ddvLpx zLFhb4KWQ!r(lo_4TjbXEDwc>g`C=DEf4@1?<+7O@8RG2p`?{UMOmWxk3b1=Hd%ylM zCJVGb{n7)KbzhA=Ue1OlmECwYFj2%A@2%Tp8+ag=8=pWdZT%*&=)+y_1jBsy+F-bj z!%E~9A3Q3ik<2;>oCzptxWY#%ZA39(lO*9ari(qIk1avQ`<-`o#;W$^vdaq5V$wbkW>nA5-U5p^thVl9`j2;_CG0RaD-DaqTum6{^W zp3=*a!JZqCf^d~`;;xupfcw)aro4^H4u-xm8ZQyLkBvBxAbeM6_C*W!xYI*Cg3U+Z wfJ1J?$CjxbU3V5E@deXS$$rF~|97ONM9*q+Vp*gk)qR+i_@% diff --git a/packages/rrweb/test/replay/hover.test.ts b/packages/rrweb/test/replay/hover.test.ts index d4cdec897e..c9ace0893a 100644 --- a/packages/rrweb/test/replay/hover.test.ts +++ b/packages/rrweb/test/replay/hover.test.ts @@ -65,7 +65,9 @@ describe('replayer', function () { await waitForRAF(page); const image = await page.screenshot(); - expect(image).toMatchImageSnapshot(); + expect(image).toMatchImageSnapshot({ + failureThreshold: 40, + }); }); }); }); diff --git a/packages/rrweb/test/utils.ts b/packages/rrweb/test/utils.ts index fb769135af..5a90f62031 100644 --- a/packages/rrweb/test/utils.ts +++ b/packages/rrweb/test/utils.ts @@ -7,6 +7,7 @@ import { Optional, mouseInteractionData, event, + pluginEvent, } from '@rrweb/types'; import type { recordOptions } from '../src/types'; import * as puppeteer from 'puppeteer'; @@ -20,7 +21,7 @@ export async function launchPuppeteer( options?: Parameters<(typeof puppeteer)['launch']>[0], ) { return await puppeteer.launch({ - headless: process.env.PUPPETEER_HEADLESS ? true : false, + headless: process.env.PUPPETEER_HEADLESS ? 'new' : false, defaultViewport: { width: 1920, height: 1080, @@ -108,7 +109,8 @@ function stringifySnapshots(snapshots: eventWithTime[]): string { .filter((s) => { if ( s.type === EventType.IncrementalSnapshot && - s.data.source === IncrementalSource.MouseMove + (s.data.source === IncrementalSource.MouseMove || + s.data.source === IncrementalSource.ViewportResize) ) { return false; } @@ -195,6 +197,33 @@ function stringifySnapshots(snapshots: eventWithTime[]): string { if (s.data.currentTime) { s.data.currentTime = Math.round(s.data.currentTime * 10) / 10; } + } else if ( + s.type === EventType.Plugin && + s.data.plugin === 'rrweb/console@1' + ) { + const pluginPayload = ( + s as pluginEvent<{ + trace: string[]; + payload: string[]; + }> + ).data.payload; + + if (pluginPayload?.trace.length) { + pluginPayload.trace = pluginPayload.trace.map((trace) => { + return trace.replace( + /^pptr:evaluate;.*?:(\d+:\d+)/, + '__puppeteer_evaluation_script__:$1', + ); + }); + } + if (pluginPayload?.payload.length) { + pluginPayload.payload = pluginPayload.payload.map((payload) => { + return payload.replace( + /pptr:evaluate;.*?:(\d+:\d+)/g, + '__puppeteer_evaluation_script__:$1', + ); + }); + } } delete (s as Optional).timestamp; return s as event; @@ -260,7 +289,24 @@ function stringifyDomSnapshot(mhtml: string): string { return newResult.map((asset) => Object.values(asset).join('\n')).join('\n\n'); } -export function assertSnapshot(snapshots: eventWithTime[]) { +export async function assertSnapshot( + snapshotsOrPage: eventWithTime[] | puppeteer.Page, +) { + let snapshots: eventWithTime[]; + if (!Array.isArray(snapshotsOrPage)) { + // make sure page has finished executing js + await waitForRAF(snapshotsOrPage); + await snapshotsOrPage.waitForFunction( + 'window.snapshots && window.snapshots.length > 0', + ); + + snapshots = (await snapshotsOrPage.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + } else { + snapshots = snapshotsOrPage; + } + expect(snapshots).toBeDefined(); expect(stringifySnapshots(snapshots)).toMatchSnapshot(); } @@ -590,14 +636,59 @@ export async function waitForRAF( }); } +export async function waitForIFrameLoad( + page: puppeteer.Frame | puppeteer.Page, + iframeSelector: string, + timeout = 10000, +): Promise { + const el = await page.waitForSelector(iframeSelector); + if (!el) + throw new Error('Waiting for iframe load has timed out - no element found'); + + let frame = await el.contentFrame(); + if (frame && frame.isDetached()) { + throw new Error( + 'Waiting for iframe load has timed out - frame is detached', + ); + } + if (frame && frame.url() !== '') { + return frame; + } + + await page.$eval( + iframeSelector, + (el, timeout) => { + const p = new Promise((resolve, reject) => { + (el as HTMLIFrameElement).onload = () => { + resolve(el as HTMLIFrameElement); + }; + setTimeout(() => { + reject( + new Error( + 'Waiting for iframe load has timed out - onload not fired', + ), + ); + }, timeout); + }); + return p; + }, + timeout, + ); + + frame = await el.contentFrame(); + if (!frame) + throw new Error('Waiting for iframe load has timed out - no frame found'); + return frame; +} + export function generateRecordSnippet(options: recordOptions) { return ` - window.snapshots = []; rrweb.record({ emit: event => { + if (!window.snapshots) window.snapshots = []; window.snapshots.push(event); }, - ignoreSelector: ${options.ignoreSelector}, + ignoreSelector: ${JSON.stringify(options.ignoreSelector)}, maskTextSelector: ${JSON.stringify(options.maskTextSelector)}, maskAllInputs: ${options.maskAllInputs}, maskInputOptions: ${JSON.stringify(options.maskAllInputs)}, diff --git a/yarn.lock b/yarn.lock index a3e1e00c82..f579e11c04 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10,6 +10,14 @@ "@jridgewell/gen-mapping" "^0.1.0" "@jridgewell/trace-mapping" "^0.3.9" +"@ampproject/remapping@^2.2.0": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.0.0-beta.35", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz" @@ -31,6 +39,13 @@ dependencies: "@babel/highlight" "^7.18.6" +"@babel/code-frame@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.5.tgz#234d98e1551960604f1246e6475891a570ad5658" + integrity sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ== + dependencies: + "@babel/highlight" "^7.22.5" + "@babel/compat-data@^7.15.0": version "7.15.0" resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz" @@ -46,6 +61,11 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.19.4.tgz#95c86de137bf0317f3a570e1b6e996b427299747" integrity sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw== +"@babel/compat-data@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730" + integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ== + "@babel/core@^7.1.0", "@babel/core@^7.7.2", "@babel/core@^7.7.5", "@babel/core@^7.8.0": version "7.15.5" resolved "https://registry.npmjs.org/@babel/core/-/core-7.15.5.tgz" @@ -67,6 +87,27 @@ semver "^6.3.0" source-map "^0.5.0" +"@babel/core@^7.11.6": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.9.tgz#bd96492c68822198f33e8a256061da3cf391f58f" + integrity sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.22.5" + "@babel/generator" "^7.22.9" + "@babel/helper-compilation-targets" "^7.22.9" + "@babel/helper-module-transforms" "^7.22.9" + "@babel/helpers" "^7.22.6" + "@babel/parser" "^7.22.7" + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.8" + "@babel/types" "^7.22.5" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.2" + semver "^6.3.1" + "@babel/core@^7.12.3": version "7.16.7" resolved "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz" @@ -136,6 +177,16 @@ "@jridgewell/gen-mapping" "^0.3.2" jsesc "^2.5.1" +"@babel/generator@^7.22.7", "@babel/generator@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.9.tgz#572ecfa7a31002fa1de2a9d91621fd895da8493d" + integrity sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw== + dependencies: + "@babel/types" "^7.22.5" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + "@babel/helper-annotate-as-pure@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" @@ -173,6 +224,17 @@ browserslist "^4.21.3" semver "^6.3.0" +"@babel/helper-compilation-targets@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz#f9d0a7aaaa7cd32a3f31c9316a69f5a9bcacb892" + integrity sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw== + dependencies: + "@babel/compat-data" "^7.22.9" + "@babel/helper-validator-option" "^7.22.5" + browserslist "^4.21.9" + lru-cache "^5.1.1" + semver "^6.3.1" + "@babel/helper-environment-visitor@^7.16.7": version "7.16.7" resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz" @@ -185,6 +247,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== +"@babel/helper-environment-visitor@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98" + integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q== + "@babel/helper-function-name@^7.15.4": version "7.15.4" resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz" @@ -211,6 +278,14 @@ "@babel/template" "^7.18.10" "@babel/types" "^7.19.0" +"@babel/helper-function-name@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be" + integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ== + dependencies: + "@babel/template" "^7.22.5" + "@babel/types" "^7.22.5" + "@babel/helper-get-function-arity@^7.15.4": version "7.15.4" resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz" @@ -246,6 +321,13 @@ dependencies: "@babel/types" "^7.18.6" +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + "@babel/helper-member-expression-to-functions@^7.15.4": version "7.15.4" resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz" @@ -274,6 +356,13 @@ dependencies: "@babel/types" "^7.18.6" +"@babel/helper-module-imports@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz#1a8f4c9f4027d23f520bd76b364d44434a72660c" + integrity sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg== + dependencies: + "@babel/types" "^7.22.5" + "@babel/helper-module-transforms@^7.15.4": version "7.15.7" resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.7.tgz" @@ -316,6 +405,17 @@ "@babel/traverse" "^7.19.0" "@babel/types" "^7.19.0" +"@babel/helper-module-transforms@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz#92dfcb1fbbb2bc62529024f72d942a8c97142129" + integrity sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.5" + "@babel/helper-optimise-call-expression@^7.15.4": version "7.15.4" resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz" @@ -333,6 +433,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz#4796bb14961521f0f8715990bee2fb6e51ce21bf" integrity sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw== +"@babel/helper-plugin-utils@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" + integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== + "@babel/helper-replace-supers@^7.15.4": version "7.15.4" resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz" @@ -364,6 +469,13 @@ dependencies: "@babel/types" "^7.19.4" +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== + dependencies: + "@babel/types" "^7.22.5" + "@babel/helper-split-export-declaration@^7.15.4": version "7.15.4" resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz" @@ -385,11 +497,23 @@ dependencies: "@babel/types" "^7.18.6" +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + "@babel/helper-string-parser@^7.19.4": version "7.19.4" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63" integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== +"@babel/helper-string-parser@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" + integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== + "@babel/helper-validator-identifier@^7.14.5": version "7.14.8" resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.8.tgz" @@ -410,6 +534,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== +"@babel/helper-validator-identifier@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193" + integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== + "@babel/helper-validator-option@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz" @@ -425,6 +554,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== +"@babel/helper-validator-option@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac" + integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw== + "@babel/helpers@^7.15.4": version "7.15.4" resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.4.tgz" @@ -452,6 +586,15 @@ "@babel/traverse" "^7.19.4" "@babel/types" "^7.19.4" +"@babel/helpers@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.6.tgz#8e61d3395a4f0c5a8060f309fb008200969b5ecd" + integrity sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA== + dependencies: + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.6" + "@babel/types" "^7.22.5" + "@babel/highlight@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz" @@ -479,6 +622,15 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/highlight@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.5.tgz#aa6c05c5407a67ebce408162b7ede789b4d22031" + integrity sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw== + dependencies: + "@babel/helper-validator-identifier" "^7.22.5" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/parser@^7.1.0", "@babel/parser@^7.15.4", "@babel/parser@^7.15.5", "@babel/parser@^7.7.2": version "7.15.7" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.15.7.tgz" @@ -494,6 +646,11 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.4.tgz#03c4339d2b8971eb3beca5252bafd9b9f79db3dc" integrity sha512-qpVT7gtuOLjWeDTKLkJ6sryqLliBaFpAtGeqw5cs5giLldvh+Ch0plqnUMKoVAUS6ZEueQQiZV+p5pxtPitEsA== +"@babel/parser@^7.22.5", "@babel/parser@^7.22.7": + version "7.22.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.7.tgz#df8cf085ce92ddbdbf668a7f186ce848c9036cae" + integrity sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q== + "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" @@ -536,6 +693,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.18.6" +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz#a6b68e84fb76e759fc3b93e901876ffabbe1d918" + integrity sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" @@ -672,6 +836,15 @@ "@babel/parser" "^7.18.10" "@babel/types" "^7.18.10" +"@babel/template@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec" + integrity sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw== + dependencies: + "@babel/code-frame" "^7.22.5" + "@babel/parser" "^7.22.5" + "@babel/types" "^7.22.5" + "@babel/traverse@^7.1.0", "@babel/traverse@^7.15.4", "@babel/traverse@^7.7.2": version "7.15.4" resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz" @@ -719,6 +892,22 @@ debug "^4.1.0" globals "^11.1.0" +"@babel/traverse@^7.22.6", "@babel/traverse@^7.22.8": + version "7.22.8" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.8.tgz#4d4451d31bc34efeae01eac222b514a77aa4000e" + integrity sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw== + dependencies: + "@babel/code-frame" "^7.22.5" + "@babel/generator" "^7.22.7" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.22.7" + "@babel/types" "^7.22.5" + debug "^4.1.0" + globals "^11.1.0" + "@babel/types@^7.0.0", "@babel/types@^7.15.4", "@babel/types@^7.15.6", "@babel/types@^7.3.0", "@babel/types@^7.3.3": version "7.15.6" resolved "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz" @@ -744,6 +933,15 @@ "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" +"@babel/types@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.5.tgz#cd93eeaab025880a3a47ec881f4b096a5b786fbe" + integrity sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA== + dependencies: + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.5" + to-fast-properties "^2.0.0" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" @@ -1960,6 +2158,18 @@ jest-util "^27.5.1" slash "^3.0.0" +"@jest/console@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.6.2.tgz#bf1d4101347c23e07c029a1b1ae07d550f5cc541" + integrity sha512-0N0yZof5hi44HAR2pPS+ikJ3nzKNoZdVu8FffRf3wy47I7Dm7etk/3KetMdRUqzVd16V4O2m2ISpNTbnIuqy1w== + dependencies: + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.6.2" + jest-util "^29.6.2" + slash "^3.0.0" + "@jest/core@^27.2.4": version "27.2.4" resolved "https://registry.npmjs.org/@jest/core/-/core-27.2.4.tgz" @@ -2028,6 +2238,40 @@ slash "^3.0.0" strip-ansi "^6.0.0" +"@jest/core@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.6.2.tgz#6f2d1dbe8aa0265fcd4fb8082ae1952f148209c8" + integrity sha512-Oj+5B+sDMiMWLhPFF+4/DvHOf+U10rgvCLGPHP8Xlsy/7QxS51aU/eBngudHlJXnaWD5EohAgJ4js+T6pa+zOg== + dependencies: + "@jest/console" "^29.6.2" + "@jest/reporters" "^29.6.2" + "@jest/test-result" "^29.6.2" + "@jest/transform" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.5.0" + jest-config "^29.6.2" + jest-haste-map "^29.6.2" + jest-message-util "^29.6.2" + jest-regex-util "^29.4.3" + jest-resolve "^29.6.2" + jest-resolve-dependencies "^29.6.2" + jest-runner "^29.6.2" + jest-runtime "^29.6.2" + jest-snapshot "^29.6.2" + jest-util "^29.6.2" + jest-validate "^29.6.2" + jest-watcher "^29.6.2" + micromatch "^4.0.4" + pretty-format "^29.6.2" + slash "^3.0.0" + strip-ansi "^6.0.0" + "@jest/environment@^27.2.4": version "27.2.4" resolved "https://registry.npmjs.org/@jest/environment/-/environment-27.2.4.tgz" @@ -2048,6 +2292,31 @@ "@types/node" "*" jest-mock "^27.5.1" +"@jest/environment@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.6.2.tgz#794c0f769d85e7553439d107d3f43186dc6874a9" + integrity sha512-AEcW43C7huGd/vogTddNNTDRpO6vQ2zaQNrttvWV18ArBx9Z56h7BIsXkNFJVOO4/kblWEQz30ckw0+L3izc+Q== + dependencies: + "@jest/fake-timers" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + jest-mock "^29.6.2" + +"@jest/expect-utils@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.6.2.tgz#1b97f290d0185d264dd9fdec7567a14a38a90534" + integrity sha512-6zIhM8go3RV2IG4aIZaZbxwpOzz3ZiM23oxAlkquOIole+G6TrbeXnykxWYlqF7kz2HlBjdKtca20x9atkEQYg== + dependencies: + jest-get-type "^29.4.3" + +"@jest/expect@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.6.2.tgz#5a2ad58bb345165d9ce0a1845bbf873c480a4b28" + integrity sha512-m6DrEJxVKjkELTVAztTLyS/7C92Y2b0VYqmDROYKLLALHn8T/04yPs70NADUYPrV3ruI+H3J0iUIuhkjp7vkfg== + dependencies: + expect "^29.6.2" + jest-snapshot "^29.6.2" + "@jest/fake-timers@^27.2.4": version "27.2.4" resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.2.4.tgz" @@ -2072,6 +2341,18 @@ jest-mock "^27.5.1" jest-util "^27.5.1" +"@jest/fake-timers@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.6.2.tgz#fe9d43c5e4b1b901168fe6f46f861b3e652a2df4" + integrity sha512-euZDmIlWjm1Z0lJ1D0f7a0/y5Kh/koLFMUBE5SUYWrmy8oNhJpbTBDAP6CxKnadcMLDoDf4waRYCe35cH6G6PA== + dependencies: + "@jest/types" "^29.6.1" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.6.2" + jest-mock "^29.6.2" + jest-util "^29.6.2" + "@jest/globals@^27.2.4": version "27.2.4" resolved "https://registry.npmjs.org/@jest/globals/-/globals-27.2.4.tgz" @@ -2090,6 +2371,16 @@ "@jest/types" "^27.5.1" expect "^27.5.1" +"@jest/globals@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.6.2.tgz#74af81b9249122cc46f1eb25793617eec69bf21a" + integrity sha512-cjuJmNDjs6aMijCmSa1g2TNG4Lby/AeU7/02VtpW+SLcZXzOLK2GpN2nLqcFjmhy3B3AoPeQVx7BnyOf681bAw== + dependencies: + "@jest/environment" "^29.6.2" + "@jest/expect" "^29.6.2" + "@jest/types" "^29.6.1" + jest-mock "^29.6.2" + "@jest/reporters@^27.2.4": version "27.2.4" resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-27.2.4.tgz" @@ -2151,6 +2442,43 @@ terminal-link "^2.0.0" v8-to-istanbul "^8.1.0" +"@jest/reporters@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.6.2.tgz#524afe1d76da33d31309c2c4a2c8062d0c48780a" + integrity sha512-sWtijrvIav8LgfJZlrGCdN0nP2EWbakglJY49J1Y5QihcQLfy7ovyxxjJBRXMNltgt4uPtEcFmIMbVshEDfFWw== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.6.2" + "@jest/test-result" "^29.6.2" + "@jest/transform" "^29.6.2" + "@jest/types" "^29.6.1" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.6.2" + jest-util "^29.6.2" + jest-worker "^29.6.2" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^29.6.0": + version "29.6.0" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.0.tgz#0f4cb2c8e3dca80c135507ba5635a4fd755b0040" + integrity sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ== + dependencies: + "@sinclair/typebox" "^0.27.8" + "@jest/source-map@^27.0.6": version "27.0.6" resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-27.0.6.tgz" @@ -2169,6 +2497,15 @@ graceful-fs "^4.2.9" source-map "^0.6.0" +"@jest/source-map@^29.6.0": + version "29.6.0" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.0.tgz#bd34a05b5737cb1a99d43e1957020ac8e5b9ddb1" + integrity sha512-oA+I2SHHQGxDCZpbrsCQSoMLb3Bz547JnM+jUr9qEbuw0vQlWZfpPS7CO9J7XiwKicEz9OFn/IYoLkkiUD7bzA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + callsites "^3.0.0" + graceful-fs "^4.2.9" + "@jest/test-result@^27.2.4": version "27.2.4" resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-27.2.4.tgz" @@ -2189,6 +2526,16 @@ "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" +"@jest/test-result@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.6.2.tgz#fdd11583cd1608e4db3114e8f0cce277bf7a32ed" + integrity sha512-3VKFXzcV42EYhMCsJQURptSqnyjqCGbtLuX5Xxb6Pm6gUf1wIRIl+mandIRGJyWKgNKYF9cnstti6Ls5ekduqw== + dependencies: + "@jest/console" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + "@jest/test-sequencer@^27.2.4": version "27.2.4" resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.2.4.tgz" @@ -2209,6 +2556,16 @@ jest-haste-map "^27.5.1" jest-runtime "^27.5.1" +"@jest/test-sequencer@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.6.2.tgz#585eff07a68dd75225a7eacf319780cb9f6b9bf4" + integrity sha512-GVYi6PfPwVejO7slw6IDO0qKVum5jtrJ3KoLGbgBWyr2qr4GaxFV6su+ZAjdTX75Sr1DkMFRk09r2ZVa+wtCGw== + dependencies: + "@jest/test-result" "^29.6.2" + graceful-fs "^4.2.9" + jest-haste-map "^29.6.2" + slash "^3.0.0" + "@jest/transform@^27.2.4": version "27.2.4" resolved "https://registry.npmjs.org/@jest/transform/-/transform-27.2.4.tgz" @@ -2251,6 +2608,27 @@ source-map "^0.6.1" write-file-atomic "^3.0.0" +"@jest/transform@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.6.2.tgz#522901ebbb211af08835bc3bcdf765ab778094e3" + integrity sha512-ZqCqEISr58Ce3U+buNFJYUktLJZOggfyvR+bZMaiV1e8B1SIvJbwZMrYz3gx/KAPn9EXmOmN+uB08yLCjWkQQg== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.1" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.6.2" + jest-regex-util "^29.4.3" + jest-util "^29.6.2" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + "@jest/types@^27.2.4": version "27.2.4" resolved "https://registry.npmjs.org/@jest/types/-/types-27.2.4.tgz" @@ -2273,6 +2651,18 @@ "@types/yargs" "^16.0.0" chalk "^4.0.0" +"@jest/types@^29.6.1": + version "29.6.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.1.tgz#ae79080278acff0a6af5eb49d063385aaa897bf2" + integrity sha512-tPKQNMPuXgvdOn2/Lg9HNfUvjYVGolt04Hp03f5hAk878uwOLikN+JzeLY0HcVgKgFl9Hs3EIqpu3WX27XNhnw== + dependencies: + "@jest/schemas" "^29.6.0" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + "@jridgewell/gen-mapping@^0.1.0": version "0.1.1" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" @@ -2290,7 +2680,7 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/resolve-uri@^3.0.3": +"@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3": version "3.1.0" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== @@ -2308,7 +2698,7 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/sourcemap-codec@^1.4.10": +"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": version "1.4.14" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== @@ -2321,6 +2711,14 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18": + version "0.3.18" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" + integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + "@jridgewell/trace-mapping@^0.3.9": version "0.3.14" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" @@ -2545,6 +2943,19 @@ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45" integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw== +"@puppeteer/browsers@1.4.6": + version "1.4.6" + resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-1.4.6.tgz#1f70fd23d5d2ccce9d29b038e5039d7a1049ca77" + integrity sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ== + dependencies: + debug "4.3.4" + extract-zip "2.0.1" + progress "2.0.3" + proxy-agent "6.3.0" + tar-fs "3.0.4" + unbzip2-stream "1.4.3" + yargs "17.7.1" + "@remix-run/router@1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.0.2.tgz#1c17eadb2fa77f80a796ad5ea9bf108e6993ef06" @@ -2665,6 +3076,11 @@ colors "~1.2.1" string-argv "~0.3.1" +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" @@ -2677,6 +3093,20 @@ dependencies: type-detect "4.0.8" +"@sinonjs/commons@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.0.tgz#beb434fe875d965265e04722ccfc21df7f755d72" + integrity sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== + dependencies: + "@sinonjs/commons" "^3.0.0" + "@sinonjs/fake-timers@^8.0.1": version "8.0.1" resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.0.1.tgz" @@ -2708,6 +3138,16 @@ resolved "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz" integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== +"@tootallnate/once@2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" + integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== + +"@tootallnate/quickjs-emscripten@^0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz#db4ecfd499a9765ab24002c3b696d02e6d32a12c" + integrity sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA== + "@ts-morph/common@~0.17.0": version "0.17.0" resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.17.0.tgz#de0d405df10857907469fef8d9363893b4163fd1" @@ -2838,6 +3278,13 @@ dependencies: "@types/node" "*" +"@types/graceful-fs@^4.1.3": + version "4.1.6" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.6.tgz#e14b2576a1c25026b7f02ede1de3b84c3a1efeae" + integrity sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw== + dependencies: + "@types/node" "*" + "@types/inquirer@^8.2.1": version "8.2.1" resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-8.2.1.tgz#28a139be3105a1175e205537e8ac10830e38dbf4" @@ -2872,10 +3319,10 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest-image-snapshot@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@types/jest-image-snapshot/-/jest-image-snapshot-5.1.0.tgz#aa355ec40625fcb338fd31c935791bc8fde72bcf" - integrity sha512-pfCz6dclA8mDxwXN/x/PuYBCPwzGuYcTfOVZvDAikC1GLXg/CwECF9UgtWse0tR42c6OaL7LPEnN7i/Dm86KkQ== +"@types/jest-image-snapshot@^6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@types/jest-image-snapshot/-/jest-image-snapshot-6.1.0.tgz#d74176821cbdf24458f39819743e9adb3d3146e9" + integrity sha512-wYayjKQGdI0ZbmsAq7OPt+5wMMi1CDXXkF3LfoGj4eRC0dOqlYJdXqLwfC89Qf2apQdlL9StgCkw0iTDb8lpUw== dependencies: "@types/jest" "*" "@types/pixelmatch" "*" @@ -2897,6 +3344,14 @@ jest-matcher-utils "^27.0.0" pretty-format "^27.0.0" +"@types/jest@^29.5.0": + version "29.5.3" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.3.tgz#7a35dc0044ffb8b56325c6802a4781a626b05777" + integrity sha512-1Nq7YrO/vJE/FYnqYyw0FS8LdrjExSgIiHyKg7xPpn+yi8Q4huZryKnkJatN1ZRH89Kw2v33/8ZMB7DuZeSLlA== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + "@types/jsdom@^20.0.0": version "20.0.0" resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-20.0.0.tgz#4414fb629465167f8b7b3804b9e067bdd99f1791" @@ -3095,6 +3550,13 @@ dependencies: "@types/yargs-parser" "*" +"@types/yargs@^17.0.8": + version "17.0.24" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.24.tgz#b3ef8d50ad4aa6aecf6ddc97c580a00f5aa11902" + integrity sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw== + dependencies: + "@types/yargs-parser" "*" + "@types/yauzl@2.9.2", "@types/yauzl@^2.9.1": version "2.9.2" resolved "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz" @@ -3350,6 +3812,11 @@ abab@^2.0.3, abab@^2.0.5: resolved "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz" integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== +abab@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" + integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== + accepts@~1.3.7: version "1.3.7" resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz" @@ -3366,6 +3833,14 @@ acorn-globals@^6.0.0: acorn "^7.1.1" acorn-walk "^7.1.1" +acorn-globals@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-7.0.1.tgz#0dbf05c44fa7c94332914c02066d5beff62c40c3" + integrity sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q== + dependencies: + acorn "^8.1.0" + acorn-walk "^8.0.2" + acorn-jsx@^5.3.1, acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" @@ -3376,7 +3851,7 @@ acorn-walk@^7.1.1: resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== -acorn-walk@^8.1.1: +acorn-walk@^8.0.2, acorn-walk@^8.1.1: version "8.2.0" resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== @@ -3386,6 +3861,11 @@ acorn@^7.1.1: resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +acorn@^8.1.0, acorn@^8.8.1: + version "8.10.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" + integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== + acorn@^8.2.4, acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.1: version "8.7.1" resolved "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz" @@ -3462,6 +3942,13 @@ agent-base@6: dependencies: debug "4" +agent-base@^7.0.1, agent-base@^7.0.2, agent-base@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.0.tgz#536802b76bc0b34aa50195eb2442276d613e3434" + integrity sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg== + dependencies: + debug "^4.3.4" + ajv-merge-patch@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ajv-merge-patch/-/ajv-merge-patch-4.1.0.tgz#cd580e5860ac53431d6aa901fa3d5e2eb2b74a6c" @@ -3690,6 +4177,13 @@ ast-metadata-inferer@^0.7.0: dependencies: "@mdn/browser-compat-data" "^3.3.14" +ast-types@^0.13.4: + version "0.13.4" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782" + integrity sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w== + dependencies: + tslib "^2.0.1" + async@^3.2.0: version "3.2.4" resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" @@ -3730,6 +4224,11 @@ aws4@^1.8.0: resolved "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== +b4a@^1.6.4: + version "1.6.4" + resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.4.tgz#ef1c1422cae5ce6535ec191baeed7567443f36c9" + integrity sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw== + babel-jest@^27.2.4: version "27.2.4" resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-27.2.4.tgz" @@ -3758,6 +4257,19 @@ babel-jest@^27.5.1: graceful-fs "^4.2.9" slash "^3.0.0" +babel-jest@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.6.2.tgz#cada0a59e07f5acaeb11cbae7e3ba92aec9c1126" + integrity sha512-BYCzImLos6J3BH/+HvUCHG1dTf2MzmAB4jaVxHV+29RZLjR29XuYTmsf2sdDwkrb+FczkGo3kOhE7ga6sI0P4A== + dependencies: + "@jest/transform" "^29.6.2" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.5.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + babel-plugin-istanbul@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz" @@ -3800,6 +4312,16 @@ babel-plugin-jest-hoist@^27.5.1: "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" +babel-plugin-jest-hoist@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz#a97db437936f441ec196990c9738d4b88538618a" + integrity sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + babel-plugin-macros@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" @@ -3843,6 +4365,14 @@ babel-preset-jest@^27.5.1: babel-plugin-jest-hoist "^27.5.1" babel-preset-current-node-syntax "^1.0.0" +babel-preset-jest@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz#57bc8cc88097af7ff6a5ab59d1cd29d52a5916e2" + integrity sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg== + dependencies: + babel-plugin-jest-hoist "^29.5.0" + babel-preset-current-node-syntax "^1.0.0" + babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz" @@ -3876,6 +4406,11 @@ base64-js@^1.3.1: resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +basic-ftp@^5.0.2: + version "5.0.3" + resolved "https://registry.yarnpkg.com/basic-ftp/-/basic-ftp-5.0.3.tgz#b14c0fe8111ce001ec913686434fe0c2fb461228" + integrity sha512-QHX8HLlncOLpy54mh+k/sWIFd0ThmRqwe9ZjELybGZK+tZ8rUb9VO0saKJUROTbE+KhzDUT7xziGpGrW8Kmd+g== + bcrypt-pbkdf@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz" @@ -4056,6 +4591,16 @@ browserslist@^4.17.5: node-releases "^2.0.1" picocolors "^1.0.0" +browserslist@^4.21.9: + version "4.21.10" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" + integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== + dependencies: + caniuse-lite "^1.0.30001517" + electron-to-chromium "^1.4.477" + node-releases "^2.0.13" + update-browserslist-db "^1.0.11" + bs-logger@0.x: version "0.2.6" resolved "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz" @@ -4205,6 +4750,11 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001219, caniuse-lite@^1.0.30001264, can resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001402.tgz" integrity sha512-Mx4MlhXO5NwuvXGgVb+hg65HZ+bhUYsz8QtDGDo2QmaJS2GBX47Xfi2koL86lc8K+l+htXeTEB/Aeqvezoo6Ew== +caniuse-lite@^1.0.30001517: + version "1.0.30001518" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001518.tgz#b3ca93904cb4699c01218246c4d77a71dbe97150" + integrity sha512-rup09/e3I0BKjncL+FesTayKtPrdwKhUufQFd3riFw1hHg8JmIFoInYfB102cFcY/pPgGmdyl/iy+jgiDi2vdA== + caseless@~0.12.0: version "0.12.0" resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz" @@ -4320,6 +4870,13 @@ chrome-launcher@0.15.0: is-wsl "^2.2.0" lighthouse-logger "^1.0.0" +chromium-bidi@0.4.16: + version "0.4.16" + resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-0.4.16.tgz#8a67bfdf6bb8804efc22765a82859d20724b46ab" + integrity sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA== + dependencies: + mitt "3.0.0" + ci-info@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz" @@ -4624,6 +5181,11 @@ convert-source-map@^1.5.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" @@ -4666,6 +5228,16 @@ core-util-is@^1.0.2: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== +cosmiconfig@8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.2.0.tgz#f7d17c56a590856cd1e7cee98734dca272b0d8fd" + integrity sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ== + dependencies: + import-fresh "^3.2.1" + js-yaml "^4.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + cosmiconfig@^5.0.0: version "5.2.1" resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz" @@ -4713,6 +5285,13 @@ cross-fetch@3.1.5: dependencies: node-fetch "2.6.7" +cross-fetch@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-4.0.0.tgz#f037aef1580bb3a1a35164ea2a848ba81b445983" + integrity sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g== + dependencies: + node-fetch "^2.6.12" + cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -4924,18 +5503,13 @@ csso@^4.0.2: dependencies: css-tree "^1.1.2" -cssom@^0.4.4, "cssom@https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz": +cssom@^0.4.4, cssom@^0.5.0, "cssom@https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz": version "0.6.0" resolved "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz#ed298055b97cbddcdeb278f904857629dec5e0e1" -cssom@^0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz" - integrity sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw== - cssom@~0.3.6: version "0.3.8" - resolved "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== cssstyle@^2.3.0: @@ -4982,6 +5556,11 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" +data-uri-to-buffer@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-5.0.1.tgz#db89a9e279c2ffe74f50637a59a32fb23b3e4d7c" + integrity sha512-a9l6T1qqDogvvnw0nKlfZzqsyikEBZBClF39V3TFoKhDtGBqHu2HkuomJc02j5zft8zrUaXEuoicLeW54RkzPg== + data-urls@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz" @@ -4991,6 +5570,15 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" +data-urls@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-3.0.2.tgz#9cf24a477ae22bcef5cd5f6f0bfbc1d2d3be9143" + integrity sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ== + dependencies: + abab "^2.0.6" + whatwg-mimetype "^3.0.0" + whatwg-url "^11.0.0" + dataloader@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-1.4.0.tgz#bca11d867f5d3f1b9ed9f737bd15970c65dff5c8" @@ -5013,7 +5601,7 @@ debug@2.6.9, debug@^2.6.9, debug@~2.6.3: dependencies: ms "2.0.0" -debug@4, debug@4.3.2, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2: +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2: version "4.3.2" resolved "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz" integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== @@ -5050,6 +5638,11 @@ decimal.js@^10.2.1: resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz" integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== +decimal.js@^10.4.2: + version "10.4.3" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" + integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== + decompress-response@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" @@ -5062,6 +5655,11 @@ dedent@^0.7.0: resolved "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz" integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= +dedent@^1.0.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" + integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== + deep-equal@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" @@ -5123,6 +5721,15 @@ define-properties@^1.1.4: has-property-descriptors "^1.0.0" object-keys "^1.1.1" +degenerator@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-5.0.1.tgz#9403bf297c6dad9a1ece409b37db27954f91f2f5" + integrity sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ== + dependencies: + ast-types "^0.13.4" + escodegen "^2.1.0" + esprima "^4.0.1" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" @@ -5158,16 +5765,16 @@ devtools-protocol@0.0.1036444: resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1036444.tgz#a570d3cdde61527c82f9b03919847b8ac7b1c2b9" integrity sha512-0y4f/T8H9lsESV9kKP1HDUXgHxCdniFeJh6Erq+FbdOEvp/Ydp9t8kcAAM5gOd17pMrTDlFWntoHtzzeTUWKNw== +devtools-protocol@0.0.1147663: + version "0.0.1147663" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz#4ec5610b39a6250d1f87e6b9c7e16688ed0ac78e" + integrity sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ== + devtools-protocol@0.0.869402: version "0.0.869402" resolved "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.869402.tgz" integrity sha512-VvlVYY+VDJe639yHs5PHISzdWTLL3Aw8rO4cvUtwvoxFd6FHbE4OpHHcde52M6096uYYazAmd4l0o5VuFRO2WA== -devtools-protocol@0.0.901419: - version "0.0.901419" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.901419.tgz#79b5459c48fe7e1c5563c02bd72f8fec3e0cebcd" - integrity sha512-4INMPwNm9XRpBukhNbF7OB6fNTTCaI8pzy/fXg0xQzAy5h3zL1P8xT3QazgKqBrb/hAYwIBizqDBZ7GtJE74QQ== - diff-sequences@^27.0.6: version "27.0.6" resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz" @@ -5178,6 +5785,11 @@ diff-sequences@^27.5.1: resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz" integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== +diff-sequences@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" + integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== + diff@^3.1.0, diff@^3.2.0: version "3.5.0" resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz" @@ -5236,6 +5848,13 @@ domexception@^2.0.1: dependencies: webidl-conversions "^5.0.0" +domexception@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-4.0.0.tgz#4ad1be56ccadc86fc76d033353999a8037d03673" + integrity sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw== + dependencies: + webidl-conversions "^7.0.0" + domhandler@^4.0.0, domhandler@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz" @@ -5339,6 +5958,16 @@ electron-to-chromium@^1.4.251: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.254.tgz#c6203583890abf88dfc0be046cd72d3b48f8beb6" integrity sha512-Sh/7YsHqQYkA6ZHuHMy24e6TE4eX6KZVsZb9E/DvU1nQRIrH4BflO/4k+83tfdYvDl+MObvlqHPRICzEdC9c6Q== +electron-to-chromium@^1.4.477: + version "1.4.479" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.479.tgz#ec9f676f23d3a0b0e429bc454d25e0b3253d2118" + integrity sha512-ABv1nHMIR8I5n3O3Een0gr6i0mfM+YcTZqjHy3pAYaOjgFG+BMquuKrSyfYf5CbEkLr9uM05RA3pOk4udNB/aQ== + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + emittery@^0.8.1: version "0.8.1" resolved "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz" @@ -5388,6 +6017,11 @@ entities@^4.3.0: resolved "https://registry.yarnpkg.com/entities/-/entities-4.3.1.tgz#c34062a94c865c322f9d67b4384e4169bcede6a4" integrity sha512-o4q/dYJlmyjP2zfnaWDUC6A3BQFmVTX+tZPezK7k0GLSU9QYCauscf5Y+qcEPzKL+EixVouYDgLQK5H9GrLpkg== +entities@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + entities@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" @@ -5828,6 +6462,17 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" +escodegen@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17" + integrity sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionalDependencies: + source-map "~0.6.1" + eslint-config-google@^0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/eslint-config-google/-/eslint-config-google-0.14.0.tgz#4f5f8759ba6e11b424294a219dbfa18c508bcc1a" @@ -5848,9 +6493,9 @@ eslint-plugin-compat@^4.0.2: semver "7.3.5" eslint-plugin-jest@^27.1.3: - version "27.1.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.1.3.tgz#9f359eeac0c720a825f658e7e261a9eef869dc8d" - integrity sha512-7DrIfYRQPa7JQd1Le8G/BJsfYHVUKQdJQ/6vULSp/4NjKZmSMJ/605G2hhScEra++SiH68zPEjLnrO74nHrMLg== + version "27.2.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.2.3.tgz#6f8a4bb2ca82c0c5d481d1b3be256ab001f5a3ec" + integrity sha512-sRLlSCpICzWuje66Gl9zvdF6mwD5X86I4u55hJyFBsxYOsBCmT5+kSUjf+fkFWVMMgpzNEupjW8WzUqi83hJAQ== dependencies: "@typescript-eslint/utils" "^5.10.0" @@ -6185,6 +6830,18 @@ expect@^27.5.1: jest-matcher-utils "^27.5.1" jest-message-util "^27.5.1" +expect@^29.0.0, expect@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.6.2.tgz#7b08e83eba18ddc4a2cf62b5f2d1918f5cd84521" + integrity sha512-iAErsLxJ8C+S02QbLAwgSGSezLQK+XXRDt8IuFXFpwCNw2ECmzZSmjKcCaFVp5VRMk+WAvz6h6jokzEzBFZEuA== + dependencies: + "@jest/expect-utils" "^29.6.2" + "@types/node" "*" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.6.2" + jest-message-util "^29.6.2" + jest-util "^29.6.2" + express@^4.16.4: version "4.17.1" resolved "https://registry.npmjs.org/express/-/express-4.17.1.tgz" @@ -6278,6 +6935,11 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-fifo@^1.1.0, fast-fifo@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.0.tgz#03e381bcbfb29932d7c3afde6e15e83e05ab4d8b" + integrity sha512-IgfweLvEpwyA4WgiQe9Nx6VV2QkML2NkvZnk1oKnIzXgXdWxuhF7zw4DvLTPZJn6PIUneiAXPF24QmoEqHTjyw== + fast-glob@^3.1.1: version "3.2.7" resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz" @@ -6318,7 +6980,7 @@ fast-json-patch@^2.0.6: dependencies: fast-deep-equal "^2.0.1" -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -6552,6 +7214,15 @@ form-data@^3.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + form-data@~2.3.2: version "2.3.3" resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz" @@ -6812,6 +7483,16 @@ get-symbol-description@^1.0.0: call-bind "^1.0.2" get-intrinsic "^1.1.1" +get-uri@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-6.0.1.tgz#cff2ba8d456c3513a04b70c45de4dbcca5b1527c" + integrity sha512-7ZqONUVqaabogsYNWlYj0t3YZaL6dhuEueZXGF+/YVmf6dHmaFg8/6psJKqhx9QykIDKzpGcy2cn4oV4YC7V/Q== + dependencies: + basic-ftp "^5.0.2" + data-uri-to-buffer "^5.0.1" + debug "^4.3.4" + fs-extra "^8.1.0" + getpass@^0.1.1: version "0.1.7" resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz" @@ -7165,6 +7846,13 @@ html-encoding-sniffer@^2.0.1: dependencies: whatwg-encoding "^1.0.5" +html-encoding-sniffer@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz#2cb1a8cf0db52414776e5b2a7a04d5dd98158de9" + integrity sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA== + dependencies: + whatwg-encoding "^2.0.0" + html-escaper@^2.0.0: version "2.0.2" resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" @@ -7216,7 +7904,24 @@ http-proxy-agent@^4.0.1: agent-base "6" debug "4" -http-signature@~1.2.0: +http-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" + integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w== + dependencies: + "@tootallnate/once" "2" + agent-base "6" + debug "4" + +http-proxy-agent@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz#e9096c5afd071a3fce56e6252bb321583c124673" + integrity sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" + +http-signature@~1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz" integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= @@ -7225,7 +7930,15 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" -https-proxy-agent@5.0.0, https-proxy-agent@^5.0.0: +https-proxy-agent@5.0.1, https-proxy-agent@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + +https-proxy-agent@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz" integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== @@ -7233,12 +7946,12 @@ https-proxy-agent@5.0.0, https-proxy-agent@^5.0.0: agent-base "6" debug "4" -https-proxy-agent@5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" - integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== +https-proxy-agent@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz#0277e28f13a07d45c663633841e20a40aaafe0ab" + integrity sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ== dependencies: - agent-base "6" + agent-base "^7.0.2" debug "4" human-id@^1.0.2: @@ -7263,6 +7976,13 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + icss-replace-symbols@1.1.0, icss-replace-symbols@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz" @@ -7468,6 +8188,16 @@ invert-kv@^3.0.0: resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-3.0.1.tgz#a93c7a3d4386a1dc8325b97da9bb1620c0282523" integrity sha512-CYdFeFexxhv/Bcny+Q0BfOV+ltRlJcd4BBZBYFX/O0u4npJrgZtIcjokegtiSMAvlMTJ+Koq0GBCc//3bueQxw== +ip@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.8.tgz#ae05948f6b075435ed3307acce04629da8cdbf48" + integrity sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg== + +ip@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" + integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== + ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" @@ -8009,6 +8739,14 @@ jest-changed-files@^27.5.1: execa "^5.0.0" throat "^6.0.1" +jest-changed-files@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.5.0.tgz#e88786dca8bf2aa899ec4af7644e16d9dcf9b23e" + integrity sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag== + dependencies: + execa "^5.0.0" + p-limit "^3.1.0" + jest-circus@^27.2.4: version "27.2.4" resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-27.2.4.tgz" @@ -8059,6 +8797,32 @@ jest-circus@^27.5.1: stack-utils "^2.0.3" throat "^6.0.1" +jest-circus@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.6.2.tgz#1e6ffca60151ac66cad63fce34f443f6b5bb4258" + integrity sha512-G9mN+KOYIUe2sB9kpJkO9Bk18J4dTDArNFPwoZ7WKHKel55eKIS/u2bLthxgojwlf9NLCVQfgzM/WsOVvoC6Fw== + dependencies: + "@jest/environment" "^29.6.2" + "@jest/expect" "^29.6.2" + "@jest/test-result" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.6.2" + jest-matcher-utils "^29.6.2" + jest-message-util "^29.6.2" + jest-runtime "^29.6.2" + jest-snapshot "^29.6.2" + jest-util "^29.6.2" + p-limit "^3.1.0" + pretty-format "^29.6.2" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + jest-cli@^27.2.4: version "27.2.4" resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-27.2.4.tgz" @@ -8095,6 +8859,24 @@ jest-cli@^27.5.1: prompts "^2.0.1" yargs "^16.2.0" +jest-cli@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.6.2.tgz#edb381763398d1a292cd1b636a98bfa5644b8fda" + integrity sha512-TT6O247v6dCEX2UGHGyflMpxhnrL0DNqP2fRTKYm3nJJpCTfXX3GCMQPGFjXDoj0i5/Blp3jriKXFgdfmbYB6Q== + dependencies: + "@jest/core" "^29.6.2" + "@jest/test-result" "^29.6.2" + "@jest/types" "^29.6.1" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^29.6.2" + jest-util "^29.6.2" + jest-validate "^29.6.2" + prompts "^2.0.1" + yargs "^17.3.1" + jest-config@^27.2.4: version "27.2.4" resolved "https://registry.npmjs.org/jest-config/-/jest-config-27.2.4.tgz" @@ -8152,6 +8934,34 @@ jest-config@^27.5.1: slash "^3.0.0" strip-json-comments "^3.1.1" +jest-config@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.6.2.tgz#c68723f06b31ca5e63030686e604727d406cd7c3" + integrity sha512-VxwFOC8gkiJbuodG9CPtMRjBUNZEHxwfQXmIudSTzFWxaci3Qub1ddTRbFNQlD/zUeaifLndh/eDccFX4wCMQw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.6.2" + "@jest/types" "^29.6.1" + babel-jest "^29.6.2" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.6.2" + jest-environment-node "^29.6.2" + jest-get-type "^29.4.3" + jest-regex-util "^29.4.3" + jest-resolve "^29.6.2" + jest-runner "^29.6.2" + jest-util "^29.6.2" + jest-validate "^29.6.2" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.6.2" + slash "^3.0.0" + strip-json-comments "^3.1.1" + jest-diff@^23.6.0: version "23.6.0" resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-23.6.0.tgz" @@ -8182,6 +8992,16 @@ jest-diff@^27.5.1: jest-get-type "^27.5.1" pretty-format "^27.5.1" +jest-diff@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.6.2.tgz#c36001e5543e82a0805051d3ceac32e6825c1c46" + integrity sha512-t+ST7CB9GX5F2xKwhwCf0TAR17uNDiaPTZnVymP9lw0lssa9vG+AFyDZoeIHStU3WowFFwT+ky+er0WVl2yGhA== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.4.3" + jest-get-type "^29.4.3" + pretty-format "^29.6.2" + jest-docblock@^27.0.6: version "27.0.6" resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.0.6.tgz" @@ -8196,6 +9016,13 @@ jest-docblock@^27.5.1: dependencies: detect-newline "^3.0.0" +jest-docblock@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.4.3.tgz#90505aa89514a1c7dceeac1123df79e414636ea8" + integrity sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg== + dependencies: + detect-newline "^3.0.0" + jest-each@^27.2.4: version "27.2.4" resolved "https://registry.npmjs.org/jest-each/-/jest-each-27.2.4.tgz" @@ -8218,6 +9045,17 @@ jest-each@^27.5.1: jest-util "^27.5.1" pretty-format "^27.5.1" +jest-each@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.6.2.tgz#c9e4b340bcbe838c73adf46b76817b15712d02ce" + integrity sha512-MsrsqA0Ia99cIpABBc3izS1ZYoYfhIy0NNWqPSE0YXbQjwchyt6B1HD2khzyPe1WiJA7hbxXy77ZoUQxn8UlSw== + dependencies: + "@jest/types" "^29.6.1" + chalk "^4.0.0" + jest-get-type "^29.4.3" + jest-util "^29.6.2" + pretty-format "^29.6.2" + jest-environment-jsdom@^27.2.4: version "27.2.4" resolved "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.2.4.tgz" @@ -8244,6 +9082,20 @@ jest-environment-jsdom@^27.5.1: jest-util "^27.5.1" jsdom "^16.6.0" +jest-environment-jsdom@^29.6.0: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-29.6.2.tgz#4fc68836a7774a771819a2f980cb47af3b1629da" + integrity sha512-7oa/+266AAEgkzae8i1awNEfTfjwawWKLpiw2XesZmaoVVj9u9t8JOYx18cG29rbPNtkUlZ8V4b5Jb36y/VxoQ== + dependencies: + "@jest/environment" "^29.6.2" + "@jest/fake-timers" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/jsdom" "^20.0.0" + "@types/node" "*" + jest-mock "^29.6.2" + jest-util "^29.6.2" + jsdom "^20.0.0" + jest-environment-node@^27.2.4: version "27.2.4" resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.2.4.tgz" @@ -8268,6 +9120,18 @@ jest-environment-node@^27.5.1: jest-mock "^27.5.1" jest-util "^27.5.1" +jest-environment-node@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.6.2.tgz#a9ea2cabff39b08eca14ccb32c8ceb924c8bb1ad" + integrity sha512-YGdFeZ3T9a+/612c5mTQIllvWkddPbYcN2v95ZH24oWMbGA4GGS2XdIF92QMhUhvrjjuQWYgUGW2zawOyH63MQ== + dependencies: + "@jest/environment" "^29.6.2" + "@jest/fake-timers" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + jest-mock "^29.6.2" + jest-util "^29.6.2" + jest-get-type@^22.1.0: version "22.4.3" resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz" @@ -8283,6 +9147,11 @@ jest-get-type@^27.5.1: resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz" integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== +jest-get-type@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5" + integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg== + jest-haste-map@^27.2.4: version "27.2.4" resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.2.4.tgz" @@ -8323,16 +9192,34 @@ jest-haste-map@^27.5.1: optionalDependencies: fsevents "^2.3.2" -jest-image-snapshot@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/jest-image-snapshot/-/jest-image-snapshot-5.2.0.tgz#4af046935b465f0460aa73e890717bbc25d431e9" - integrity sha512-msKQqsxr4ZS8S3FQ6ot1SPlDKc4pCfyKY3SxU9LEoASj1zoEfglDYjmxNX53pxpNf7Fp7CJZvwP4xkNXVQgEXA== +jest-haste-map@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.6.2.tgz#298c25ea5255cfad8b723179d4295cf3a50a70d1" + integrity sha512-+51XleTDAAysvU8rT6AnS1ZJ+WHVNqhj1k6nTvN2PYP+HjU3kqlaKQ1Lnw3NYW3bm2r8vq82X0Z1nDDHZMzHVA== dependencies: - chalk "^1.1.3" + "@jest/types" "^29.6.1" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.4.3" + jest-util "^29.6.2" + jest-worker "^29.6.2" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-image-snapshot@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/jest-image-snapshot/-/jest-image-snapshot-6.2.0.tgz#b6bfc3e1585ec14b2b0595daf537ae1b4d7f8d13" + integrity sha512-9mTHBKiiSIZ26csbLmjKyN+SrVypM93S5y+jULCvn6YItgepvcrJIKGNeSyt9d2EZiutOroLs/UjtrWiBzpHbA== + dependencies: + chalk "^4.0.0" get-stdin "^5.0.1" glur "^1.1.2" lodash "^4.17.4" - mkdirp "^0.5.1" pixelmatch "^5.1.0" pngjs "^3.4.0" rimraf "^2.6.2" @@ -8401,6 +9288,14 @@ jest-leak-detector@^27.5.1: jest-get-type "^27.5.1" pretty-format "^27.5.1" +jest-leak-detector@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.6.2.tgz#e2b307fee78cab091c37858a98c7e1d73cdf5b38" + integrity sha512-aNqYhfp5uYEO3tdWMb2bfWv6f0b4I0LOxVRpnRLAeque2uqOVVMLh6khnTcE2qJ5wAKop0HcreM1btoysD6bPQ== + dependencies: + jest-get-type "^29.4.3" + pretty-format "^29.6.2" + jest-matcher-utils@^23.6.0: version "23.6.0" resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-23.6.0.tgz" @@ -8430,6 +9325,16 @@ jest-matcher-utils@^27.2.4: jest-get-type "^27.0.6" pretty-format "^27.2.4" +jest-matcher-utils@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.6.2.tgz#39de0be2baca7a64eacb27291f0bd834fea3a535" + integrity sha512-4LiAk3hSSobtomeIAzFTe+N8kL6z0JtF3n6I4fg29iIW7tt99R7ZcIFW34QkX+DuVrf+CUe6wuVOpm7ZKFJzZQ== + dependencies: + chalk "^4.0.0" + jest-diff "^29.6.2" + jest-get-type "^29.4.3" + pretty-format "^29.6.2" + jest-message-util@^23.4.0: version "23.4.0" resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-23.4.0.tgz" @@ -8471,6 +9376,21 @@ jest-message-util@^27.5.1: slash "^3.0.0" stack-utils "^2.0.3" +jest-message-util@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.6.2.tgz#af7adc2209c552f3f5ae31e77cf0a261f23dc2bb" + integrity sha512-vnIGYEjoPSuRqV8W9t+Wow95SDp6KPX2Uf7EoeG9G99J2OVh7OSwpS4B6J0NfpEIpfkBNHlBZpA2rblEuEFhZQ== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.1" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.6.2" + slash "^3.0.0" + stack-utils "^2.0.3" + jest-mock@^27.2.4: version "27.2.4" resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-27.2.4.tgz" @@ -8487,6 +9407,15 @@ jest-mock@^27.5.1: "@jest/types" "^27.5.1" "@types/node" "*" +jest-mock@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.6.2.tgz#ef9c9b4d38c34a2ad61010a021866dad41ce5e00" + integrity sha512-hoSv3lb3byzdKfwqCuT6uTscan471GUECqgNYykg6ob0yiAw3zYc7OrPnI9Qv8Wwoa4lC7AZ9hyS4AiIx5U2zg== + dependencies: + "@jest/types" "^29.6.1" + "@types/node" "*" + jest-util "^29.6.2" + jest-pnp-resolver@^1.2.2: version "1.2.2" resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz" @@ -8502,6 +9431,11 @@ jest-regex-util@^27.5.1: resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz" integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg== +jest-regex-util@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.4.3.tgz#a42616141e0cae052cfa32c169945d00c0aa0bb8" + integrity sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg== + jest-resolve-dependencies@^27.2.4: version "27.2.4" resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.2.4.tgz" @@ -8520,6 +9454,14 @@ jest-resolve-dependencies@^27.5.1: jest-regex-util "^27.5.1" jest-snapshot "^27.5.1" +jest-resolve-dependencies@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.2.tgz#36435269b6672c256bcc85fb384872c134cc4cf2" + integrity sha512-LGqjDWxg2fuQQm7ypDxduLu/m4+4Lb4gczc13v51VMZbVP5tSBILqVx8qfWcsdP8f0G7aIqByIALDB0R93yL+w== + dependencies: + jest-regex-util "^29.4.3" + jest-snapshot "^29.6.2" + jest-resolve@^23.6.0: version "23.6.0" resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-23.6.0.tgz" @@ -8561,6 +9503,21 @@ jest-resolve@^27.5.1: resolve.exports "^1.1.0" slash "^3.0.0" +jest-resolve@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.6.2.tgz#f18405fe4b50159b7b6d85e81f6a524d22afb838" + integrity sha512-G/iQUvZWI5e3SMFssc4ug4dH0aZiZpsDq9o1PtXTV1210Ztyb2+w+ZgQkB3iOiC5SmAEzJBOHWz6Hvrd+QnNPw== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.6.2" + jest-pnp-resolver "^1.2.2" + jest-util "^29.6.2" + jest-validate "^29.6.2" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + jest-runner@^27.2.4: version "27.2.4" resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-27.2.4.tgz" @@ -8616,6 +9573,33 @@ jest-runner@^27.5.1: source-map-support "^0.5.6" throat "^6.0.1" +jest-runner@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.6.2.tgz#89e8e32a8fef24781a7c4c49cd1cb6358ac7fc01" + integrity sha512-wXOT/a0EspYgfMiYHxwGLPCZfC0c38MivAlb2lMEAlwHINKemrttu1uSbcGbfDV31sFaPWnWJPmb2qXM8pqZ4w== + dependencies: + "@jest/console" "^29.6.2" + "@jest/environment" "^29.6.2" + "@jest/test-result" "^29.6.2" + "@jest/transform" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.4.3" + jest-environment-node "^29.6.2" + jest-haste-map "^29.6.2" + jest-leak-detector "^29.6.2" + jest-message-util "^29.6.2" + jest-resolve "^29.6.2" + jest-runtime "^29.6.2" + jest-util "^29.6.2" + jest-watcher "^29.6.2" + jest-worker "^29.6.2" + p-limit "^3.1.0" + source-map-support "0.5.13" + jest-runtime@^27.2.4: version "27.2.4" resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.2.4.tgz" @@ -8677,6 +9661,34 @@ jest-runtime@^27.5.1: slash "^3.0.0" strip-bom "^4.0.0" +jest-runtime@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.6.2.tgz#692f25e387f982e89ab83270e684a9786248e545" + integrity sha512-2X9dqK768KufGJyIeLmIzToDmsN0m7Iek8QNxRSI/2+iPFYHF0jTwlO3ftn7gdKd98G/VQw9XJCk77rbTGZnJg== + dependencies: + "@jest/environment" "^29.6.2" + "@jest/fake-timers" "^29.6.2" + "@jest/globals" "^29.6.2" + "@jest/source-map" "^29.6.0" + "@jest/test-result" "^29.6.2" + "@jest/transform" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.6.2" + jest-message-util "^29.6.2" + jest-mock "^29.6.2" + jest-regex-util "^29.4.3" + jest-resolve "^29.6.2" + jest-snapshot "^29.6.2" + jest-util "^29.6.2" + slash "^3.0.0" + strip-bom "^4.0.0" + jest-serializer@^27.0.6: version "27.0.6" resolved "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.0.6.tgz" @@ -8767,6 +9779,32 @@ jest-snapshot@^27.5.1: pretty-format "^27.5.1" semver "^7.3.2" +jest-snapshot@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.6.2.tgz#9b431b561a83f2bdfe041e1cab8a6becdb01af9c" + integrity sha512-1OdjqvqmRdGNvWXr/YZHuyhh5DeaLp1p/F8Tht/MrMw4Kr1Uu/j4lRG+iKl1DAqUJDWxtQBMk41Lnf/JETYBRA== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.6.2" + "@jest/transform" "^29.6.2" + "@jest/types" "^29.6.1" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.6.2" + graceful-fs "^4.2.9" + jest-diff "^29.6.2" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.6.2" + jest-message-util "^29.6.2" + jest-util "^29.6.2" + natural-compare "^1.4.0" + pretty-format "^29.6.2" + semver "^7.5.3" + jest-util@^27.0.0, jest-util@^27.2.4: version "27.2.4" resolved "https://registry.npmjs.org/jest-util/-/jest-util-27.2.4.tgz" @@ -8791,6 +9829,18 @@ jest-util@^27.5.1: graceful-fs "^4.2.9" picomatch "^2.2.3" +jest-util@^29.0.0, jest-util@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.6.2.tgz#8a052df8fff2eebe446769fd88814521a517664d" + integrity sha512-3eX1qb6L88lJNCFlEADKOkjpXJQyZRiavX1INZ4tRnrBVr2COd3RgcTLyUiEXMNBlDU/cgYq6taUS0fExrWW4w== + dependencies: + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + jest-validate@^27.2.4: version "27.2.4" resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-27.2.4.tgz" @@ -8815,6 +9865,18 @@ jest-validate@^27.5.1: leven "^3.1.0" pretty-format "^27.5.1" +jest-validate@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.6.2.tgz#25d972af35b2415b83b1373baf1a47bb266c1082" + integrity sha512-vGz0yMN5fUFRRbpJDPwxMpgSXW1LDKROHfBopAvDcmD6s+B/s8WJrwi+4bfH4SdInBA5C3P3BI19dBtKzx1Arg== + dependencies: + "@jest/types" "^29.6.1" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.4.3" + leven "^3.1.0" + pretty-format "^29.6.2" + jest-watcher@^27.2.4: version "27.2.4" resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.2.4.tgz" @@ -8841,6 +9903,20 @@ jest-watcher@^27.5.1: jest-util "^27.5.1" string-length "^4.0.1" +jest-watcher@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.6.2.tgz#77c224674f0620d9f6643c4cfca186d8893ca088" + integrity sha512-GZitlqkMkhkefjfN/p3SJjrDaxPflqxEAv3/ik10OirZqJGYH5rPiIsgVcfof0Tdqg3shQGdEIxDBx+B4tuLzA== + dependencies: + "@jest/test-result" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.6.2" + string-length "^4.0.1" + jest-worker@^26.2.1: version "26.6.2" resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz" @@ -8868,6 +9944,16 @@ jest-worker@^27.5.1: merge-stream "^2.0.0" supports-color "^8.0.0" +jest-worker@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.6.2.tgz#682fbc4b6856ad0aa122a5403c6d048b83f3fb44" + integrity sha512-l3ccBOabTdkng8I/ORCkADz4eSMKejTYv1vB/Z83UiubqhC1oQ5Li6dWCyqOIvSifGjUBxuvxvlm6KGK2DtuAQ== + dependencies: + "@types/node" "*" + jest-util "^29.6.2" + merge-stream "^2.0.0" + supports-color "^8.0.0" + jest@^27.2.4: version "27.2.4" resolved "https://registry.npmjs.org/jest/-/jest-27.2.4.tgz" @@ -8886,6 +9972,16 @@ jest@^27.5.1: import-local "^3.0.2" jest-cli "^27.5.1" +jest@^29.6.0: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.6.2.tgz#3bd55b9fd46a161b2edbdf5f1d1bd0d1eab76c42" + integrity sha512-8eQg2mqFbaP7CwfsTpCxQ+sHzw1WuNWL5UUvjnWP4hx2riGz9fPSzYOaU5q8/GqWn1TfgZIVTqYJygbGbWAANg== + dependencies: + "@jest/core" "^29.6.2" + "@jest/types" "^29.6.1" + import-local "^3.0.2" + jest-cli "^29.6.2" + jju@~1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/jju/-/jju-1.4.0.tgz#a3abe2718af241a2b2904f84a625970f389ae32a" @@ -8987,6 +10083,38 @@ jsdom@^16.6.0: ws "^7.4.6" xml-name-validator "^3.0.0" +jsdom@^20.0.0: + version "20.0.3" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-20.0.3.tgz#886a41ba1d4726f67a8858028c99489fed6ad4db" + integrity sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ== + dependencies: + abab "^2.0.6" + acorn "^8.8.1" + acorn-globals "^7.0.0" + cssom "^0.5.0" + cssstyle "^2.3.0" + data-urls "^3.0.2" + decimal.js "^10.4.2" + domexception "^4.0.0" + escodegen "^2.0.0" + form-data "^4.0.0" + html-encoding-sniffer "^3.0.0" + http-proxy-agent "^5.0.0" + https-proxy-agent "^5.0.1" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.2" + parse5 "^7.1.1" + saxes "^6.0.0" + symbol-tree "^3.2.4" + tough-cookie "^4.1.2" + w3c-xmlserializer "^4.0.0" + webidl-conversions "^7.0.0" + whatwg-encoding "^2.0.0" + whatwg-mimetype "^3.0.0" + whatwg-url "^11.0.0" + ws "^8.11.0" + xml-name-validator "^4.0.0" + jsesc@^2.5.1: version "2.5.2" resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" @@ -9058,6 +10186,11 @@ json5@^2.2.1: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== +json5@^2.2.2, json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + jsonc-parser@^3.0.0, jsonc-parser@~3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz" @@ -9404,6 +10537,13 @@ lru-cache@^4.0.1: pseudomap "^1.0.2" yallist "^2.1.2" +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" @@ -9411,6 +10551,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lru-cache@^7.14.1: + version "7.18.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" + integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== + magic-string@^0.25.7: version "0.25.7" resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz" @@ -9437,6 +10582,13 @@ make-error@1.x, make-error@^1.1.1, make-error@^1.3.2: resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + makeerror@1.0.x: version "1.0.11" resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz" @@ -9721,7 +10873,7 @@ minimist@^1.2.0, minimist@^1.2.5: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== -mitt@^3.0.0: +mitt@3.0.0, mitt@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.0.tgz#69ef9bd5c80ff6f57473e8d89326d01c414be0bd" integrity sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ== @@ -9842,18 +10994,16 @@ negotiator@0.6.2: resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== +netmask@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" + integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -node-fetch@2.6.5: - version "2.6.5" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.5.tgz#42735537d7f080a7e5f78b6c549b7146be1742fd" - integrity sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ== - dependencies: - whatwg-url "^5.0.0" - node-fetch@2.6.7, node-fetch@^2.6.1: version "2.6.7" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz" @@ -9868,6 +11018,13 @@ node-fetch@^2.5.0: dependencies: whatwg-url "^5.0.0" +node-fetch@^2.6.12: + version "2.6.12" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.12.tgz#02eb8e22074018e3d5a83016649d04df0e348fba" + integrity sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g== + dependencies: + whatwg-url "^5.0.0" + node-forge@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" @@ -9910,6 +11067,11 @@ node-releases@^2.0.1: resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz" integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== +node-releases@^2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" + integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== + node-releases@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" @@ -9973,6 +11135,11 @@ nwsapi@^2.2.0: resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz" integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== +nwsapi@^2.2.2: + version "2.2.7" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" + integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ== + oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz" @@ -10202,7 +11369,7 @@ p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-limit@^3.0.2: +p-limit@^3.0.2, p-limit@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== @@ -10248,6 +11415,29 @@ p-try@^2.0.0: resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +pac-proxy-agent@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-7.0.0.tgz#db42120c64292685dafaf2bd921e223c56bfb13b" + integrity sha512-t4tRAMx0uphnZrio0S0Jw9zg3oDbz1zVhQ/Vy18FjLfP1XOLNUEjaVxYCYRI6NS+BsMBXKIzV6cTLOkO9AtywA== + dependencies: + "@tootallnate/quickjs-emscripten" "^0.23.0" + agent-base "^7.0.2" + debug "^4.3.4" + get-uri "^6.0.1" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.0" + pac-resolver "^7.0.0" + socks-proxy-agent "^8.0.1" + +pac-resolver@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-7.0.0.tgz#79376f1ca26baf245b96b34c339d79bff25e900c" + integrity sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg== + dependencies: + degenerator "^5.0.0" + ip "^1.1.8" + netmask "^2.0.2" + package-json@^6.3.0: version "6.5.0" resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" @@ -10317,6 +11507,13 @@ parse5@^7.0.0: dependencies: entities "^4.3.0" +parse5@^7.1.1: + version "7.1.2" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" + integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== + dependencies: + entities "^4.4.0" + parseurl@~1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" @@ -10486,13 +11683,6 @@ pixelmatch@^5.1.0: dependencies: pngjs "^4.0.1" -pkg-dir@4.2.0, pkg-dir@^4.1.0, pkg-dir@^4.2.0: - version "4.2.0" - resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz" - integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== - dependencies: - find-up "^4.0.0" - "pkg-dir@< 6 >= 5": version "5.0.0" resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz" @@ -10500,6 +11690,13 @@ pkg-dir@4.2.0, pkg-dir@^4.1.0, pkg-dir@^4.2.0: dependencies: find-up "^5.0.0" +pkg-dir@^4.1.0, pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + playwright-core@1.32.1: version "1.32.1" resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.32.1.tgz#5a10c32403323b07d75ea428ebeed866a80b76a1" @@ -10986,6 +12183,15 @@ pretty-format@^27.5.1: ansi-styles "^5.0.0" react-is "^17.0.1" +pretty-format@^29.0.0, pretty-format@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.6.2.tgz#3d5829261a8a4d89d8b9769064b29c50ed486a47" + integrity sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg== + dependencies: + "@jest/schemas" "^29.6.0" + ansi-styles "^5.0.0" + react-is "^18.0.0" + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" @@ -11038,6 +12244,20 @@ proxy-addr@~2.0.5: forwarded "0.2.0" ipaddr.js "1.9.1" +proxy-agent@6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-6.3.0.tgz#72f7bb20eb06049db79f7f86c49342c34f9ba08d" + integrity sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og== + dependencies: + agent-base "^7.0.2" + debug "^4.3.4" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.0" + lru-cache "^7.14.1" + pac-proxy-agent "^7.0.0" + proxy-from-env "^1.1.0" + socks-proxy-agent "^8.0.1" + proxy-from-env@1.1.0, proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" @@ -11073,23 +12293,17 @@ pupa@^2.1.1: dependencies: escape-goat "^2.0.0" -puppeteer@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-11.0.0.tgz#0808719c38e15315ecc1b1c28911f1c9054d201f" - integrity sha512-6rPFqN1ABjn4shgOICGDBITTRV09EjXVqhDERBDKwCLz0UyBxeeBH6Ay0vQUJ84VACmlxwzOIzVEJXThcF3aNg== +puppeteer-core@20.9.0: + version "20.9.0" + resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-20.9.0.tgz#6f4b420001b64419deab38d398a4d9cd071040e6" + integrity sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg== dependencies: - debug "4.3.2" - devtools-protocol "0.0.901419" - extract-zip "2.0.1" - https-proxy-agent "5.0.0" - node-fetch "2.6.5" - pkg-dir "4.2.0" - progress "2.0.3" - proxy-from-env "1.1.0" - rimraf "3.0.2" - tar-fs "2.1.1" - unbzip2-stream "1.4.3" - ws "8.2.3" + "@puppeteer/browsers" "1.4.6" + chromium-bidi "0.4.16" + cross-fetch "4.0.0" + debug "4.3.4" + devtools-protocol "0.0.1147663" + ws "8.13.0" puppeteer@^17.1.3: version "17.1.3" @@ -11108,6 +12322,15 @@ puppeteer@^17.1.3: unbzip2-stream "1.4.3" ws "8.8.1" +puppeteer@^20.9.0: + version "20.9.0" + resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-20.9.0.tgz#7bfb9e37deab9728e13b02ea3fb499b5560c79a7" + integrity sha512-kAglT4VZ9fWEGg3oLc4/de+JcONuEJhlh3J6f5R1TLkrY/EHHIHxWXDOzXvaxQCtedmyVXBwg8M+P8YCO/wZjw== + dependencies: + "@puppeteer/browsers" "1.4.6" + cosmiconfig "8.2.0" + puppeteer-core "20.9.0" + puppeteer@^9.1.1: version "9.1.1" resolved "https://registry.npmjs.org/puppeteer/-/puppeteer-9.1.1.tgz" @@ -11126,6 +12349,11 @@ puppeteer@^9.1.1: unbzip2-stream "^1.3.3" ws "^7.2.3" +pure-rand@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.2.tgz#a9c2ddcae9b68d736a8163036f088a2781c8b306" + integrity sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ== + q@^1.1.2: version "1.5.1" resolved "https://registry.npmjs.org/q/-/q-1.5.1.tgz" @@ -11141,11 +12369,21 @@ qs@~6.5.2: resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +queue-tick@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142" + integrity sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag== + queue@6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/queue/-/queue-6.0.2.tgz#b91525283e2315c7553d2efa18d83e76432fed65" @@ -11251,6 +12489,11 @@ react-is@^17.0.1: resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + react-refresh@^0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e" @@ -11510,6 +12753,11 @@ require-relative@^0.8.7: resolved "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz" integrity sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4= +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz" @@ -11537,6 +12785,11 @@ resolve.exports@^1.1.0: resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz" integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== +resolve.exports@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" + integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== + resolve@1.1.7: version "1.1.7" resolved "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz" @@ -11839,7 +13092,7 @@ safe-stable-stringify@^2.1.0: resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.0.tgz#95fadb1bcf8057a1363e11052122f5da36a69215" integrity sha512-eehKHKpab6E741ud7ZIMcXhKcP6TSIezPkNZhy5U8xC6+VvrRdUA2tMgxGxaGl4cz7c2Ew5+mg5+wNB16KQqrA== -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -11856,6 +13109,13 @@ saxes@^5.0.1: dependencies: xmlchars "^2.2.0" +saxes@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-6.0.0.tgz#fe5b4a4768df4f14a201b1ba6a65c1f3d9988cc5" + integrity sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA== + dependencies: + xmlchars "^2.2.0" + scheduler@^0.23.0: version "0.23.0" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" @@ -11894,6 +13154,11 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + semver@^7.3.7: version "7.3.7" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" @@ -11901,6 +13166,13 @@ semver@^7.3.7: dependencies: lru-cache "^6.0.0" +semver@^7.5.3: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + semver@~7.3.0: version "7.3.8" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" @@ -12031,6 +13303,11 @@ signal-exit@^3.0.2, signal-exit@^3.0.3: resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== +signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + simple-peer-light@^9.10.0: version "9.10.0" resolved "https://registry.yarnpkg.com/simple-peer-light/-/simple-peer-light-9.10.0.tgz#6f3699b80e4b6d3a9374a865e1a8e497aa623afb" @@ -12079,6 +13356,11 @@ slash@^3.0.0: resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + smartwrap@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/smartwrap/-/smartwrap-2.0.2.tgz#7e25d3dd58b51c6ca4aba3a9e391650ea62698a4" @@ -12091,6 +13373,23 @@ smartwrap@^2.0.2: wcwidth "^1.0.1" yargs "^15.1.0" +socks-proxy-agent@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.1.tgz#ffc5859a66dac89b0c4dab90253b96705f3e7120" + integrity sha512-59EjPbbgg8U3x62hhKOFVAmySQUcfRQ4C7Q/D5sEHnZTQRrQlNKINks44DMR1gwXp0p4LaVIeccX2KHTTcHVqQ== + dependencies: + agent-base "^7.0.1" + debug "^4.3.4" + socks "^2.7.1" + +socks@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.1.tgz#d8e651247178fde79c0663043e07240196857d55" + integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ== + dependencies: + ip "^2.0.0" + smart-buffer "^4.2.0" + sonic-boom@^2.2.1: version "2.8.0" resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-2.8.0.tgz#c1def62a77425090e6ad7516aad8eb402e047611" @@ -12103,6 +13402,14 @@ source-map-js@^1.0.2: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-support@0.5.20: version "0.5.20" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" @@ -12275,6 +13582,14 @@ stream-transform@^2.1.3: dependencies: mixme "^0.5.1" +streamx@^2.15.0: + version "2.15.0" + resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.15.0.tgz#f58c92e6f726b5390dcabd6dd9094d29a854d698" + integrity sha512-HcxY6ncGjjklGs1xsP1aR71INYcsXFJet5CU1CHqihQ2J5nOsbd4OjgjHO42w/4QNv9gZb3BueV+Vxok5pLEXg== + dependencies: + fast-fifo "^1.1.0" + queue-tick "^1.0.1" + string-argv@~0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" @@ -12580,6 +13895,15 @@ tar-fs@2.1.1, tar-fs@^2.0.0: pump "^3.0.0" tar-stream "^2.1.4" +tar-fs@3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.4.tgz#a21dc60a2d5d9f55e0089ccd78124f1d3771dbbf" + integrity sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w== + dependencies: + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^3.1.5" + tar-stream@^2.1.4: version "2.2.0" resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz" @@ -12591,6 +13915,15 @@ tar-stream@^2.1.4: inherits "^2.0.3" readable-stream "^3.1.1" +tar-stream@^3.1.5: + version "3.1.6" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.6.tgz#6520607b55a06f4a2e2e04db360ba7d338cc5bab" + integrity sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg== + dependencies: + b4a "^1.6.4" + fast-fifo "^1.2.0" + streamx "^2.15.0" + term-size@^2.1.0: version "2.2.1" resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" @@ -12688,7 +14021,7 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" -tmpl@1.0.x: +tmpl@1.0.5, tmpl@1.0.x: version "1.0.5" resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz" integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== @@ -12739,6 +14072,16 @@ tough-cookie@^4.0.0: punycode "^2.1.1" universalify "^0.1.2" +tough-cookie@^4.1.2: + version "4.1.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" + integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.2.0" + url-parse "^1.5.3" + tough-cookie@~2.5.0: version "2.5.0" resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz" @@ -12754,6 +14097,13 @@ tr46@^2.1.0: dependencies: punycode "^2.1.1" +tr46@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" + integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA== + dependencies: + punycode "^2.1.1" + tr46@~0.0.3: version "0.0.3" resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" @@ -12804,6 +14154,20 @@ ts-jest@^27.1.3: semver "7.x" yargs-parser "20.x" +ts-jest@^29.1.1: + version "29.1.1" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.1.tgz#f58fe62c63caf7bfcc5cc6472082f79180f0815b" + integrity sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^29.0.0" + json5 "^2.2.3" + lodash.memoize "4.x" + make-error "1.x" + semver "^7.5.3" + yargs-parser "^21.0.1" + ts-morph@^16.0.0: version "16.0.0" resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-16.0.0.tgz#35caca7c286dd70e09e5f72af47536bf3b6a27af" @@ -12860,6 +14224,11 @@ tslib@^2.0.0, tslib@^2.2.0: resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz" integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== +tslib@^2.0.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410" + integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig== + tslib@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz" @@ -13129,6 +14498,11 @@ universalify@^0.1.0, universalify@^0.1.2: resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== + universalify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d" @@ -13163,6 +14537,14 @@ upath@2.0.1, upath@^2.0.1: resolved "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz" integrity sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w== +update-browserslist-db@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" + integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + update-browserslist-db@^1.0.9: version "1.0.9" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz#2924d3927367a38d5c555413a7ce138fc95fcb18" @@ -13205,6 +14587,14 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" +url-parse@^1.5.3: + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + use-callback-ref@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.0.tgz#772199899b9c9a50526fedc4993fc7fa1f7e32d5" @@ -13280,6 +14670,15 @@ v8-to-istanbul@^8.1.0: convert-source-map "^1.6.0" source-map "^0.7.3" +v8-to-istanbul@^9.0.1: + version "9.1.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz#1b83ed4e397f58c85c266a570fc2558b5feb9265" + integrity sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz" @@ -13379,6 +14778,13 @@ w3c-xmlserializer@^2.0.0: dependencies: xml-name-validator "^3.0.0" +w3c-xmlserializer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz#aebdc84920d806222936e3cdce408e32488a3073" + integrity sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw== + dependencies: + xml-name-validator "^4.0.0" + walker@^1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz" @@ -13386,6 +14792,13 @@ walker@^1.0.7: dependencies: makeerror "1.0.x" +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + watchpack@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.1.1.tgz#e99630550fca07df9f90a06056987baa40a689c7" @@ -13457,6 +14870,11 @@ webidl-conversions@^6.1.0: resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz" integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + whatwg-encoding@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz" @@ -13464,11 +14882,31 @@ whatwg-encoding@^1.0.5: dependencies: iconv-lite "0.4.24" +whatwg-encoding@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz#e7635f597fd87020858626805a2729fa7698ac53" + integrity sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg== + dependencies: + iconv-lite "0.6.3" + whatwg-mimetype@^2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== +whatwg-mimetype@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#5fa1a7623867ff1af6ca3dc72ad6b8a4208beba7" + integrity sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q== + +whatwg-url@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-11.0.0.tgz#0a849eebb5faf2119b901bb76fd795c2848d4018" + integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ== + dependencies: + tr46 "^3.0.0" + webidl-conversions "^7.0.0" + whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" @@ -13608,15 +15046,23 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + ws@7.4.6: version "7.4.6" resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== -ws@8.2.3: - version "8.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" - integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA== +ws@8.13.0, ws@^8.11.0: + version "8.13.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" + integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== ws@8.8.1: version "8.8.1" @@ -13648,6 +15094,11 @@ xml-name-validator@^3.0.0: resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== +xml-name-validator@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835" + integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw== + xml2js@~0.4.23: version "0.4.23" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" @@ -13681,6 +15132,11 @@ yallist@^2.1.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" integrity sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A== +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + yallist@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" @@ -13704,7 +15160,7 @@ yargs-parser@^18.1.2, yargs-parser@^18.1.3: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^21.0.0, yargs-parser@^21.1.1: +yargs-parser@^21.0.0, yargs-parser@^21.0.1, yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== @@ -13735,6 +15191,19 @@ yargs@17.4.0: y18n "^5.0.5" yargs-parser "^21.0.0" +yargs@17.7.1: + version "17.7.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.1.tgz#34a77645201d1a8fc5213ace787c220eabbd0967" + integrity sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yargs@^15.1.0: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" @@ -13765,6 +15234,19 @@ yargs@^17.1.1: y18n "^5.0.5" yargs-parser "^21.1.1" +yargs@^17.3.1: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yauzl@2.10.0, yauzl@^2.10.0: version "2.10.0" resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz" From 8a48e42378a2f3c4b72acb0a263895d632274728 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 7 Aug 2023 10:21:52 +0200 Subject: [PATCH 019/123] Version Packages (alpha) (#1252) Co-authored-by: github-actions[bot] --- .changeset/pre.json | 7 +++++++ packages/rrdom-nodejs/CHANGELOG.md | 8 ++++++++ packages/rrdom-nodejs/package.json | 6 +++--- packages/rrdom/CHANGELOG.md | 7 +++++++ packages/rrdom/package.json | 6 +++--- packages/rrvideo/CHANGELOG.md | 7 +++++++ packages/rrvideo/package.json | 6 +++--- packages/rrweb-player/CHANGELOG.md | 7 +++++++ packages/rrweb-player/package.json | 6 +++--- packages/rrweb-snapshot/CHANGELOG.md | 6 ++++++ packages/rrweb-snapshot/package.json | 2 +- packages/rrweb/CHANGELOG.md | 27 +++++++++++++++++++++++++++ packages/rrweb/package.json | 8 ++++---- packages/types/CHANGELOG.md | 12 ++++++++++++ packages/types/package.json | 4 ++-- packages/web-extension/CHANGELOG.md | 8 ++++++++ packages/web-extension/package.json | 8 ++++---- 17 files changed, 112 insertions(+), 23 deletions(-) diff --git a/.changeset/pre.json b/.changeset/pre.json index c9cc65e0ca..c9d02029ba 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -12,9 +12,12 @@ "rrvideo": "2.0.0-alpha.6" }, "changesets": [ + "attribute-text-reductions", "brave-numbers-joke", "calm-bulldogs-speak", "chatty-cherries-train", + "clean-plants-play", + "clean-shrimps-lay", "cold-eyes-hunt", "controller-finish-flag", "date-now-guard", @@ -38,6 +41,7 @@ "lovely-students-boil", "mean-tips-impress", "mighty-frogs-sparkle", + "nervous-buses-pump", "nervous-poets-grin", "nervous-tables-travel", "new-snakes-call", @@ -55,7 +59,10 @@ "smooth-poems-bake", "stupid-ghosts-help", "swift-peas-film", + "thirty-baboons-punch", "tidy-yaks-joke", + "tiny-buckets-love", + "tiny-chairs-build", "tricky-panthers-guess", "twenty-lies-switch", "twenty-planets-repeat", diff --git a/packages/rrdom-nodejs/CHANGELOG.md b/packages/rrdom-nodejs/CHANGELOG.md index 4fe4518e12..b69007b8e5 100644 --- a/packages/rrdom-nodejs/CHANGELOG.md +++ b/packages/rrdom-nodejs/CHANGELOG.md @@ -1,5 +1,13 @@ # rrdom-nodejs +## 2.0.0-alpha.10 + +### Patch Changes + +- Updated dependencies [[`c6600e7`](https://github.com/rrweb-io/rrweb/commit/c6600e742b8ec0b6295816bb5de9edcd624d975e)]: + - rrweb-snapshot@2.0.0-alpha.10 + - rrdom@2.0.0-alpha.10 + ## 2.0.0-alpha.9 ### Patch Changes diff --git a/packages/rrdom-nodejs/package.json b/packages/rrdom-nodejs/package.json index 9e2b8d23b2..395710dd00 100644 --- a/packages/rrdom-nodejs/package.json +++ b/packages/rrdom-nodejs/package.json @@ -1,6 +1,6 @@ { "name": "rrdom-nodejs", - "version": "2.0.0-alpha.9", + "version": "2.0.0-alpha.10", "scripts": { "dev": "rollup -c -w", "bundle": "rollup --config", @@ -48,8 +48,8 @@ "cssom": "^0.5.0", "cssstyle": "^2.3.0", "nwsapi": "^2.2.0", - "rrdom": "^2.0.0-alpha.9", - "rrweb-snapshot": "^2.0.0-alpha.9" + "rrdom": "^2.0.0-alpha.10", + "rrweb-snapshot": "^2.0.0-alpha.10" }, "browserslist": [ "supports es6-class" diff --git a/packages/rrdom/CHANGELOG.md b/packages/rrdom/CHANGELOG.md index fcfd27dd0c..4c94a15108 100644 --- a/packages/rrdom/CHANGELOG.md +++ b/packages/rrdom/CHANGELOG.md @@ -1,5 +1,12 @@ # rrdom +## 2.0.0-alpha.10 + +### Patch Changes + +- Updated dependencies [[`c6600e7`](https://github.com/rrweb-io/rrweb/commit/c6600e742b8ec0b6295816bb5de9edcd624d975e)]: + - rrweb-snapshot@2.0.0-alpha.10 + ## 2.0.0-alpha.9 ### Patch Changes diff --git a/packages/rrdom/package.json b/packages/rrdom/package.json index 04bbbbad0a..d2e52e1599 100644 --- a/packages/rrdom/package.json +++ b/packages/rrdom/package.json @@ -1,6 +1,6 @@ { "name": "rrdom", - "version": "2.0.0-alpha.9", + "version": "2.0.0-alpha.10", "homepage": "https://github.com/rrweb-io/rrweb/tree/main/packages/rrdom#readme", "license": "MIT", "main": "lib/rrdom.cjs", @@ -32,7 +32,7 @@ }, "devDependencies": { "@rollup/plugin-commonjs": "^20.0.0", - "@rrweb/types": "^2.0.0-alpha.9", + "@rrweb/types": "^2.0.0-alpha.10", "@types/jest": "^27.4.1", "@types/puppeteer": "^5.4.4", "@typescript-eslint/eslint-plugin": "^5.23.0", @@ -47,6 +47,6 @@ "ts-jest": "^27.1.3" }, "dependencies": { - "rrweb-snapshot": "^2.0.0-alpha.9" + "rrweb-snapshot": "^2.0.0-alpha.10" } } diff --git a/packages/rrvideo/CHANGELOG.md b/packages/rrvideo/CHANGELOG.md index c603c1d329..a6ce3f2fe6 100644 --- a/packages/rrvideo/CHANGELOG.md +++ b/packages/rrvideo/CHANGELOG.md @@ -1,5 +1,12 @@ # rrvideo +## 2.0.0-alpha.10 + +### Patch Changes + +- Updated dependencies []: + - rrweb-player@2.0.0-alpha.10 + ## 2.0.0-alpha.9 ### Patch Changes diff --git a/packages/rrvideo/package.json b/packages/rrvideo/package.json index c654da461f..c7d64b7c76 100644 --- a/packages/rrvideo/package.json +++ b/packages/rrvideo/package.json @@ -1,6 +1,6 @@ { "name": "rrvideo", - "version": "2.0.0-alpha.9", + "version": "2.0.0-alpha.10", "description": "transform rrweb session into video", "main": "build/index.js", "bin": { @@ -26,13 +26,13 @@ "@types/node": "^18.15.11", "jest": "^27.5.1", "ts-jest": "^27.1.3", - "@rrweb/types": "^2.0.0-alpha.9" + "@rrweb/types": "^2.0.0-alpha.10" }, "dependencies": { "@open-tech-world/cli-progress-bar": "^2.0.2", "fs-extra": "^11.1.1", "minimist": "^1.2.5", "playwright": "^1.32.1", - "rrweb-player": "^2.0.0-alpha.9" + "rrweb-player": "^2.0.0-alpha.10" } } diff --git a/packages/rrweb-player/CHANGELOG.md b/packages/rrweb-player/CHANGELOG.md index 6c5cfe50fe..c9be0dc3ad 100644 --- a/packages/rrweb-player/CHANGELOG.md +++ b/packages/rrweb-player/CHANGELOG.md @@ -1,5 +1,12 @@ # rrweb-player +## 2.0.0-alpha.10 + +### Patch Changes + +- Updated dependencies [[`7103625`](https://github.com/rrweb-io/rrweb/commit/7103625b4683cbd75732ee03973e38f573847b1c), [`d872d28`](https://github.com/rrweb-io/rrweb/commit/d872d2809e3ec8d6ff5d3d5f43bc81aff70e7548), [`36da39d`](https://github.com/rrweb-io/rrweb/commit/36da39db366a9f80c28549771ed331090a1c6647), [`bbbfa22`](https://github.com/rrweb-io/rrweb/commit/bbbfa226fc5882a01ecc1607b713f0caf797775e), [`d0fbe23`](https://github.com/rrweb-io/rrweb/commit/d0fbe23c632021410a6dd45f9028a9a012467261), [`a3de582`](https://github.com/rrweb-io/rrweb/commit/a3de582e9c32be9e0ccd84bb7df756af6b0594f7)]: + - rrweb@2.0.0-alpha.10 + ## 2.0.0-alpha.9 ### Patch Changes diff --git a/packages/rrweb-player/package.json b/packages/rrweb-player/package.json index 5536cc6b12..99b04790fd 100644 --- a/packages/rrweb-player/package.json +++ b/packages/rrweb-player/package.json @@ -1,10 +1,10 @@ { "name": "rrweb-player", - "version": "2.0.0-alpha.9", + "version": "2.0.0-alpha.10", "devDependencies": { "@rollup/plugin-commonjs": "^22.0.0", "@rollup/plugin-node-resolve": "^13.2.1", - "@rrweb/types": "^2.0.0-alpha.9", + "@rrweb/types": "^2.0.0-alpha.10", "@types/offscreencanvas": "^2019.6.4", "eslint-config-google": "^0.14.0", "eslint-plugin-svelte3": "^4.0.0", @@ -24,7 +24,7 @@ }, "dependencies": { "@tsconfig/svelte": "^1.0.0", - "rrweb": "^2.0.0-alpha.9" + "rrweb": "^2.0.0-alpha.10" }, "scripts": { "build": "rollup -c", diff --git a/packages/rrweb-snapshot/CHANGELOG.md b/packages/rrweb-snapshot/CHANGELOG.md index 3ac44a0032..2491fca4dd 100644 --- a/packages/rrweb-snapshot/CHANGELOG.md +++ b/packages/rrweb-snapshot/CHANGELOG.md @@ -1,5 +1,11 @@ # rrweb-snapshot +## 2.0.0-alpha.10 + +### Patch Changes + +- [#1253](https://github.com/rrweb-io/rrweb/pull/1253) [`c6600e7`](https://github.com/rrweb-io/rrweb/commit/c6600e742b8ec0b6295816bb5de9edcd624d975e) Thanks [@mydea](https://github.com/mydea)! - Fix CSS rules captured in Safari + ## 2.0.0-alpha.9 ### Patch Changes diff --git a/packages/rrweb-snapshot/package.json b/packages/rrweb-snapshot/package.json index 4fc2fda5d6..e77df133be 100644 --- a/packages/rrweb-snapshot/package.json +++ b/packages/rrweb-snapshot/package.json @@ -1,6 +1,6 @@ { "name": "rrweb-snapshot", - "version": "2.0.0-alpha.9", + "version": "2.0.0-alpha.10", "description": "rrweb's component to take a snapshot of DOM, aka DOM serializer", "scripts": { "prepare": "npm run prepack", diff --git a/packages/rrweb/CHANGELOG.md b/packages/rrweb/CHANGELOG.md index 7eed53c2b3..65b460cda5 100644 --- a/packages/rrweb/CHANGELOG.md +++ b/packages/rrweb/CHANGELOG.md @@ -1,5 +1,32 @@ # rrweb +## 2.0.0-alpha.10 + +### Patch Changes + +- [#1269](https://github.com/rrweb-io/rrweb/pull/1269) [`7103625`](https://github.com/rrweb-io/rrweb/commit/7103625b4683cbd75732ee03973e38f573847b1c) Thanks [@eoghanmurray](https://github.com/eoghanmurray)! - Don't include redundant data from text/attribute mutations on just-added nodes + +- [#1268](https://github.com/rrweb-io/rrweb/pull/1268) [`d872d28`](https://github.com/rrweb-io/rrweb/commit/d872d2809e3ec8d6ff5d3d5f43bc81aff70e7548) Thanks [@eoghanmurray](https://github.com/eoghanmurray)! - Compact style mutation fixes and improvements + + - fixes when style updates contain a 'var()' on a shorthand property #1246 + - further ensures that style mutations are compact by reverting to string method if it is shorter + +- [#1262](https://github.com/rrweb-io/rrweb/pull/1262) [`36da39d`](https://github.com/rrweb-io/rrweb/commit/36da39db366a9f80c28549771ed331090a1c6647) Thanks [@billyvg](https://github.com/billyvg)! - feat: Add `ignoreSelector` option + + Similar to ignoreClass, but accepts a CSS selector so that you can use any CSS selector. + +- [#1251](https://github.com/rrweb-io/rrweb/pull/1251) [`bbbfa22`](https://github.com/rrweb-io/rrweb/commit/bbbfa226fc5882a01ecc1607b713f0caf797775e) Thanks [@wfk007](https://github.com/wfk007)! - fix: Resize and MediaInteraction events repeat generated after the iframe appeared + +- [#1254](https://github.com/rrweb-io/rrweb/pull/1254) [`d0fbe23`](https://github.com/rrweb-io/rrweb/commit/d0fbe23c632021410a6dd45f9028a9a012467261) Thanks [@mydea](https://github.com/mydea)! - Handle case where `event` is null/undefined + +- [#1273](https://github.com/rrweb-io/rrweb/pull/1273) [`a3de582`](https://github.com/rrweb-io/rrweb/commit/a3de582e9c32be9e0ccd84bb7df756af6b0594f7) Thanks [@Juice10](https://github.com/Juice10)! - Canvas FPS recording: override `preserveDrawingBuffer: true` on canvas creation. + Canvas replay: fix flickering canvas elemenrs. + Canvas FPS recording: fix bug that wipes webgl(2) canvas backgrounds while recording. +- Updated dependencies [[`d872d28`](https://github.com/rrweb-io/rrweb/commit/d872d2809e3ec8d6ff5d3d5f43bc81aff70e7548), [`c6600e7`](https://github.com/rrweb-io/rrweb/commit/c6600e742b8ec0b6295816bb5de9edcd624d975e)]: + - @rrweb/types@2.0.0-alpha.10 + - rrweb-snapshot@2.0.0-alpha.10 + - rrdom@2.0.0-alpha.10 + ## 2.0.0-alpha.9 ### Patch Changes diff --git a/packages/rrweb/package.json b/packages/rrweb/package.json index ebca356d79..2b6287486e 100644 --- a/packages/rrweb/package.json +++ b/packages/rrweb/package.json @@ -1,6 +1,6 @@ { "name": "rrweb", - "version": "2.0.0-alpha.9", + "version": "2.0.0-alpha.10", "description": "record and replay the web", "scripts": { "prepare": "npm run prepack", @@ -81,13 +81,13 @@ "tslib": "^2.3.1" }, "dependencies": { - "@rrweb/types": "^2.0.0-alpha.9", + "@rrweb/types": "^2.0.0-alpha.10", "@types/css-font-loading-module": "0.0.7", "@xstate/fsm": "^1.4.0", "base64-arraybuffer": "^1.0.1", "fflate": "^0.4.4", "mitt": "^3.0.0", - "rrdom": "^2.0.0-alpha.9", - "rrweb-snapshot": "^2.0.0-alpha.9" + "rrdom": "^2.0.0-alpha.10", + "rrweb-snapshot": "^2.0.0-alpha.10" } } diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index c25deee87b..5f6c542c6a 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -1,5 +1,17 @@ # @rrweb/types +## 2.0.0-alpha.10 + +### Patch Changes + +- [#1268](https://github.com/rrweb-io/rrweb/pull/1268) [`d872d28`](https://github.com/rrweb-io/rrweb/commit/d872d2809e3ec8d6ff5d3d5f43bc81aff70e7548) Thanks [@eoghanmurray](https://github.com/eoghanmurray)! - Compact style mutation fixes and improvements + + - fixes when style updates contain a 'var()' on a shorthand property #1246 + - further ensures that style mutations are compact by reverting to string method if it is shorter + +- Updated dependencies [[`c6600e7`](https://github.com/rrweb-io/rrweb/commit/c6600e742b8ec0b6295816bb5de9edcd624d975e)]: + - rrweb-snapshot@2.0.0-alpha.10 + ## 2.0.0-alpha.9 ### Patch Changes diff --git a/packages/types/package.json b/packages/types/package.json index c438396a99..67685c1175 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@rrweb/types", - "version": "2.0.0-alpha.9", + "version": "2.0.0-alpha.10", "publishConfig": { "access": "public" }, @@ -43,7 +43,7 @@ "vite-plugin-dts": "^1.6.6" }, "dependencies": { - "rrweb-snapshot": "^2.0.0-alpha.9" + "rrweb-snapshot": "^2.0.0-alpha.10" }, "browserslist": [ "supports es6-class" diff --git a/packages/web-extension/CHANGELOG.md b/packages/web-extension/CHANGELOG.md index 92661a43ac..5553a9f813 100644 --- a/packages/web-extension/CHANGELOG.md +++ b/packages/web-extension/CHANGELOG.md @@ -1,5 +1,13 @@ # @rrweb/web-extension +## 2.0.0-alpha.10 + +### Patch Changes + +- Updated dependencies [[`7103625`](https://github.com/rrweb-io/rrweb/commit/7103625b4683cbd75732ee03973e38f573847b1c), [`d872d28`](https://github.com/rrweb-io/rrweb/commit/d872d2809e3ec8d6ff5d3d5f43bc81aff70e7548), [`36da39d`](https://github.com/rrweb-io/rrweb/commit/36da39db366a9f80c28549771ed331090a1c6647), [`bbbfa22`](https://github.com/rrweb-io/rrweb/commit/bbbfa226fc5882a01ecc1607b713f0caf797775e), [`d0fbe23`](https://github.com/rrweb-io/rrweb/commit/d0fbe23c632021410a6dd45f9028a9a012467261), [`a3de582`](https://github.com/rrweb-io/rrweb/commit/a3de582e9c32be9e0ccd84bb7df756af6b0594f7)]: + - rrweb@2.0.0-alpha.10 + - rrweb-player@2.0.0-alpha.10 + ## 2.0.0-alpha.9 ### Patch Changes diff --git a/packages/web-extension/package.json b/packages/web-extension/package.json index 2e438d485a..78ad204937 100644 --- a/packages/web-extension/package.json +++ b/packages/web-extension/package.json @@ -1,7 +1,7 @@ { "name": "@rrweb/web-extension", "private": true, - "version": "2.0.0-alpha.9", + "version": "2.0.0-alpha.10", "description": "The web extension of rrweb which helps to run rrweb on any website out of box", "author": "rrweb-io", "license": "MIT", @@ -16,7 +16,7 @@ "prepublish": "npm run pack:chrome && npm run pack:firefox" }, "devDependencies": { - "@rrweb/types": "^2.0.0-alpha.9", + "@rrweb/types": "^2.0.0-alpha.10", "@types/react-dom": "^18.0.6", "@types/webextension-polyfill": "^0.9.1", "@vitejs/plugin-react": "^2.1.0", @@ -40,7 +40,7 @@ "react-dom": "^18.2.0", "react-icons": "^4.4.0", "react-router-dom": "^6.4.1", - "rrweb": "^2.0.0-alpha.9", - "rrweb-player": "^2.0.0-alpha.9" + "rrweb": "^2.0.0-alpha.10", + "rrweb-player": "^2.0.0-alpha.10" } } From 5f179705d50671f9e4027a1cb72a35057a51d7dd Mon Sep 17 00:00:00 2001 From: Sahil Gupta Date: Tue, 8 Aug 2023 19:18:55 +0530 Subject: [PATCH 020/123] Added requestly in who's using rrweb section (#1278) --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 697cbcdabb..d11eade21c 100644 --- a/README.md +++ b/README.md @@ -220,4 +220,11 @@ In addition to adding integration tests and unit tests, rrweb also provides a RE + + + + Intercept, Modify, Record & Replay HTTP Requests. + + + From b01297373b820a8a3eca40743aabeb85a3df9245 Mon Sep 17 00:00:00 2001 From: Yun Feng Date: Thu, 10 Aug 2023 16:37:20 +0800 Subject: [PATCH 021/123] doc: update sponsor list and company list (#1282) * doc: update sponsor list and company list * Apply formatting changes * Apply formatting changes * Create khaki-dots-bathe.md * Apply formatting changes * Apply formatting changes --------- Co-authored-by: YunFeng0817 Co-authored-by: Justin Halsall --- .changeset/khaki-dots-bathe.md | 2 ++ README.md | 18 +++++++-------- README.zh_CN.md | 40 +++++++++++++++++++++++++++++++--- 3 files changed, 48 insertions(+), 12 deletions(-) create mode 100644 .changeset/khaki-dots-bathe.md diff --git a/.changeset/khaki-dots-bathe.md b/.changeset/khaki-dots-bathe.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/khaki-dots-bathe.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/README.md b/README.md index d11eade21c..d198499df9 100644 --- a/README.md +++ b/README.md @@ -110,15 +110,15 @@ In addition to adding integration tests and unit tests, rrweb also provides a RE
-sponsor -sponsor -sponsor -sponsor -sponsor -sponsor -sponsor -sponsor -sponsor +sponsor +sponsor +sponsor +sponsor +sponsor +sponsor +sponsor +sponsor +sponsor
diff --git a/README.zh_CN.md b/README.zh_CN.md index 6d37bbb19b..ffb90c581d 100644 --- a/README.zh_CN.md +++ b/README.zh_CN.md @@ -119,17 +119,51 @@ rrweb 主要由 3 部分组成: - + - + - + + + + + + The first ever UX automation tool + + + + + + + Smart screen recording for SaaS + + + + + Remote Access & Co-Browsing + + + + + The open source, fullstack Monitoring Platform. + + + + + Comprehensive data analytics platform that empowers businesses to gain valuable insights and make data-driven decisions. + + + + + + + Intercept, Modify, Record & Replay HTTP Requests. From 11f6567fd81ef9ed0f954a7b6d5e39653f56004f Mon Sep 17 00:00:00 2001 From: Eoghan Murray Date: Fri, 11 Aug 2023 14:19:33 +0100 Subject: [PATCH 022/123] Extend to run fixBrowserCompatibilityIssuesInCSS over inline stylesheets (#1279) * Extend to run fixBrowserCompatibilityIssuesInCSS over styles in inline style sheets * Apply formatting changes --------- Co-authored-by: eoghanmurray --- .changeset/curvy-apples-lay.md | 6 ++++++ packages/rrweb-snapshot/src/snapshot.ts | 12 +----------- yarn.lock | 7 ++++++- 3 files changed, 13 insertions(+), 12 deletions(-) create mode 100644 .changeset/curvy-apples-lay.md diff --git a/.changeset/curvy-apples-lay.md b/.changeset/curvy-apples-lay.md new file mode 100644 index 0000000000..9072a2ad25 --- /dev/null +++ b/.changeset/curvy-apples-lay.md @@ -0,0 +1,6 @@ +--- +'rrweb-snapshot': patch +'rrweb': patch +--- + +Extend to run fixBrowserCompatibilityIssuesInCSS over inline stylesheets diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index bb18542d26..6acb1c250a 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -51,16 +51,6 @@ function getValidTagName(element: HTMLElement): Lowercase { return processedTagName; } -function stringifyStyleSheet(sheet: CSSStyleSheet): string { - return sheet.cssRules - ? Array.from(sheet.cssRules) - .map((rule) => - rule.cssText ? validateStringifiedCssRule(rule.cssText) : '', - ) - .join('') - : ''; -} - function extractOrigin(url: string): string { let origin = ''; if (url.indexOf('//') > -1) { @@ -564,7 +554,7 @@ function serializeTextNode( // to _only_ include the current rule(s) added by the text node. // So we'll be conservative and keep textContent as-is. } else if ((n.parentNode as HTMLStyleElement).sheet?.cssRules) { - textContent = stringifyStyleSheet( + textContent = getCssRulesString( (n.parentNode as HTMLStyleElement).sheet!, ); } diff --git a/yarn.lock b/yarn.lock index f579e11c04..c26d4e9233 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5503,10 +5503,15 @@ csso@^4.0.2: dependencies: css-tree "^1.1.2" -cssom@^0.4.4, cssom@^0.5.0, "cssom@https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz": +cssom@^0.4.4, "cssom@https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz": version "0.6.0" resolved "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz#ed298055b97cbddcdeb278f904857629dec5e0e1" +cssom@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.5.0.tgz#d254fa92cd8b6fbd83811b9fbaed34663cc17c36" + integrity sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw== + cssom@~0.3.6: version "0.3.8" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" From efdc167ca6c039d04af83612e3d92498bb9b41a7 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Fri, 11 Aug 2023 17:58:42 +0200 Subject: [PATCH 023/123] Add workaround for Chrome/Edge css import escaping bug (#1287) * Upgrade to typescript 4.9.5 * Apply formatting changes * Add workaround for chrome incorrect escaping bug More info: https://bugs.chromium.org/p/chromium/issues/detail?id=1472259 * Apply formatting changes * Create itchy-dryers-double.md * Create rich-jars-remember.md * Apply formatting changes * Update packages/rrweb-snapshot/src/css.ts * Apply formatting changes * Update packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap * Apply formatting changes * Update snapshot * Apply formatting changes * Rename and refactor fixBrowserCompatibilityIssuesInCSSImports, getCssRulesString and getCssRuleString based on @eoghanmurray feedback * Apply formatting changes * Apply formatting changes --- .changeset/itchy-dryers-double.md | 8 + .changeset/rich-jars-remember.md | 5 + package.json | 5 +- packages/rrweb-player/package.json | 6 +- packages/rrweb-snapshot/src/css.ts | 4 +- packages/rrweb-snapshot/src/snapshot.ts | 8 +- packages/rrweb-snapshot/src/utils.ts | 59 +++- .../__snapshots__/integration.test.ts.snap | 2 +- packages/rrweb-snapshot/test/css.test.ts | 65 +++- .../test/css/style-with-import.css | 3 +- packages/rrweb/package.json | 2 +- .../src/record/constructable-stylesheets.d.ts | 10 - .../src/record/observers/canvas/canvas.ts | 6 +- .../record/observers/canvas/serialize-args.ts | 2 +- .../src/record/observers/canvas/webgl.ts | 5 +- .../rrweb/src/record/stylesheet-manager.ts | 4 +- packages/types/package.json | 2 +- yarn.lock | 303 +++++++++++------- 18 files changed, 343 insertions(+), 156 deletions(-) create mode 100644 .changeset/itchy-dryers-double.md create mode 100644 .changeset/rich-jars-remember.md delete mode 100644 packages/rrweb/src/record/constructable-stylesheets.d.ts diff --git a/.changeset/itchy-dryers-double.md b/.changeset/itchy-dryers-double.md new file mode 100644 index 0000000000..67fc6f6e36 --- /dev/null +++ b/.changeset/itchy-dryers-double.md @@ -0,0 +1,8 @@ +--- +'rrweb-player': patch +'rrweb-snapshot': patch +'rrweb': patch +'@rrweb/types': patch +--- + +Upgrade all projects to typescript 4.9.5 diff --git a/.changeset/rich-jars-remember.md b/.changeset/rich-jars-remember.md new file mode 100644 index 0000000000..efa613f772 --- /dev/null +++ b/.changeset/rich-jars-remember.md @@ -0,0 +1,5 @@ +--- +'rrweb-snapshot': patch +--- + +Add workaround for Chrome/Edge CSS `@import` escaping bug: https://bugs.chromium.org/p/chromium/issues/detail?id=1472259 diff --git a/package.json b/package.json index 3e7cb6027c..e6669ce15c 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "markdownlint-cli": "^0.31.1", "prettier": "2.8.4", "turbo": "^1.2.4", - "typescript": "^4.7.3" + "typescript": "^4.9.5" }, "scripts": { "build:all": "NODE_OPTIONS='--max-old-space-size=4096' yarn run concurrently --success=all -r -m=1 'yarn workspaces-to-typescript-project-references' 'yarn turbo run prepublish'", @@ -49,7 +49,8 @@ "release": "yarn build:all && changeset publish" }, "resolutions": { - "**/jsdom/cssom": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz" + "**/jsdom/cssom": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "**/@types/dom-webcodecs": "0.1.5" }, "browserslist": [ "defaults", diff --git a/packages/rrweb-player/package.json b/packages/rrweb-player/package.json index 99b04790fd..a6e289640c 100644 --- a/packages/rrweb-player/package.json +++ b/packages/rrweb-player/package.json @@ -17,9 +17,9 @@ "rollup-plugin-typescript2": "^0.31.2", "rollup-plugin-web-worker-loader": "^1.6.1", "sirv-cli": "^0.4.4", - "svelte": "^3.2.0", - "svelte-check": "^1.4.0", - "svelte-preprocess": "^4.0.0", + "svelte": "^3.59.2", + "svelte-check": "^3.0.1", + "svelte-preprocess": "^5.0.0", "tslib": "^2.0.0" }, "dependencies": { diff --git a/packages/rrweb-snapshot/src/css.ts b/packages/rrweb-snapshot/src/css.ts index e646f58d19..d7a413eb67 100644 --- a/packages/rrweb-snapshot/src/css.ts +++ b/packages/rrweb-snapshot/src/css.ts @@ -345,7 +345,7 @@ export function parse(css: string, options: ParserOptions = {}) { whitespace(); comments(rules); while (css.length && css.charAt(0) !== '}' && (node = atrule() || rule())) { - if (node !== false) { + if (node) { rules.push(node); comments(rules); } @@ -383,7 +383,7 @@ export function parse(css: string, options: ParserOptions = {}) { function comments(rules: Rule[] = []) { let c: Comment | void; while ((c = comment())) { - if (c !== false) { + if (c) { rules.push(c); } c = comment(); diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index 6acb1c250a..51e764ced7 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -19,7 +19,7 @@ import { isShadowRoot, maskInputValue, isNativeShadowDom, - getCssRulesString, + stringifyStylesheet, getInputType, toLowerCase, validateStringifiedCssRule, @@ -554,7 +554,7 @@ function serializeTextNode( // to _only_ include the current rule(s) added by the text node. // So we'll be conservative and keep textContent as-is. } else if ((n.parentNode as HTMLStyleElement).sheet?.cssRules) { - textContent = getCssRulesString( + textContent = stringifyStylesheet( (n.parentNode as HTMLStyleElement).sheet!, ); } @@ -644,7 +644,7 @@ function serializeElementNode( }); let cssText: string | null = null; if (stylesheet) { - cssText = getCssRulesString(stylesheet); + cssText = stringifyStylesheet(stylesheet); } if (cssText) { delete attributes.rel; @@ -659,7 +659,7 @@ function serializeElementNode( // TODO: Currently we only try to get dynamic stylesheet when it is an empty style element !(n.innerText || n.textContent || '').trim().length ) { - const cssText = getCssRulesString( + const cssText = stringifyStylesheet( (n as HTMLStyleElement).sheet as CSSStyleSheet, ); if (cssText) { diff --git a/packages/rrweb-snapshot/src/utils.ts b/packages/rrweb-snapshot/src/utils.ts index 06e3b7a010..2b432459d6 100644 --- a/packages/rrweb-snapshot/src/utils.ts +++ b/packages/rrweb-snapshot/src/utils.ts @@ -54,12 +54,51 @@ function fixBrowserCompatibilityIssuesInCSS(cssText: string): string { return cssText; } -export function getCssRulesString(s: CSSStyleSheet): string | null { +// Remove this declaration once typescript has added `CSSImportRule.supportsText` to the lib. +declare interface CSSImportRule extends CSSRule { + readonly href: string; + readonly layerName: string | null; + readonly media: MediaList; + readonly styleSheet: CSSStyleSheet; + /** + * experimental API, currently only supported in firefox + * https://developer.mozilla.org/en-US/docs/Web/API/CSSImportRule/supportsText + */ + readonly supportsText?: string | null; +} + +/** + * Browsers sometimes incorrectly escape `@import` on `.cssText` statements. + * This function tries to correct the escaping. + * more info: https://bugs.chromium.org/p/chromium/issues/detail?id=1472259 + * @param cssImportRule + * @returns `cssText` with browser inconsistencies fixed, or null if not applicable. + */ +export function escapeImportStatement(rule: CSSImportRule): string { + const { cssText } = rule; + if (cssText.split('"').length < 3) return cssText; + + const statement = ['@import', `url(${JSON.stringify(rule.href)})`]; + if (rule.layerName === '') { + statement.push(`layer`); + } else if (rule.layerName) { + statement.push(`layer(${rule.layerName})`); + } + if (rule.supportsText) { + statement.push(`supports(${rule.supportsText})`); + } + if (rule.media.length) { + statement.push(rule.media.mediaText); + } + return statement.join(' ') + ';'; +} + +export function stringifyStylesheet(s: CSSStyleSheet): string | null { try { const rules = s.rules || s.cssRules; return rules ? fixBrowserCompatibilityIssuesInCSS( - Array.from(rules).map(getCssRuleString).join(''), + Array.from(rules).map(stringifyRule).join(''), ) : null; } catch (error) { @@ -67,16 +106,22 @@ export function getCssRulesString(s: CSSStyleSheet): string | null { } } -export function getCssRuleString(rule: CSSRule): string { - let cssStringified = rule.cssText; +export function stringifyRule(rule: CSSRule): string { + let importStringified; if (isCSSImportRule(rule)) { try { - cssStringified = getCssRulesString(rule.styleSheet) || cssStringified; - } catch { + importStringified = + // for same-origin stylesheets, + // we can access the imported stylesheet rules directly + stringifyStylesheet(rule.styleSheet) || + // work around browser issues with the raw string `@import url(...)` statement + escapeImportStatement(rule); + } catch (error) { // ignore } } - return validateStringifiedCssRule(cssStringified); + + return validateStringifiedCssRule(importStringified || rule.cssText); } export function validateStringifiedCssRule(cssStringified: string): string { diff --git a/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap b/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap index 529a51eeff..a50f27cebe 100644 --- a/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap +++ b/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap @@ -490,7 +490,7 @@ exports[`integration tests [html file]: with-style-sheet-with-import.html 1`] = with style sheet with import - + " `; diff --git a/packages/rrweb-snapshot/test/css.test.ts b/packages/rrweb-snapshot/test/css.test.ts index 328ecc77d6..6599839de4 100644 --- a/packages/rrweb-snapshot/test/css.test.ts +++ b/packages/rrweb-snapshot/test/css.test.ts @@ -1,5 +1,8 @@ import { parse, Rule, Media } from '../src/css'; -import { validateStringifiedCssRule } from './../src/utils'; +import { + validateStringifiedCssRule, + escapeImportStatement, +} from './../src/utils'; describe('css parser', () => { it('should save the filename and source', () => { @@ -120,4 +123,64 @@ describe('css parser', () => { ); expect(out3).toEqual('[data-aa\\:other] { color: red; }'); }); + + it('parses imports with quotes correctly', () => { + const out1 = escapeImportStatement({ + cssText: `@import url("/foo.css;900;800"");`, + href: '/foo.css;900;800"', + media: { + length: 0, + }, + layerName: null, + supportsText: null, + } as unknown as CSSImportRule); + expect(out1).toEqual(`@import url("/foo.css;900;800\\"");`); + + const out2 = escapeImportStatement({ + cssText: `@import url("/foo.css;900;800"") supports(display: flex);`, + href: '/foo.css;900;800"', + media: { + length: 0, + }, + layerName: null, + supportsText: 'display: flex', + } as unknown as CSSImportRule); + expect(out2).toEqual( + `@import url("/foo.css;900;800\\"") supports(display: flex);`, + ); + + const out3 = escapeImportStatement({ + cssText: `@import url("/foo.css;900;800"");`, + href: '/foo.css;900;800"', + media: { + length: 1, + mediaText: 'print, screen', + }, + layerName: null, + supportsText: null, + } as unknown as CSSImportRule); + expect(out3).toEqual(`@import url("/foo.css;900;800\\"") print, screen;`); + + const out4 = escapeImportStatement({ + cssText: `@import url("/foo.css;900;800"") layer(layer-1);`, + href: '/foo.css;900;800"', + media: { + length: 0, + }, + layerName: 'layer-1', + supportsText: null, + } as unknown as CSSImportRule); + expect(out4).toEqual(`@import url("/foo.css;900;800\\"") layer(layer-1);`); + + const out5 = escapeImportStatement({ + cssText: `@import url("/foo.css;900;800"") layer;`, + href: '/foo.css;900;800"', + media: { + length: 0, + }, + layerName: '', + supportsText: null, + } as unknown as CSSImportRule); + expect(out5).toEqual(`@import url("/foo.css;900;800\\"") layer;`); + }); }); diff --git a/packages/rrweb-snapshot/test/css/style-with-import.css b/packages/rrweb-snapshot/test/css/style-with-import.css index 61058d7b1e..5fa59d8039 100644 --- a/packages/rrweb-snapshot/test/css/style-with-import.css +++ b/packages/rrweb-snapshot/test/css/style-with-import.css @@ -1 +1,2 @@ -@import "./style.css"; +@import '//fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&family=Roboto:wght@100;300;400;500;700&display=swap"'; +@import './style.css'; diff --git a/packages/rrweb/package.json b/packages/rrweb/package.json index 2b6287486e..22a91a411a 100644 --- a/packages/rrweb/package.json +++ b/packages/rrweb/package.json @@ -51,7 +51,7 @@ "devDependencies": { "@rollup/plugin-node-resolve": "^13.1.3", "@types/chai": "^4.1.6", - "@types/dom-mediacapture-transform": "^0.1.3", + "@types/dom-mediacapture-transform": "0.1.4", "@types/inquirer": "^8.2.1", "@types/jest": "^29.5.0", "@types/jest-image-snapshot": "^6.1.0", diff --git a/packages/rrweb/src/record/constructable-stylesheets.d.ts b/packages/rrweb/src/record/constructable-stylesheets.d.ts deleted file mode 100644 index 8545dfdfd4..0000000000 --- a/packages/rrweb/src/record/constructable-stylesheets.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -// This informs the TS compiler about constructed stylesheets. -// It can be removed when this is fixed: https://github.com/Microsoft/TypeScript/issues/30022 -declare interface DocumentOrShadowRoot { - adoptedStyleSheets?: CSSStyleSheet[]; -} - -declare interface CSSStyleSheet { - replace?(text: string): Promise; - replaceSync?(text: string): void; -} diff --git a/packages/rrweb/src/record/observers/canvas/canvas.ts b/packages/rrweb/src/record/observers/canvas/canvas.ts index 4ab79af2e4..4f6b30fc36 100644 --- a/packages/rrweb/src/record/observers/canvas/canvas.ts +++ b/packages/rrweb/src/record/observers/canvas/canvas.ts @@ -19,19 +19,19 @@ export default function initCanvasContextObserver( 'getContext', function ( original: ( - this: ICanvas, + this: ICanvas | HTMLCanvasElement, contextType: string, ...args: Array ) => void, ) { return function ( - this: ICanvas, + this: ICanvas | HTMLCanvasElement, contextType: string, ...args: Array ) { if (!isBlocked(this, blockClass, blockSelector, true)) { const ctxName = getNormalizedContextName(contextType); - if (!('__context' in this)) this.__context = ctxName; + if (!('__context' in this)) (this as ICanvas).__context = ctxName; if ( setPreserveDrawingBufferToTrue && diff --git a/packages/rrweb/src/record/observers/canvas/serialize-args.ts b/packages/rrweb/src/record/observers/canvas/serialize-args.ts index 32806fefef..adc15a91b9 100644 --- a/packages/rrweb/src/record/observers/canvas/serialize-args.ts +++ b/packages/rrweb/src/record/observers/canvas/serialize-args.ts @@ -125,7 +125,7 @@ export function serializeArg( }; } - return value as CanvasArg; + return value as unknown as CanvasArg; } export const serializeArgs = ( diff --git a/packages/rrweb/src/record/observers/canvas/webgl.ts b/packages/rrweb/src/record/observers/canvas/webgl.ts index a5b026ab2c..6a4fe6c849 100644 --- a/packages/rrweb/src/record/observers/canvas/webgl.ts +++ b/packages/rrweb/src/record/observers/canvas/webgl.ts @@ -49,7 +49,10 @@ function patchGLPrototype( return function (this: typeof prototype, ...args: Array) { const result = original.apply(this, args); saveWebGLVar(result, win, this); - if (!isBlocked(this.canvas, blockClass, blockSelector, true)) { + if ( + 'tagName' in this.canvas && + !isBlocked(this.canvas, blockClass, blockSelector, true) + ) { const recordArgs = serializeArgs([...args], win, this); const mutation: canvasMutationWithType = { type, diff --git a/packages/rrweb/src/record/stylesheet-manager.ts b/packages/rrweb/src/record/stylesheet-manager.ts index 89c628768f..b517b7202e 100644 --- a/packages/rrweb/src/record/stylesheet-manager.ts +++ b/packages/rrweb/src/record/stylesheet-manager.ts @@ -1,5 +1,5 @@ import type { elementNode, serializedNodeWithId } from 'rrweb-snapshot'; -import { getCssRuleString } from 'rrweb-snapshot'; +import { stringifyRule } from 'rrweb-snapshot'; import type { adoptedStyleSheetCallback, adoptedStyleSheetParam, @@ -66,7 +66,7 @@ export class StylesheetManager { styleId, rules: rules.map((r, index) => { return { - rule: getCssRuleString(r), + rule: stringifyRule(r), index, }; }), diff --git a/packages/types/package.json b/packages/types/package.json index 67685c1175..3dd53ef711 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -40,7 +40,7 @@ ], "devDependencies": { "vite": "^3.2.0-beta.2", - "vite-plugin-dts": "^1.6.6" + "vite-plugin-dts": "^1.7.3" }, "dependencies": { "rrweb-snapshot": "^2.0.0-alpha.10" diff --git a/yarn.lock b/yarn.lock index c26d4e9233..784f857d42 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2703,6 +2703,11 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== +"@jridgewell/sourcemap-codec@^1.4.13", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + "@jridgewell/trace-mapping@0.3.9": version "0.3.9" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" @@ -2764,29 +2769,29 @@ resolved "https://registry.yarnpkg.com/@mdn/browser-compat-data/-/browser-compat-data-4.2.1.tgz#1fead437f3957ceebe2e8c3f46beccdb9bc575b8" integrity sha512-EWUguj2kd7ldmrF9F+vI5hUOralPd+sdsUnYbRy33vZTuZkduC1shE9TtEMEjAQwyfyMb4ole5KtjF8MsnQOlA== -"@microsoft/api-extractor-model@7.25.2": - version "7.25.2" - resolved "https://registry.yarnpkg.com/@microsoft/api-extractor-model/-/api-extractor-model-7.25.2.tgz#a3e69e952122bbe3f0fc339a8ce0d9d20dd06406" - integrity sha512-+h1uCrLQXFAKMUdghhdDcnniDB+6UA/lS9ArlB4QZQ34UbLuXNy2oQ6fafFK8cKXU4mUPTF/yGRjv7JKD5L7eg== +"@microsoft/api-extractor-model@7.26.9": + version "7.26.9" + resolved "https://registry.yarnpkg.com/@microsoft/api-extractor-model/-/api-extractor-model-7.26.9.tgz#22b4e86ab654488b06c9fb240ec440a446846828" + integrity sha512-1AowqcRy5qMH/OB7UNkdXa4qLoJp58WFdJ026IMFS8skA0OOAOcvBV/Fi4L7fO1R/8uCMz5KHi3NsqVH4Li8xg== dependencies: "@microsoft/tsdoc" "0.14.2" "@microsoft/tsdoc-config" "~0.16.1" - "@rushstack/node-core-library" "3.53.2" + "@rushstack/node-core-library" "3.59.0" -"@microsoft/api-extractor@^7.33.1": - version "7.33.5" - resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.33.5.tgz#6f6791aa0b30fe1581002912ebd4565ef8313323" - integrity sha512-ENoWpTWarKNuodpRFDQr3jyBigHuv98KuJ8H5qXc1LZ1aP5Mk77lCo88HbPisTmSnGevJJHTScfd/DPznOb4CQ== +"@microsoft/api-extractor@^7.33.5": + version "7.34.9" + resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.34.9.tgz#ff92cd6939aa5c1674085494c101e0b614512bfd" + integrity sha512-dasBIbqgHgxvfRfEOX4+ynNYQPnTYc6k7jkL3V4f/MoaS2xFUoIj/D71crrsDxf5MNMybjzeyZPdRNZdzvKBVw== dependencies: - "@microsoft/api-extractor-model" "7.25.2" + "@microsoft/api-extractor-model" "7.26.9" "@microsoft/tsdoc" "0.14.2" "@microsoft/tsdoc-config" "~0.16.1" - "@rushstack/node-core-library" "3.53.2" - "@rushstack/rig-package" "0.3.17" - "@rushstack/ts-command-line" "4.13.0" + "@rushstack/node-core-library" "3.59.0" + "@rushstack/rig-package" "0.3.18" + "@rushstack/ts-command-line" "4.13.2" colors "~1.2.1" lodash "~4.17.15" - resolve "~1.17.0" + resolve "~1.22.1" semver "~7.3.0" source-map "~0.6.1" typescript "~4.8.4" @@ -3044,32 +3049,53 @@ estree-walker "^2.0.1" picomatch "^2.2.2" -"@rushstack/node-core-library@3.53.2", "@rushstack/node-core-library@^3.53.2": - version "3.53.2" - resolved "https://registry.yarnpkg.com/@rushstack/node-core-library/-/node-core-library-3.53.2.tgz#f442e121f9e6c8bef9a23b7337e6399ab5c0c579" - integrity sha512-FggLe5DQs0X9MNFeJN3/EXwb+8hyZUTEp2i+V1e8r4Va4JgkjBNY0BuEaQI+3DW6S4apV3UtXU3im17MSY00DA== +"@rollup/pluginutils@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.0.2.tgz#012b8f53c71e4f6f9cb317e311df1404f56e7a33" + integrity sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^2.0.2" + picomatch "^2.3.1" + +"@rushstack/node-core-library@3.59.0": + version "3.59.0" + resolved "https://registry.yarnpkg.com/@rushstack/node-core-library/-/node-core-library-3.59.0.tgz#f04db22575a242c30114b4723ba0580b6f2d8c85" + integrity sha512-f8ilzooAu8vj60dDe7weqHvR1NujOaKfe3TaNgAoT22rk+daUTmDtY3TlVGJ3HayVPmw3ffWToDatITi7Ic4ag== dependencies: - "@types/node" "12.20.24" colors "~1.2.1" fs-extra "~7.0.1" import-lazy "~4.0.0" jju "~1.4.0" - resolve "~1.17.0" + resolve "~1.22.1" semver "~7.3.0" z-schema "~5.0.2" -"@rushstack/rig-package@0.3.17": - version "0.3.17" - resolved "https://registry.yarnpkg.com/@rushstack/rig-package/-/rig-package-0.3.17.tgz#687bd55603f2902447f3be246d93afac97095a1f" - integrity sha512-nxvAGeIMnHl1LlZSQmacgcRV4y1EYtgcDIrw6KkeVjudOMonlxO482PhDj3LVZEp6L7emSf6YSO2s5JkHlwfZA== +"@rushstack/node-core-library@^3.53.2": + version "3.59.7" + resolved "https://registry.yarnpkg.com/@rushstack/node-core-library/-/node-core-library-3.59.7.tgz#9dcd62b79263e8a5b68465d4bf9124ec86e14b6c" + integrity sha512-ln1Drq0h+Hwa1JVA65x5mlSgUrBa1uHL+V89FqVWQgXd1vVIMhrtqtWGQrhTnFHxru5ppX+FY39VWELF/FjQCw== + dependencies: + colors "~1.2.1" + fs-extra "~7.0.1" + import-lazy "~4.0.0" + jju "~1.4.0" + resolve "~1.22.1" + semver "~7.5.4" + z-schema "~5.0.2" + +"@rushstack/rig-package@0.3.18": + version "0.3.18" + resolved "https://registry.yarnpkg.com/@rushstack/rig-package/-/rig-package-0.3.18.tgz#2b59eb8ed482e8cd6ad8d396414bf3200efdd682" + integrity sha512-SGEwNTwNq9bI3pkdd01yCaH+gAsHqs0uxfGvtw9b0LJXH52qooWXnrFTRRLG1aL9pf+M2CARdrA9HLHJys3jiQ== dependencies: - resolve "~1.17.0" + resolve "~1.22.1" strip-json-comments "~3.1.1" -"@rushstack/ts-command-line@4.13.0": - version "4.13.0" - resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-4.13.0.tgz#a56aa90e5742c25d330cdb0cda1da19225d7bfcf" - integrity sha512-crLT31kl+qilz0eBRjqqYO06CqwbElc0EvzS6jI69B9Ikt1SkkSzIZ2iDP7zt/rd1ZYipKIS9hf9CQR9swDIKg== +"@rushstack/ts-command-line@4.13.2": + version "4.13.2" + resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-4.13.2.tgz#2dfdcf418d58256671433b1da4a3b67e1814cc7a" + integrity sha512-bCU8qoL9HyWiciltfzg7GqdfODUeda/JpI0602kbN5YH22rzTxyqYvv7aRLENCM7XCQ1VRs7nMkEqgJUOU8Sag== dependencies: "@types/argparse" "1.0.38" argparse "~1.0.9" @@ -3148,12 +3174,12 @@ resolved "https://registry.yarnpkg.com/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz#db4ecfd499a9765ab24002c3b696d02e6d32a12c" integrity sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA== -"@ts-morph/common@~0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.17.0.tgz#de0d405df10857907469fef8d9363893b4163fd1" - integrity sha512-RMSSvSfs9kb0VzkvQ2NWobwnj7TxCA9vI/IjR9bDHqgAyVbu2T0DN4wiKVqomyDWqO7dPr/tErSfq7urQ1Q37g== +"@ts-morph/common@~0.18.0": + version "0.18.1" + resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.18.1.tgz#ca40c3a62c3f9e17142e0af42633ad63efbae0ec" + integrity sha512-RVE+zSRICWRsfrkAw5qCAK+4ZH9kwEFv5h0+/YeHTLieWP7F4wWq4JsKFuNWG+fYh/KF+8rAtgdj5zb2mm+DVA== dependencies: - fast-glob "^3.2.11" + fast-glob "^3.2.12" minimatch "^5.1.0" mkdirp "^1.0.4" path-browserify "^1.0.1" @@ -3241,17 +3267,17 @@ resolved "https://registry.npmjs.org/@types/cssstyle/-/cssstyle-2.2.1.tgz#fa010824006ff47af94a6b9baf9759e031815347" integrity sha512-CSQFKdZc3dmWoZXLAM0pPL6XiYLG8hMGzImM2MwQ9kavB5LnbeMGan94CCj4oxY65xMl5mRMwrFUfKPOWO4WpQ== -"@types/dom-mediacapture-transform@^0.1.3": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@types/dom-mediacapture-transform/-/dom-mediacapture-transform-0.1.3.tgz#ef0b5c7a3aeb0af7e35fe7f57b5700c9a479bfef" - integrity sha512-Zi2IOA+NFqPmqFojaOskEzUOABMHEouZg8vtwMt0MbppgTu1pOVg2zWQVvfjnCIgOj//CleXHhryvRKaykSVJw== +"@types/dom-mediacapture-transform@0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@types/dom-mediacapture-transform/-/dom-mediacapture-transform-0.1.4.tgz#f77c1b469f4c33513219dbca46201cf5bf0d082f" + integrity sha512-G4DI51gU3zp/nCFVP7O5dv3sZ7nVXy3Dqooup8tDhvdzUNeAMiC0XIFGiwH3UHPh/t6L5odMOHwB3BYlY86WKw== dependencies: "@types/dom-webcodecs" "*" -"@types/dom-webcodecs@*": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@types/dom-webcodecs/-/dom-webcodecs-0.1.4.tgz#90a3dd80e5baf72baa79a74cf410e63863992516" - integrity sha512-dc+xSUnCaCdi/hExZArnLhiavS3E1Rdpp2+zCI6TcmJvz4qgDPBbpvCM7DsQhwRXIIpVMHO6c3s+t+JyCSqYBA== +"@types/dom-webcodecs@*", "@types/dom-webcodecs@0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@types/dom-webcodecs/-/dom-webcodecs-0.1.5.tgz#2252fdb4a3229924d27f054242cc614e2cd5b83b" + integrity sha512-dsAE+4ws75W5mmNmIZ7IKZwv4bcz5GgPuA87u+Mk1CeVWB6g7ZwBfizRwBZDeyO12RSxoU3NlRa8jgLYQeSZGg== "@types/estree@*": version "0.0.50" @@ -3263,6 +3289,11 @@ resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz" integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== +"@types/estree@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194" + integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA== + "@types/fs-extra@11.0.1": version "11.0.1" resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-11.0.1.tgz#f542ec47810532a8a252127e6e105f487e0a6ea5" @@ -3400,11 +3431,6 @@ resolved "https://registry.npmjs.org/@types/node/-/node-16.4.0.tgz" integrity sha512-HrJuE7Mlqcjj+00JqMWpZ3tY8w7EUd+S0U3L1+PQSWiXZbOgyQDvi+ogoUxaHApPJq5diKxYBQwA3iIlNcPqOg== -"@types/node@12.20.24": - version "12.20.24" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.24.tgz#c37ac69cb2948afb4cef95f424fa0037971a9a5c" - integrity sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ== - "@types/node@^12.7.1": version "12.20.55" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" @@ -3452,10 +3478,10 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== -"@types/pug@^2.0.4": - version "2.0.5" - resolved "https://registry.npmjs.org/@types/pug/-/pug-2.0.5.tgz" - integrity sha512-LOnASQoeNZMkzexRuyqcBBDZ6rS+rQxUMkmj5A0PkhhiSZivLIuz6Hxyr1mkGoEZEkk66faROmpMi4fFkrKsBA== +"@types/pug@^2.0.6": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/pug/-/pug-2.0.6.tgz#f830323c88172e66826d0bde413498b61054b5a6" + integrity sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg== "@types/puppeteer@^1.12.4": version "1.20.8" @@ -3499,13 +3525,6 @@ dependencies: "@types/node" "*" -"@types/sass@^1.16.0": - version "1.16.1" - resolved "https://registry.npmjs.org/@types/sass/-/sass-1.16.1.tgz" - integrity sha512-iZUcRrGuz/Tbg3loODpW7vrQJkUtpY2fFSf4ELqqkApcS2TkZ1msk7ie8iZPB86lDOP8QOTTmuvWjc5S0R9OjQ== - dependencies: - "@types/node" "*" - "@types/scheduler@*": version "0.16.2" resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" @@ -4615,7 +4634,7 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" -buffer-crc32@~0.2.3: +buffer-crc32@^0.2.5, buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz" integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= @@ -5750,7 +5769,7 @@ destroy@~1.0.4: resolved "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= -detect-indent@^6.0.0: +detect-indent@^6.0.0, detect-indent@^6.1.0: version "6.1.0" resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz" integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== @@ -6161,6 +6180,11 @@ es6-error@4.1.1: resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== +es6-promise@^3.1.2: + version "3.3.1" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613" + integrity sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg== + es6-promisify@7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-7.0.0.tgz#9a710008dd6a4ab75a89e280bad787bfb749927b" @@ -6744,7 +6768,7 @@ estree-walker@^1.0.1: resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz" integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== -estree-walker@^2.0.1: +estree-walker@^2.0.1, estree-walker@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz" integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== @@ -6956,10 +6980,10 @@ fast-glob@^3.1.1: merge2 "^1.3.0" micromatch "^4.0.4" -fast-glob@^3.2.11, fast-glob@^3.2.12: - version "3.2.12" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" - integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== +fast-glob@^3.2.12, fast-glob@^3.2.7: + version "3.3.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -7686,6 +7710,11 @@ graceful-fs@^4.1.2: resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz" integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== +graceful-fs@^4.1.3: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + graceful-fs@^4.1.5: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" @@ -8326,6 +8355,13 @@ is-core-module@^2.1.0: dependencies: has "^1.0.3" +is-core-module@^2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" + integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== + dependencies: + has "^1.0.3" + is-core-module@^2.2.0: version "2.5.0" resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz" @@ -10300,9 +10336,9 @@ kleur@^4.1.4: integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== kolorist@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.6.0.tgz#f43ac794305b30032a5bedcae7799d0f91d2ff36" - integrity sha512-dLkz37Ab97HWMx9KTes3Tbi3D1ln9fCAy2zr2YVExJasDRPGRaKcoE4fycWNtnCAJfjFqe0cnY+f8KT2JePEXQ== + version "1.8.0" + resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.8.0.tgz#edddbbbc7894bc13302cdf740af6374d4a04743c" + integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ== latest-version@^5.1.0: version "5.1.0" @@ -10575,6 +10611,13 @@ magic-string@^0.26.2: dependencies: sourcemap-codec "^1.4.8" +magic-string@^0.27.0: + version "0.27.0" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.27.0.tgz#e4a3413b4bab6d98d2becffd48b4a257effdbbf3" + integrity sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.13" + make-dir@^3.0.0, make-dir@^3.0.2: version "3.1.0" resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz" @@ -10851,9 +10894,9 @@ min-indent@^1.0.0: brace-expansion "^1.1.7" minimatch@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.0.tgz#1717b464f4971b144f6aabe8f2d0b8e4511e09c7" - integrity sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg== + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== dependencies: brace-expansion "^2.0.1" @@ -12817,13 +12860,6 @@ resolve@^1.22.1: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@~1.17.0: - version "1.17.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" - integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== - dependencies: - path-parse "^1.0.6" - resolve@~1.19.0: version "1.19.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" @@ -12832,6 +12868,15 @@ resolve@~1.19.0: is-core-module "^2.1.0" path-parse "^1.0.6" +resolve@~1.22.1: + version "1.22.4" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34" + integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + responselike@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" @@ -12869,7 +12914,7 @@ rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" -rimraf@^2.6.2: +rimraf@^2.5.2, rimraf@^2.6.2: version "2.7.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -13102,6 +13147,16 @@ safe-stable-stringify@^2.1.0: resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +sander@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/sander/-/sander-0.5.1.tgz#741e245e231f07cafb6fdf0f133adfa216a502ad" + integrity sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA== + dependencies: + es6-promise "^3.1.2" + graceful-fs "^4.1.3" + mkdirp "^0.5.1" + rimraf "^2.5.2" + sax@>=0.6.0, sax@~1.2.4: version "1.2.4" resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz" @@ -13171,7 +13226,7 @@ semver@^7.3.7: dependencies: lru-cache "^6.0.0" -semver@^7.5.3: +semver@^7.5.3, semver@~7.5.4: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== @@ -13402,6 +13457,16 @@ sonic-boom@^2.2.1: dependencies: atomic-sleep "^1.0.0" +sorcery@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/sorcery/-/sorcery-0.11.0.tgz#310c80ee993433854bb55bb9aa4003acd147fca8" + integrity sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.14" + buffer-crc32 "^0.2.5" + minimist "^1.2.0" + sander "^0.5.0" + source-map-js@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" @@ -13836,35 +13901,35 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -svelte-check@^1.4.0: - version "1.6.0" - resolved "https://registry.npmjs.org/svelte-check/-/svelte-check-1.6.0.tgz" - integrity sha512-nQTlbFJWhwoeLY5rkhgbjzGQSwk5F1pRdEXait0EFaQSrE/iJF+PIjrQlk0BjL/ogk9HaR9ZI0DQSYrl7jl3IQ== +svelte-check@^3.0.1: + version "3.4.6" + resolved "https://registry.yarnpkg.com/svelte-check/-/svelte-check-3.4.6.tgz#d43de724ad89d1198c96770e9d23965d3379ad44" + integrity sha512-OBlY8866Zh1zHQTkBMPS6psPi7o2umTUyj6JWm4SacnIHXpWFm658pG32m3dKvKFL49V4ntAkfFHKo4ztH07og== dependencies: - chalk "^4.0.0" + "@jridgewell/trace-mapping" "^0.3.17" chokidar "^3.4.1" - glob "^7.1.6" + fast-glob "^3.2.7" import-fresh "^3.2.1" - minimist "^1.2.5" + picocolors "^1.0.0" sade "^1.7.4" - source-map "^0.7.3" - svelte-preprocess "^4.0.0" - typescript "*" + svelte-preprocess "^5.0.4" + typescript "^5.0.3" -svelte-preprocess@^4.0.0: - version "4.7.4" - resolved "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.7.4.tgz" - integrity sha512-mDAmaltQl6e5zU2VEtoWEf7eLTfuOTGr9zt+BpA3AGHo8MIhKiNSPE9OLTCTOMgj0vj/uL9QBbaNmpG4G1CgIA== +svelte-preprocess@^5.0.0, svelte-preprocess@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/svelte-preprocess/-/svelte-preprocess-5.0.4.tgz#2123898e079a074f7f4ef1799e10e037f5bcc55b" + integrity sha512-ABia2QegosxOGsVlsSBJvoWeXy1wUKSfF7SWJdTjLAbx/Y3SrVevvvbFNQqrSJw89+lNSsM58SipmZJ5SRi5iw== dependencies: - "@types/pug" "^2.0.4" - "@types/sass" "^1.16.0" - detect-indent "^6.0.0" + "@types/pug" "^2.0.6" + detect-indent "^6.1.0" + magic-string "^0.27.0" + sorcery "^0.11.0" strip-indent "^3.0.0" -svelte@^3.2.0: - version "3.49.0" - resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.49.0.tgz#5baee3c672306de1070c3b7888fc2204e36a4029" - integrity sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA== +svelte@^3.59.2: + version "3.59.2" + resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.59.2.tgz#a137b28e025a181292b2ae2e3dca90bf8ec73aec" + integrity sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA== svgo@^1.0.0: version "1.3.2" @@ -14173,12 +14238,12 @@ ts-jest@^29.1.1: semver "^7.5.3" yargs-parser "^21.0.1" -ts-morph@^16.0.0: - version "16.0.0" - resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-16.0.0.tgz#35caca7c286dd70e09e5f72af47536bf3b6a27af" - integrity sha512-jGNF0GVpFj0orFw55LTsQxVYEUOCWBAbR5Ls7fTYE5pQsbW18ssTb/6UXx/GYAEjS+DQTp8VoTw0vqYMiaaQuw== +ts-morph@17.0.1: + version "17.0.1" + resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-17.0.1.tgz#d85df4fcf9a1fcda1b331d52c00655f381c932d1" + integrity sha512-10PkHyXmrtsTvZSL+cqtJLTgFXkU43Gd0JCc0Rw6GchWbqKe0Rwgt1v3ouobTZwQzF1mGhDeAlWYBMGRV7y+3g== dependencies: - "@ts-morph/common" "~0.17.0" + "@ts-morph/common" "~0.18.0" code-block-writer "^11.0.3" ts-node@^10.9.1: @@ -14438,10 +14503,15 @@ typedarray@^0.0.6: resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@*, typescript@^4.7.3: - version "4.7.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" - integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== +typescript@^4.9.5: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== + +typescript@^5.0.3: + version "5.1.6" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274" + integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== typescript@~4.8.4: version "4.8.4" @@ -14716,18 +14786,19 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -vite-plugin-dts@^1.6.6: - version "1.6.6" - resolved "https://registry.yarnpkg.com/vite-plugin-dts/-/vite-plugin-dts-1.6.6.tgz#aa572d40cb371f91470b37300ab632cf83734ab7" - integrity sha512-XEZQlcAN5Bi1PWL0l/E08cI3VpjTCWY5x7C4/bVyC7lpS+/q9CDBCV8gGsqV97/g34N7gNNRNhqs8r0m6JAmIQ== +vite-plugin-dts@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/vite-plugin-dts/-/vite-plugin-dts-1.7.3.tgz#cf0c243fff9ae3fc1f103987b97439b3bf813f15" + integrity sha512-u3t45p6fTbzUPMkwYe0ESwuUeiRMlwdPfD3dRyDKUwLe2WmEYcFyVp2o9/ke2EMrM51lQcmNWdV9eLcgjD1/ng== dependencies: - "@microsoft/api-extractor" "^7.33.1" + "@microsoft/api-extractor" "^7.33.5" + "@rollup/pluginutils" "^5.0.2" "@rushstack/node-core-library" "^3.53.2" debug "^4.3.4" fast-glob "^3.2.12" fs-extra "^10.1.0" kolorist "^1.6.0" - ts-morph "^16.0.0" + ts-morph "17.0.1" vite-plugin-web-extension@^1.4.5: version "1.4.5" From 3119e0d1d80edf9d6c989e65fcafbd40e4290f31 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 11:05:02 +0200 Subject: [PATCH 024/123] Version Packages (alpha) (#1286) Co-authored-by: github-actions[bot] --- .changeset/pre.json | 4 ++++ packages/rrdom-nodejs/CHANGELOG.md | 8 ++++++++ packages/rrdom-nodejs/package.json | 6 +++--- packages/rrdom/CHANGELOG.md | 7 +++++++ packages/rrdom/package.json | 6 +++--- packages/rrvideo/CHANGELOG.md | 7 +++++++ packages/rrvideo/package.json | 6 +++--- packages/rrweb-player/CHANGELOG.md | 9 +++++++++ packages/rrweb-player/package.json | 6 +++--- packages/rrweb-snapshot/CHANGELOG.md | 10 ++++++++++ packages/rrweb-snapshot/package.json | 2 +- packages/rrweb/CHANGELOG.md | 13 +++++++++++++ packages/rrweb/package.json | 8 ++++---- packages/types/CHANGELOG.md | 9 +++++++++ packages/types/package.json | 4 ++-- packages/web-extension/CHANGELOG.md | 8 ++++++++ packages/web-extension/package.json | 8 ++++---- 17 files changed, 98 insertions(+), 23 deletions(-) diff --git a/.changeset/pre.json b/.changeset/pre.json index c9d02029ba..067c4ae386 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -20,6 +20,7 @@ "clean-shrimps-lay", "cold-eyes-hunt", "controller-finish-flag", + "curvy-apples-lay", "date-now-guard", "eight-terms-hunt", "empty-bikes-cheer", @@ -32,6 +33,8 @@ "fresh-spoons-drive", "gold-terms-look", "grumpy-ways-own", + "itchy-dryers-double", + "khaki-dots-bathe", "large-ants-prove", "lazy-toes-confess", "little-radios-thank", @@ -53,6 +56,7 @@ "real-masks-explode", "real-trains-switch", "rich-crews-protect", + "rich-jars-remember", "serious-ants-juggle", "sixty-impalas-laugh", "small-olives-arrive", diff --git a/packages/rrdom-nodejs/CHANGELOG.md b/packages/rrdom-nodejs/CHANGELOG.md index b69007b8e5..644746d893 100644 --- a/packages/rrdom-nodejs/CHANGELOG.md +++ b/packages/rrdom-nodejs/CHANGELOG.md @@ -1,5 +1,13 @@ # rrdom-nodejs +## 2.0.0-alpha.11 + +### Patch Changes + +- Updated dependencies [[`11f6567`](https://github.com/rrweb-io/rrweb/commit/11f6567fd81ef9ed0f954a7b6d5e39653f56004f), [`efdc167`](https://github.com/rrweb-io/rrweb/commit/efdc167ca6c039d04af83612e3d92498bb9b41a7), [`efdc167`](https://github.com/rrweb-io/rrweb/commit/efdc167ca6c039d04af83612e3d92498bb9b41a7)]: + - rrweb-snapshot@2.0.0-alpha.11 + - rrdom@2.0.0-alpha.11 + ## 2.0.0-alpha.10 ### Patch Changes diff --git a/packages/rrdom-nodejs/package.json b/packages/rrdom-nodejs/package.json index 395710dd00..58aad4a681 100644 --- a/packages/rrdom-nodejs/package.json +++ b/packages/rrdom-nodejs/package.json @@ -1,6 +1,6 @@ { "name": "rrdom-nodejs", - "version": "2.0.0-alpha.10", + "version": "2.0.0-alpha.11", "scripts": { "dev": "rollup -c -w", "bundle": "rollup --config", @@ -48,8 +48,8 @@ "cssom": "^0.5.0", "cssstyle": "^2.3.0", "nwsapi": "^2.2.0", - "rrdom": "^2.0.0-alpha.10", - "rrweb-snapshot": "^2.0.0-alpha.10" + "rrdom": "^2.0.0-alpha.11", + "rrweb-snapshot": "^2.0.0-alpha.11" }, "browserslist": [ "supports es6-class" diff --git a/packages/rrdom/CHANGELOG.md b/packages/rrdom/CHANGELOG.md index 4c94a15108..656122115a 100644 --- a/packages/rrdom/CHANGELOG.md +++ b/packages/rrdom/CHANGELOG.md @@ -1,5 +1,12 @@ # rrdom +## 2.0.0-alpha.11 + +### Patch Changes + +- Updated dependencies [[`11f6567`](https://github.com/rrweb-io/rrweb/commit/11f6567fd81ef9ed0f954a7b6d5e39653f56004f), [`efdc167`](https://github.com/rrweb-io/rrweb/commit/efdc167ca6c039d04af83612e3d92498bb9b41a7), [`efdc167`](https://github.com/rrweb-io/rrweb/commit/efdc167ca6c039d04af83612e3d92498bb9b41a7)]: + - rrweb-snapshot@2.0.0-alpha.11 + ## 2.0.0-alpha.10 ### Patch Changes diff --git a/packages/rrdom/package.json b/packages/rrdom/package.json index d2e52e1599..f7122da917 100644 --- a/packages/rrdom/package.json +++ b/packages/rrdom/package.json @@ -1,6 +1,6 @@ { "name": "rrdom", - "version": "2.0.0-alpha.10", + "version": "2.0.0-alpha.11", "homepage": "https://github.com/rrweb-io/rrweb/tree/main/packages/rrdom#readme", "license": "MIT", "main": "lib/rrdom.cjs", @@ -32,7 +32,7 @@ }, "devDependencies": { "@rollup/plugin-commonjs": "^20.0.0", - "@rrweb/types": "^2.0.0-alpha.10", + "@rrweb/types": "^2.0.0-alpha.11", "@types/jest": "^27.4.1", "@types/puppeteer": "^5.4.4", "@typescript-eslint/eslint-plugin": "^5.23.0", @@ -47,6 +47,6 @@ "ts-jest": "^27.1.3" }, "dependencies": { - "rrweb-snapshot": "^2.0.0-alpha.10" + "rrweb-snapshot": "^2.0.0-alpha.11" } } diff --git a/packages/rrvideo/CHANGELOG.md b/packages/rrvideo/CHANGELOG.md index a6ce3f2fe6..d0a3168f9c 100644 --- a/packages/rrvideo/CHANGELOG.md +++ b/packages/rrvideo/CHANGELOG.md @@ -1,5 +1,12 @@ # rrvideo +## 2.0.0-alpha.11 + +### Patch Changes + +- Updated dependencies [[`efdc167`](https://github.com/rrweb-io/rrweb/commit/efdc167ca6c039d04af83612e3d92498bb9b41a7)]: + - rrweb-player@2.0.0-alpha.11 + ## 2.0.0-alpha.10 ### Patch Changes diff --git a/packages/rrvideo/package.json b/packages/rrvideo/package.json index c7d64b7c76..5472c8981a 100644 --- a/packages/rrvideo/package.json +++ b/packages/rrvideo/package.json @@ -1,6 +1,6 @@ { "name": "rrvideo", - "version": "2.0.0-alpha.10", + "version": "2.0.0-alpha.11", "description": "transform rrweb session into video", "main": "build/index.js", "bin": { @@ -26,13 +26,13 @@ "@types/node": "^18.15.11", "jest": "^27.5.1", "ts-jest": "^27.1.3", - "@rrweb/types": "^2.0.0-alpha.10" + "@rrweb/types": "^2.0.0-alpha.11" }, "dependencies": { "@open-tech-world/cli-progress-bar": "^2.0.2", "fs-extra": "^11.1.1", "minimist": "^1.2.5", "playwright": "^1.32.1", - "rrweb-player": "^2.0.0-alpha.10" + "rrweb-player": "^2.0.0-alpha.11" } } diff --git a/packages/rrweb-player/CHANGELOG.md b/packages/rrweb-player/CHANGELOG.md index c9be0dc3ad..0743a3a1d3 100644 --- a/packages/rrweb-player/CHANGELOG.md +++ b/packages/rrweb-player/CHANGELOG.md @@ -1,5 +1,14 @@ # rrweb-player +## 2.0.0-alpha.11 + +### Patch Changes + +- [#1287](https://github.com/rrweb-io/rrweb/pull/1287) [`efdc167`](https://github.com/rrweb-io/rrweb/commit/efdc167ca6c039d04af83612e3d92498bb9b41a7) Thanks [@Juice10](https://github.com/Juice10)! - Upgrade all projects to typescript 4.9.5 + +- Updated dependencies [[`11f6567`](https://github.com/rrweb-io/rrweb/commit/11f6567fd81ef9ed0f954a7b6d5e39653f56004f), [`efdc167`](https://github.com/rrweb-io/rrweb/commit/efdc167ca6c039d04af83612e3d92498bb9b41a7)]: + - rrweb@2.0.0-alpha.11 + ## 2.0.0-alpha.10 ### Patch Changes diff --git a/packages/rrweb-player/package.json b/packages/rrweb-player/package.json index a6e289640c..f545256267 100644 --- a/packages/rrweb-player/package.json +++ b/packages/rrweb-player/package.json @@ -1,10 +1,10 @@ { "name": "rrweb-player", - "version": "2.0.0-alpha.10", + "version": "2.0.0-alpha.11", "devDependencies": { "@rollup/plugin-commonjs": "^22.0.0", "@rollup/plugin-node-resolve": "^13.2.1", - "@rrweb/types": "^2.0.0-alpha.10", + "@rrweb/types": "^2.0.0-alpha.11", "@types/offscreencanvas": "^2019.6.4", "eslint-config-google": "^0.14.0", "eslint-plugin-svelte3": "^4.0.0", @@ -24,7 +24,7 @@ }, "dependencies": { "@tsconfig/svelte": "^1.0.0", - "rrweb": "^2.0.0-alpha.10" + "rrweb": "^2.0.0-alpha.11" }, "scripts": { "build": "rollup -c", diff --git a/packages/rrweb-snapshot/CHANGELOG.md b/packages/rrweb-snapshot/CHANGELOG.md index 2491fca4dd..3051b02caf 100644 --- a/packages/rrweb-snapshot/CHANGELOG.md +++ b/packages/rrweb-snapshot/CHANGELOG.md @@ -1,5 +1,15 @@ # rrweb-snapshot +## 2.0.0-alpha.11 + +### Patch Changes + +- [#1279](https://github.com/rrweb-io/rrweb/pull/1279) [`11f6567`](https://github.com/rrweb-io/rrweb/commit/11f6567fd81ef9ed0f954a7b6d5e39653f56004f) Thanks [@eoghanmurray](https://github.com/eoghanmurray)! - Extend to run fixBrowserCompatibilityIssuesInCSS over inline stylesheets + +- [#1287](https://github.com/rrweb-io/rrweb/pull/1287) [`efdc167`](https://github.com/rrweb-io/rrweb/commit/efdc167ca6c039d04af83612e3d92498bb9b41a7) Thanks [@Juice10](https://github.com/Juice10)! - Upgrade all projects to typescript 4.9.5 + +- [#1287](https://github.com/rrweb-io/rrweb/pull/1287) [`efdc167`](https://github.com/rrweb-io/rrweb/commit/efdc167ca6c039d04af83612e3d92498bb9b41a7) Thanks [@Juice10](https://github.com/Juice10)! - Add workaround for Chrome/Edge CSS `@import` escaping bug: https://bugs.chromium.org/p/chromium/issues/detail?id=1472259 + ## 2.0.0-alpha.10 ### Patch Changes diff --git a/packages/rrweb-snapshot/package.json b/packages/rrweb-snapshot/package.json index e77df133be..00b2a98f35 100644 --- a/packages/rrweb-snapshot/package.json +++ b/packages/rrweb-snapshot/package.json @@ -1,6 +1,6 @@ { "name": "rrweb-snapshot", - "version": "2.0.0-alpha.10", + "version": "2.0.0-alpha.11", "description": "rrweb's component to take a snapshot of DOM, aka DOM serializer", "scripts": { "prepare": "npm run prepack", diff --git a/packages/rrweb/CHANGELOG.md b/packages/rrweb/CHANGELOG.md index 65b460cda5..d920660c75 100644 --- a/packages/rrweb/CHANGELOG.md +++ b/packages/rrweb/CHANGELOG.md @@ -1,5 +1,18 @@ # rrweb +## 2.0.0-alpha.11 + +### Patch Changes + +- [#1279](https://github.com/rrweb-io/rrweb/pull/1279) [`11f6567`](https://github.com/rrweb-io/rrweb/commit/11f6567fd81ef9ed0f954a7b6d5e39653f56004f) Thanks [@eoghanmurray](https://github.com/eoghanmurray)! - Extend to run fixBrowserCompatibilityIssuesInCSS over inline stylesheets + +- [#1287](https://github.com/rrweb-io/rrweb/pull/1287) [`efdc167`](https://github.com/rrweb-io/rrweb/commit/efdc167ca6c039d04af83612e3d92498bb9b41a7) Thanks [@Juice10](https://github.com/Juice10)! - Upgrade all projects to typescript 4.9.5 + +- Updated dependencies [[`11f6567`](https://github.com/rrweb-io/rrweb/commit/11f6567fd81ef9ed0f954a7b6d5e39653f56004f), [`efdc167`](https://github.com/rrweb-io/rrweb/commit/efdc167ca6c039d04af83612e3d92498bb9b41a7), [`efdc167`](https://github.com/rrweb-io/rrweb/commit/efdc167ca6c039d04af83612e3d92498bb9b41a7)]: + - rrweb-snapshot@2.0.0-alpha.11 + - @rrweb/types@2.0.0-alpha.11 + - rrdom@2.0.0-alpha.11 + ## 2.0.0-alpha.10 ### Patch Changes diff --git a/packages/rrweb/package.json b/packages/rrweb/package.json index 22a91a411a..a95f60f380 100644 --- a/packages/rrweb/package.json +++ b/packages/rrweb/package.json @@ -1,6 +1,6 @@ { "name": "rrweb", - "version": "2.0.0-alpha.10", + "version": "2.0.0-alpha.11", "description": "record and replay the web", "scripts": { "prepare": "npm run prepack", @@ -81,13 +81,13 @@ "tslib": "^2.3.1" }, "dependencies": { - "@rrweb/types": "^2.0.0-alpha.10", + "@rrweb/types": "^2.0.0-alpha.11", "@types/css-font-loading-module": "0.0.7", "@xstate/fsm": "^1.4.0", "base64-arraybuffer": "^1.0.1", "fflate": "^0.4.4", "mitt": "^3.0.0", - "rrdom": "^2.0.0-alpha.10", - "rrweb-snapshot": "^2.0.0-alpha.10" + "rrdom": "^2.0.0-alpha.11", + "rrweb-snapshot": "^2.0.0-alpha.11" } } diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index 5f6c542c6a..6a9c4a2fa7 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -1,5 +1,14 @@ # @rrweb/types +## 2.0.0-alpha.11 + +### Patch Changes + +- [#1287](https://github.com/rrweb-io/rrweb/pull/1287) [`efdc167`](https://github.com/rrweb-io/rrweb/commit/efdc167ca6c039d04af83612e3d92498bb9b41a7) Thanks [@Juice10](https://github.com/Juice10)! - Upgrade all projects to typescript 4.9.5 + +- Updated dependencies [[`11f6567`](https://github.com/rrweb-io/rrweb/commit/11f6567fd81ef9ed0f954a7b6d5e39653f56004f), [`efdc167`](https://github.com/rrweb-io/rrweb/commit/efdc167ca6c039d04af83612e3d92498bb9b41a7), [`efdc167`](https://github.com/rrweb-io/rrweb/commit/efdc167ca6c039d04af83612e3d92498bb9b41a7)]: + - rrweb-snapshot@2.0.0-alpha.11 + ## 2.0.0-alpha.10 ### Patch Changes diff --git a/packages/types/package.json b/packages/types/package.json index 3dd53ef711..d3d376e0f2 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@rrweb/types", - "version": "2.0.0-alpha.10", + "version": "2.0.0-alpha.11", "publishConfig": { "access": "public" }, @@ -43,7 +43,7 @@ "vite-plugin-dts": "^1.7.3" }, "dependencies": { - "rrweb-snapshot": "^2.0.0-alpha.10" + "rrweb-snapshot": "^2.0.0-alpha.11" }, "browserslist": [ "supports es6-class" diff --git a/packages/web-extension/CHANGELOG.md b/packages/web-extension/CHANGELOG.md index 5553a9f813..5f70ed0631 100644 --- a/packages/web-extension/CHANGELOG.md +++ b/packages/web-extension/CHANGELOG.md @@ -1,5 +1,13 @@ # @rrweb/web-extension +## 2.0.0-alpha.11 + +### Patch Changes + +- Updated dependencies [[`11f6567`](https://github.com/rrweb-io/rrweb/commit/11f6567fd81ef9ed0f954a7b6d5e39653f56004f), [`efdc167`](https://github.com/rrweb-io/rrweb/commit/efdc167ca6c039d04af83612e3d92498bb9b41a7)]: + - rrweb@2.0.0-alpha.11 + - rrweb-player@2.0.0-alpha.11 + ## 2.0.0-alpha.10 ### Patch Changes diff --git a/packages/web-extension/package.json b/packages/web-extension/package.json index 78ad204937..eb87e818ba 100644 --- a/packages/web-extension/package.json +++ b/packages/web-extension/package.json @@ -1,7 +1,7 @@ { "name": "@rrweb/web-extension", "private": true, - "version": "2.0.0-alpha.10", + "version": "2.0.0-alpha.11", "description": "The web extension of rrweb which helps to run rrweb on any website out of box", "author": "rrweb-io", "license": "MIT", @@ -16,7 +16,7 @@ "prepublish": "npm run pack:chrome && npm run pack:firefox" }, "devDependencies": { - "@rrweb/types": "^2.0.0-alpha.10", + "@rrweb/types": "^2.0.0-alpha.11", "@types/react-dom": "^18.0.6", "@types/webextension-polyfill": "^0.9.1", "@vitejs/plugin-react": "^2.1.0", @@ -40,7 +40,7 @@ "react-dom": "^18.2.0", "react-icons": "^4.4.0", "react-router-dom": "^6.4.1", - "rrweb": "^2.0.0-alpha.10", - "rrweb-player": "^2.0.0-alpha.10" + "rrweb": "^2.0.0-alpha.11", + "rrweb-player": "^2.0.0-alpha.11" } } From f1b8e855b1f0283f8700a146991f182b2e79911f Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Mon, 14 Aug 2023 11:33:24 +0200 Subject: [PATCH 025/123] Make sure CI doesn't trigger updates to yarn.lock files (#1288) * Make sure CI doesn't trigger updates to yarn.lock files * Apply formatting changes * Create cuddly-readers-warn.md * Apply formatting changes --- .changeset/cuddly-readers-warn.md | 2 ++ .github/workflows/style-check.yml | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 .changeset/cuddly-readers-warn.md diff --git a/.changeset/cuddly-readers-warn.md b/.changeset/cuddly-readers-warn.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/cuddly-readers-warn.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.github/workflows/style-check.yml b/.github/workflows/style-check.yml index 53748056f8..0f2fd01df9 100644 --- a/.github/workflows/style-check.yml +++ b/.github/workflows/style-check.yml @@ -65,7 +65,7 @@ jobs: node-version: 16 cache: 'yarn' - name: Install Dependencies - run: yarn + run: yarn install --frozen-lockfile - name: Prettier Check run: yarn prettier --check '**/*.{ts,md}' @@ -85,7 +85,7 @@ jobs: node-version: 16 cache: 'yarn' - name: Install Dependencies - run: yarn + run: yarn install --frozen-lockfile - name: Prettify Code run: yarn prettier --write '**/*.{ts,md}' - name: Commit Changes From 64420c7e46abe84e63b1b4c1baa71ab30f7c9745 Mon Sep 17 00:00:00 2001 From: Eoghan Murray Date: Mon, 14 Aug 2023 12:43:34 +0100 Subject: [PATCH 026/123] Perf: don't run the regex replace unless the selectorText contains a colon (#1280) * Perf: don't run the regex replace unless the selectorText contains a colon (rules generally contain colons) * Need to check type before querying selectorText property - also good as it means we only try to fix colons at the leaf level --------- Authored-by: eoghan murray --- packages/rrweb-snapshot/src/snapshot.ts | 1 - packages/rrweb-snapshot/src/utils.ts | 23 +++++++++++++---------- packages/rrweb-snapshot/test/css.test.ts | 13 ++++--------- yarn.lock | 7 +------ 4 files changed, 18 insertions(+), 26 deletions(-) diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index 51e764ced7..02619296c8 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -22,7 +22,6 @@ import { stringifyStylesheet, getInputType, toLowerCase, - validateStringifiedCssRule, } from './utils'; let _id = 1; diff --git a/packages/rrweb-snapshot/src/utils.ts b/packages/rrweb-snapshot/src/utils.ts index 2b432459d6..02043995fe 100644 --- a/packages/rrweb-snapshot/src/utils.ts +++ b/packages/rrweb-snapshot/src/utils.ts @@ -119,26 +119,29 @@ export function stringifyRule(rule: CSSRule): string { } catch (error) { // ignore } + } else if (isCSSStyleRule(rule) && rule.selectorText.includes(':')) { + // Safari does not escape selectors with : properly + // see https://bugs.webkit.org/show_bug.cgi?id=184604 + return fixSafariColons(rule.cssText); } - return validateStringifiedCssRule(importStringified || rule.cssText); + return importStringified || rule.cssText; } -export function validateStringifiedCssRule(cssStringified: string): string { - // Safari does not escape selectors with : properly - if (cssStringified.includes(':')) { - // Replace e.g. [aa:bb] with [aa\\:bb] - const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm; - return cssStringified.replace(regex, '$1\\$2'); - } - - return cssStringified; +export function fixSafariColons(cssStringified: string): string { + // Replace e.g. [aa:bb] with [aa\\:bb] + const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm; + return cssStringified.replace(regex, '$1\\$2'); } export function isCSSImportRule(rule: CSSRule): rule is CSSImportRule { return 'styleSheet' in rule; } +export function isCSSStyleRule(rule: CSSRule): rule is CSSStyleRule { + return 'selectorText' in rule; +} + export class Mirror implements IMirror { private idNodeMap: idNodeMap = new Map(); private nodeMetaMap: nodeMetaMap = new WeakMap(); diff --git a/packages/rrweb-snapshot/test/css.test.ts b/packages/rrweb-snapshot/test/css.test.ts index 6599839de4..2818386071 100644 --- a/packages/rrweb-snapshot/test/css.test.ts +++ b/packages/rrweb-snapshot/test/css.test.ts @@ -1,8 +1,5 @@ import { parse, Rule, Media } from '../src/css'; -import { - validateStringifiedCssRule, - escapeImportStatement, -} from './../src/utils'; +import { fixSafariColons, escapeImportStatement } from './../src/utils'; describe('css parser', () => { it('should save the filename and source', () => { @@ -112,15 +109,13 @@ describe('css parser', () => { }); it('parses : in attribute selectors correctly', () => { - const out1 = validateStringifiedCssRule('[data-foo] { color: red; }'); + const out1 = fixSafariColons('[data-foo] { color: red; }'); expect(out1).toEqual('[data-foo] { color: red; }'); - const out2 = validateStringifiedCssRule('[data-foo:other] { color: red; }'); + const out2 = fixSafariColons('[data-foo:other] { color: red; }'); expect(out2).toEqual('[data-foo\\:other] { color: red; }'); - const out3 = validateStringifiedCssRule( - '[data-aa\\:other] { color: red; }', - ); + const out3 = fixSafariColons('[data-aa\\:other] { color: red; }'); expect(out3).toEqual('[data-aa\\:other] { color: red; }'); }); diff --git a/yarn.lock b/yarn.lock index 784f857d42..34c29fb6fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5522,15 +5522,10 @@ csso@^4.0.2: dependencies: css-tree "^1.1.2" -cssom@^0.4.4, "cssom@https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz": +cssom@^0.4.4, cssom@^0.5.0, "cssom@https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz": version "0.6.0" resolved "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz#ed298055b97cbddcdeb278f904857629dec5e0e1" -cssom@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.5.0.tgz#d254fa92cd8b6fbd83811b9fbaed34663cc17c36" - integrity sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw== - cssom@~0.3.6: version "0.3.8" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" From 58c9104eddc8b7994a067a97daae5684e42f892f Mon Sep 17 00:00:00 2001 From: Eoghan Murray Date: Tue, 15 Aug 2023 10:39:29 +0100 Subject: [PATCH 027/123] Perf: Avoid creation of intermediary array when iterating over style rules (#1272) * Perf: Avoid creation of intermediary array when iterating over stylesheet rules by using the second `mapFn` argument of Array.from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from Performance analysis by: JonasBA Authored-by: Eoghan Murray --- .changeset/nervous-mirrors-perform.md | 6 ++++++ packages/rrweb-snapshot/src/utils.ts | 2 +- packages/rrweb/src/record/stylesheet-manager.ts | 11 ++++------- 3 files changed, 11 insertions(+), 8 deletions(-) create mode 100644 .changeset/nervous-mirrors-perform.md diff --git a/.changeset/nervous-mirrors-perform.md b/.changeset/nervous-mirrors-perform.md new file mode 100644 index 0000000000..46cf31fef8 --- /dev/null +++ b/.changeset/nervous-mirrors-perform.md @@ -0,0 +1,6 @@ +--- +'rrweb-snapshot': patch +'rrweb': patch +--- + +Perf: Avoid creation of intermediary array when iterating over style rules diff --git a/packages/rrweb-snapshot/src/utils.ts b/packages/rrweb-snapshot/src/utils.ts index 02043995fe..95444c18b3 100644 --- a/packages/rrweb-snapshot/src/utils.ts +++ b/packages/rrweb-snapshot/src/utils.ts @@ -98,7 +98,7 @@ export function stringifyStylesheet(s: CSSStyleSheet): string | null { const rules = s.rules || s.cssRules; return rules ? fixBrowserCompatibilityIssuesInCSS( - Array.from(rules).map(stringifyRule).join(''), + Array.from(rules, stringifyRule).join(''), ) : null; } catch (error) { diff --git a/packages/rrweb/src/record/stylesheet-manager.ts b/packages/rrweb/src/record/stylesheet-manager.ts index b517b7202e..6e0a8077b4 100644 --- a/packages/rrweb/src/record/stylesheet-manager.ts +++ b/packages/rrweb/src/record/stylesheet-manager.ts @@ -61,15 +61,12 @@ export class StylesheetManager { let styleId; if (!this.styleMirror.has(sheet)) { styleId = this.styleMirror.add(sheet); - const rules = Array.from(sheet.rules || CSSRule); styles.push({ styleId, - rules: rules.map((r, index) => { - return { - rule: stringifyRule(r), - index, - }; - }), + rules: Array.from(sheet.rules || CSSRule, (r, index) => ({ + rule: stringifyRule(r), + index, + })), }); } else styleId = this.styleMirror.getId(sheet); adoptedStyleSheetData.styleIds.push(styleId); From 297104cc8aac739ba7fefd98c3946ff5390f9cc3 Mon Sep 17 00:00:00 2001 From: Kento Moriwaki Date: Fri, 6 Oct 2023 18:42:59 +0900 Subject: [PATCH 028/123] Enable preserveSource (#1309) --- packages/rrweb/rollup.config.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/rrweb/rollup.config.js b/packages/rrweb/rollup.config.js index 4afb1ace2f..998433bda9 100644 --- a/packages/rrweb/rollup.config.js +++ b/packages/rrweb/rollup.config.js @@ -125,6 +125,7 @@ function getPlugins(options = {}) { webWorkerLoader({ targetPlatform: 'browser', inline: true, + preserveSource: true, sourceMap, }), esbuild({ @@ -144,7 +145,11 @@ for (const c of baseConfigs) { resolve({ browser: true }), // supports bundling `web-worker:..filename` - webWorkerLoader({ targetPlatform: 'browser' }), + webWorkerLoader({ + targetPlatform: 'browser', + inline: true, + preserveSource: true, + }), typescript(), ]; From 980a38c816d763833fc3491f56d03c959a41122d Mon Sep 17 00:00:00 2001 From: Eoghan Murray Date: Fri, 13 Oct 2023 09:58:20 +0100 Subject: [PATCH 029/123] Add config option to turn off all snapshotting and related observers (#1311) * Add config option to turn off all snapshotting and related observers - allows RRWEB to be used for click/movement tracking alone, e.g. for a heatmaps use case - could also be used if there was a separate process for recording the DOM (in which case a 3rd party library like https://github.com/antonmedv/finder could be added to record targets instead of the mirror) --------- Authored-by: eoghanmurray Co-authored-by: Justin Halsall --- .changeset/polite-olives-wave.md | 5 +++++ packages/rrweb/src/record/index.ts | 5 +++++ packages/rrweb/src/record/observer.ts | 31 ++++++++++++++++----------- packages/rrweb/src/types.ts | 2 ++ 4 files changed, 31 insertions(+), 12 deletions(-) create mode 100644 .changeset/polite-olives-wave.md diff --git a/.changeset/polite-olives-wave.md b/.changeset/polite-olives-wave.md new file mode 100644 index 0000000000..1d3e5987f3 --- /dev/null +++ b/.changeset/polite-olives-wave.md @@ -0,0 +1,5 @@ +--- +'rrweb': patch +--- + +Add 'recordDOM' config option to turn off recording of DOM (making recordings unreplayable). Specialist use case e.g. only heatmap click/scroll recording diff --git a/packages/rrweb/src/record/index.ts b/packages/rrweb/src/record/index.ts index 1c2141bfef..7308ac6d04 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -78,6 +78,7 @@ function record( sampling = {}, dataURLOptions = {}, mousemoveWait, + recordDOM = true, recordCanvas = false, recordCrossOriginIframes = false, recordAfter = options.recordAfter === 'DOMContentLoaded' @@ -345,6 +346,9 @@ function record( }); takeFullSnapshot = (isCheckout = false) => { + if (!recordDOM) { + return; + } wrappedEmit( wrapEvent({ type: EventType.Meta, @@ -529,6 +533,7 @@ function record( maskInputOptions, inlineStylesheet, sampling, + recordDOM, recordCanvas, inlineImages, userTriggeredOnInput, diff --git a/packages/rrweb/src/record/observer.ts b/packages/rrweb/src/record/observer.ts index 428cce1a4e..02a9ae8669 100644 --- a/packages/rrweb/src/record/observer.ts +++ b/packages/rrweb/src/record/observer.ts @@ -1282,7 +1282,10 @@ export function initObservers( } mergeHooks(o, hooks); - const mutationObserver = initMutationObserver(o, o.doc); + let mutationObserver: MutationObserver | undefined; + if (o.recordDOM) { + mutationObserver = initMutationObserver(o, o.doc); + } const mousemoveHandler = initMoveObserver(o); const mouseInteractionHandler = initMouseInteractionObserver(o); const scrollHandler = initScrollObserver(o); @@ -1292,16 +1295,20 @@ export function initObservers( const inputHandler = initInputObserver(o); const mediaInteractionHandler = initMediaInteractionObserver(o); - const styleSheetObserver = initStyleSheetObserver(o, { win: currentWindow }); - const adoptedStyleSheetObserver = initAdoptedStyleSheetObserver(o, o.doc); - const styleDeclarationObserver = initStyleDeclarationObserver(o, { - win: currentWindow, - }); - const fontObserver = o.collectFonts - ? initFontObserver(o) - : () => { - // - }; + let styleSheetObserver = () => {}; + let adoptedStyleSheetObserver = () => {}; + let styleDeclarationObserver = () => {}; + let fontObserver = () => {}; + if (o.recordDOM) { + styleSheetObserver = initStyleSheetObserver(o, { win: currentWindow }); + adoptedStyleSheetObserver = initAdoptedStyleSheetObserver(o, o.doc); + styleDeclarationObserver = initStyleDeclarationObserver(o, { + win: currentWindow, + }); + if (o.collectFonts) { + fontObserver = initFontObserver(o); + } + } const selectionObserver = initSelectionObserver(o); // plugins @@ -1314,7 +1321,7 @@ export function initObservers( return callbackWrapper(() => { mutationBuffers.forEach((b) => b.reset()); - mutationObserver.disconnect(); + mutationObserver?.disconnect(); mousemoveHandler(); mouseInteractionHandler(); scrollHandler(); diff --git a/packages/rrweb/src/types.ts b/packages/rrweb/src/types.ts index 17ed750e68..1ceb44222b 100644 --- a/packages/rrweb/src/types.ts +++ b/packages/rrweb/src/types.ts @@ -60,6 +60,7 @@ export type recordOptions = { packFn?: PackFn; sampling?: SamplingStrategy; dataURLOptions?: DataURLOptions; + recordDOM?: boolean; recordCanvas?: boolean; recordCrossOriginIframes?: boolean; recordAfter?: 'DOMContentLoaded' | 'load'; @@ -98,6 +99,7 @@ export type observerParam = { canvasMutationCb: canvasMutationCallback; fontCb: fontCallback; sampling: SamplingStrategy; + recordDOM: boolean; recordCanvas: boolean; inlineImages: boolean; userTriggeredOnInput: boolean; From 7c0dc9dfe1564c9d6624557c5b394e7844955882 Mon Sep 17 00:00:00 2001 From: Ben White Date: Fri, 13 Oct 2023 13:02:08 +0200 Subject: [PATCH 030/123] Extended text masking function to include relevant HTMLElement (#1310) * Extends maskTextFn to pass the HTMLElement to the deciding function --------- Authored-by: benjackwhite Co-authored-by: Justin Halsall Co-authored-by: Eoghan Murray --- .changeset/swift-dancers-rest.md | 6 + packages/rrweb-snapshot/src/snapshot.ts | 2 +- packages/rrweb-snapshot/src/types.ts | 2 +- packages/rrweb/src/record/mutation.ts | 4 +- packages/rrweb/src/utils.ts | 27 +- .../__snapshots__/integration.test.ts.snap | 354 +++++++++++++++++- packages/rrweb/test/html/mask-text.html | 4 + packages/rrweb/test/integration.test.ts | 20 + 8 files changed, 403 insertions(+), 16 deletions(-) create mode 100644 .changeset/swift-dancers-rest.md diff --git a/.changeset/swift-dancers-rest.md b/.changeset/swift-dancers-rest.md new file mode 100644 index 0000000000..bcedf6c875 --- /dev/null +++ b/.changeset/swift-dancers-rest.md @@ -0,0 +1,6 @@ +--- +'rrweb-snapshot': minor +'rrweb': minor +--- + +Extends maskTextFn to pass the HTMLElement to the deciding function diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index 02619296c8..0963e6cfef 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -575,7 +575,7 @@ function serializeTextNode( needMaskingText(n, maskTextClass, maskTextSelector) ) { textContent = maskTextFn - ? maskTextFn(textContent) + ? maskTextFn(textContent, n.parentElement) : textContent.replace(/[\S]/g, '*'); } diff --git a/packages/rrweb-snapshot/src/types.ts b/packages/rrweb-snapshot/src/types.ts index 9edb4dd6d4..e573dfc1e0 100644 --- a/packages/rrweb-snapshot/src/types.ts +++ b/packages/rrweb-snapshot/src/types.ts @@ -153,7 +153,7 @@ export type DataURLOptions = Partial<{ quality: number; }>; -export type MaskTextFn = (text: string) => string; +export type MaskTextFn = (text: string, element: HTMLElement | null) => string; export type MaskInputFn = (text: string, element: HTMLElement) => string; export type KeepIframeSrcFn = (src: string) => boolean; diff --git a/packages/rrweb/src/record/mutation.ts b/packages/rrweb/src/record/mutation.ts index 097d1a8fd5..80943d96ab 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -30,6 +30,7 @@ import { isSerializedStylesheet, inDom, getShadowHost, + closestElementOfNode, } from '../utils'; type DoubleLinkedListNode = { @@ -508,6 +509,7 @@ export default class MutationBuffer { switch (m.type) { case 'characterData': { const value = m.target.textContent; + if ( !isBlocked(m.target, this.blockClass, this.blockSelector, false) && value !== m.oldValue @@ -520,7 +522,7 @@ export default class MutationBuffer { this.maskTextSelector, ) && value ? this.maskTextFn - ? this.maskTextFn(value) + ? this.maskTextFn(value, closestElementOfNode(m.target)) : value.replace(/[\S]/g, '*') : value, node: m.target, diff --git a/packages/rrweb/src/utils.ts b/packages/rrweb/src/utils.ts index 604c8810e2..f426689d2f 100644 --- a/packages/rrweb/src/utils.ts +++ b/packages/rrweb/src/utils.ts @@ -215,6 +215,23 @@ export function getWindowWidth(): number { ); } +/** + * Returns the given node as an HTMLElement if it is one, otherwise the parent node as an HTMLElement + * @param node - node to check + * @returns HTMLElement or null + */ + +export function closestElementOfNode(node: Node | null): HTMLElement | null { + if (!node) { + return null; + } + const el: HTMLElement | null = + node.nodeType === node.ELEMENT_NODE + ? (node as HTMLElement) + : node.parentElement; + return el; +} + /** * Checks if the given element set to be blocked by rrweb * @param node - node to check @@ -232,11 +249,11 @@ export function isBlocked( if (!node) { return false; } - const el: HTMLElement | null = - node.nodeType === node.ELEMENT_NODE - ? (node as HTMLElement) - : node.parentElement; - if (!el) return false; + const el = closestElementOfNode(node); + + if (!el) { + return false; + } try { if (typeof blockClass === 'string') { diff --git a/packages/rrweb/test/__snapshots__/integration.test.ts.snap b/packages/rrweb/test/__snapshots__/integration.test.ts.snap index c95ec53a5f..e320254111 100644 --- a/packages/rrweb/test/__snapshots__/integration.test.ts.snap +++ b/packages/rrweb/test/__snapshots__/integration.test.ts.snap @@ -7109,9 +7109,29 @@ exports[`record integration tests should mask texts 1`] = ` }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\\\n \\", + \\"textContent\\": \\"\\\\n\\\\n \\", \\"id\\": 35 }, + { + \\"type\\": 2, + \\"tagName\\": \\"p\\", + \\"attributes\\": { + \\"data-unmask-example\\": \\"true\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n unmask1\\\\n \\", + \\"id\\": 37 + } + ], + \\"id\\": 36 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\", + \\"id\\": 38 + }, { \\"type\\": 2, \\"tagName\\": \\"script\\", @@ -7120,15 +7140,15 @@ exports[`record integration tests should mask texts 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 37 + \\"id\\": 40 } ], - \\"id\\": 36 + \\"id\\": 39 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 38 + \\"id\\": 41 } ], \\"id\\": 16 @@ -7387,9 +7407,29 @@ exports[`record integration tests should mask texts using maskTextFn 1`] = ` }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\\\n \\", + \\"textContent\\": \\"\\\\n\\\\n \\", \\"id\\": 35 }, + { + \\"type\\": 2, + \\"tagName\\": \\"p\\", + \\"attributes\\": { + \\"data-unmask-example\\": \\"true\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n unmask1\\\\n \\", + \\"id\\": 37 + } + ], + \\"id\\": 36 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\", + \\"id\\": 38 + }, { \\"type\\": 2, \\"tagName\\": \\"script\\", @@ -7398,15 +7438,15 @@ exports[`record integration tests should mask texts using maskTextFn 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 37 + \\"id\\": 40 } ], - \\"id\\": 36 + \\"id\\": 39 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 38 + \\"id\\": 41 } ], \\"id\\": 16 @@ -16237,6 +16277,304 @@ exports[`record integration tests should record webgl canvas mutations 1`] = ` ]" `; +exports[`record integration tests should unmask texts using maskTextFn 1`] = ` +"[ + { + \\"type\\": 0, + \\"data\\": {} + }, + { + \\"type\\": 1, + \\"data\\": {} + }, + { + \\"type\\": 4, + \\"data\\": { + \\"href\\": \\"about:blank\\", + \\"width\\": 1920, + \\"height\\": 1080 + } + }, + { + \\"type\\": 2, + \\"data\\": { + \\"node\\": { + \\"type\\": 0, + \\"childNodes\\": [ + { + \\"type\\": 1, + \\"name\\": \\"html\\", + \\"publicId\\": \\"\\", + \\"systemId\\": \\"\\", + \\"id\\": 2 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"html\\", + \\"attributes\\": { + \\"lang\\": \\"en\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"head\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 5 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"charset\\": \\"UTF-8\\" + }, + \\"childNodes\\": [], + \\"id\\": 6 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 7 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"name\\": \\"viewport\\", + \\"content\\": \\"width=device-width, initial-scale=1.0\\" + }, + \\"childNodes\\": [], + \\"id\\": 8 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 9 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"http-equiv\\": \\"X-UA-Compatible\\", + \\"content\\": \\"ie=edge\\" + }, + \\"childNodes\\": [], + \\"id\\": 10 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 11 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"title\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"M*** ****\\", + \\"id\\": 13 + } + ], + \\"id\\": 12 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 14 + } + ], + \\"id\\": 4 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 15 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"body\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 17 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"p\\", + \\"attributes\\": { + \\"class\\": \\"rr-mask\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"****1\\", + \\"id\\": 19 + } + ], + \\"id\\": 18 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 20 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"div\\", + \\"attributes\\": { + \\"class\\": \\"rr-mask\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 22 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"span\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"****2\\", + \\"id\\": 24 + } + ], + \\"id\\": 23 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 25 + } + ], + \\"id\\": 21 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 26 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"div\\", + \\"attributes\\": { + \\"data-masking\\": \\"true\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 28 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"div\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 30 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"div\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"****3\\", + \\"id\\": 32 + } + ], + \\"id\\": 31 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 33 + } + ], + \\"id\\": 29 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 34 + } + ], + \\"id\\": 27 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n\\\\n \\", + \\"id\\": 35 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"p\\", + \\"attributes\\": { + \\"data-unmask-example\\": \\"true\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n unmask1\\\\n \\", + \\"id\\": 37 + } + ], + \\"id\\": 36 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\", + \\"id\\": 38 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"script\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", + \\"id\\": 40 + } + ], + \\"id\\": 39 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", + \\"id\\": 41 + } + ], + \\"id\\": 16 + } + ], + \\"id\\": 3 + } + ], + \\"id\\": 1 + }, + \\"initialOffset\\": { + \\"left\\": 0, + \\"top\\": 0 + } + } + } +]" +`; + exports[`record integration tests will serialize node before record 1`] = ` "[ { diff --git a/packages/rrweb/test/html/mask-text.html b/packages/rrweb/test/html/mask-text.html index 2abaaaa511..135034b6af 100644 --- a/packages/rrweb/test/html/mask-text.html +++ b/packages/rrweb/test/html/mask-text.html @@ -16,5 +16,9 @@
mask3
+ +

+ unmask1 +

diff --git a/packages/rrweb/test/integration.test.ts b/packages/rrweb/test/integration.test.ts index edfc8a97af..c627be84cb 100644 --- a/packages/rrweb/test/integration.test.ts +++ b/packages/rrweb/test/integration.test.ts @@ -1170,6 +1170,26 @@ describe('record integration tests', function (this: ISuite) { assertSnapshot(snapshots); }); + it('should unmask texts using maskTextFn', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'mask-text.html', { + maskTextSelector: '*', + maskTextFn: (t: string, el: HTMLElement) => { + return el.matches('[data-unmask-example="true"]') + ? t + : t.replace(/[a-z]/g, '*'); + }, + }), + ); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + it('can mask character data mutations', async () => { const page: puppeteer.Page = await browser.newPage(); await page.goto('about:blank'); From 57a940afac0bdd14cd82937915d53110b5311673 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Fri, 13 Oct 2023 13:05:26 +0200 Subject: [PATCH 031/123] fix: Fix checking for `patchTarget` in `initAdoptedStyleSheetObserver` (#1327) --- .changeset/calm-oranges-sin.md | 5 +++++ packages/rrweb/src/record/observer.ts | 10 ++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 .changeset/calm-oranges-sin.md diff --git a/.changeset/calm-oranges-sin.md b/.changeset/calm-oranges-sin.md new file mode 100644 index 0000000000..a1449698e4 --- /dev/null +++ b/.changeset/calm-oranges-sin.md @@ -0,0 +1,5 @@ +--- +'rrweb': patch +--- + +fix: Fix checking for `patchTarget` in `initAdoptedStyleSheetObserver` diff --git a/packages/rrweb/src/record/observer.ts b/packages/rrweb/src/record/observer.ts index 02a9ae8669..c6b38cbb96 100644 --- a/packages/rrweb/src/record/observer.ts +++ b/packages/rrweb/src/record/observer.ts @@ -900,10 +900,12 @@ export function initAdoptedStyleSheetObserver( host.nodeName === '#document' ? (host as Document).defaultView?.Document : host.ownerDocument?.defaultView?.ShadowRoot; - const originalPropertyDescriptor = Object.getOwnPropertyDescriptor( - patchTarget?.prototype, - 'adoptedStyleSheets', - ); + const originalPropertyDescriptor = patchTarget?.prototype + ? Object.getOwnPropertyDescriptor( + patchTarget?.prototype, + 'adoptedStyleSheets', + ) + : undefined; if ( hostId === null || hostId === -1 || From 8444cb2dad6ceb4bef3e32a6adba05ab65b56e52 Mon Sep 17 00:00:00 2001 From: huangkairan <56213366+huangkairan@users.noreply.github.com> Date: Thu, 19 Oct 2023 22:10:21 -0500 Subject: [PATCH 032/123] =?UTF-8?q?=F0=9F=90=9E=20fix(web-extension):=20ty?= =?UTF-8?q?po=20(#1307)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Yun Feng --- .changeset/tiny-candles-whisper.md | 5 +++++ packages/web-extension/src/utils/channel.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/tiny-candles-whisper.md diff --git a/.changeset/tiny-candles-whisper.md b/.changeset/tiny-candles-whisper.md new file mode 100644 index 0000000000..770cb86f51 --- /dev/null +++ b/.changeset/tiny-candles-whisper.md @@ -0,0 +1,5 @@ +--- +'@rrweb/web-extension': patch +--- + +🐞 fix(web-extension): typo diff --git a/packages/web-extension/src/utils/channel.ts b/packages/web-extension/src/utils/channel.ts index 4268811eac..1a8e9b2a82 100644 --- a/packages/web-extension/src/utils/channel.ts +++ b/packages/web-extension/src/utils/channel.ts @@ -33,7 +33,7 @@ class Channel { private emitter = mitt(); constructor() { /** - * Register massage listener. + * Register message listener. */ Browser.runtime.onMessage.addListener( ((message: string, sender: Runtime.MessageSender) => { From 1fe39ab0db7f5d2b04f4a4f39fb5c0cfee33a1f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=9F=B9=E8=80=81=E6=9D=BF?= Date: Wed, 1 Nov 2023 01:20:25 +0800 Subject: [PATCH 033/123] Pref: export eventWithTime (#1324) * export eventWithTime for consumption in typescript code --- .changeset/lemon-lamps-switch.md | 5 +++++ packages/rrweb/src/index.ts | 1 + 2 files changed, 6 insertions(+) create mode 100644 .changeset/lemon-lamps-switch.md diff --git a/.changeset/lemon-lamps-switch.md b/.changeset/lemon-lamps-switch.md new file mode 100644 index 0000000000..b325dfe252 --- /dev/null +++ b/.changeset/lemon-lamps-switch.md @@ -0,0 +1,5 @@ +--- +'rrweb': patch +--- + +export eventWithTime for consumption by typescript code diff --git a/packages/rrweb/src/index.ts b/packages/rrweb/src/index.ts index ecc1695909..acf8155689 100644 --- a/packages/rrweb/src/index.ts +++ b/packages/rrweb/src/index.ts @@ -8,6 +8,7 @@ export { IncrementalSource, MouseInteractions, ReplayerEvents, + type eventWithTime } from '@rrweb/types'; export type { recordOptions } from './types'; From f362e7a84c4488aa5a85ab509239a22241d5a13f Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Fri, 3 Nov 2023 11:40:54 +0100 Subject: [PATCH 034/123] Fix linting issues (#1347) * Fix linting issues * Apply formatting changes --- packages/rrweb/src/index.ts | 2 +- packages/rrweb/src/record/observer.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/rrweb/src/index.ts b/packages/rrweb/src/index.ts index acf8155689..367df3eb5b 100644 --- a/packages/rrweb/src/index.ts +++ b/packages/rrweb/src/index.ts @@ -8,7 +8,7 @@ export { IncrementalSource, MouseInteractions, ReplayerEvents, - type eventWithTime + type eventWithTime, } from '@rrweb/types'; export type { recordOptions } from './types'; diff --git a/packages/rrweb/src/record/observer.ts b/packages/rrweb/src/record/observer.ts index c6b38cbb96..e23e5a1004 100644 --- a/packages/rrweb/src/record/observer.ts +++ b/packages/rrweb/src/record/observer.ts @@ -1297,9 +1297,13 @@ export function initObservers( const inputHandler = initInputObserver(o); const mediaInteractionHandler = initMediaInteractionObserver(o); + // eslint-disable-next-line @typescript-eslint/no-empty-function let styleSheetObserver = () => {}; + // eslint-disable-next-line @typescript-eslint/no-empty-function let adoptedStyleSheetObserver = () => {}; + // eslint-disable-next-line @typescript-eslint/no-empty-function let styleDeclarationObserver = () => {}; + // eslint-disable-next-line @typescript-eslint/no-empty-function let fontObserver = () => {}; if (o.recordDOM) { styleSheetObserver = initStyleSheetObserver(o, { win: currentWindow }); From 9c6edfe2261680b4e92284be69f9d183b1eca8f4 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Fri, 3 Nov 2023 12:09:21 +0100 Subject: [PATCH 035/123] ref: Avoid unnecessary cloning of objects or arrays (#1340) --- .changeset/gold-apples-joke.md | 5 ++++ packages/rrweb/src/record/observer.ts | 28 +++++-------------- .../rrweb/src/record/observers/canvas/2d.ts | 2 +- .../record/observers/canvas/serialize-args.ts | 2 +- .../src/record/observers/canvas/webgl.ts | 2 +- 5 files changed, 15 insertions(+), 24 deletions(-) create mode 100644 .changeset/gold-apples-joke.md diff --git a/.changeset/gold-apples-joke.md b/.changeset/gold-apples-joke.md new file mode 100644 index 0000000000..4ad27974b8 --- /dev/null +++ b/.changeset/gold-apples-joke.md @@ -0,0 +1,5 @@ +--- +'rrweb': patch +--- + +ref: Avoid unnecessary cloning of objects or arrays diff --git a/packages/rrweb/src/record/observer.ts b/packages/rrweb/src/record/observer.ts index e23e5a1004..a8dde3319f 100644 --- a/packages/rrweb/src/record/observer.ts +++ b/packages/rrweb/src/record/observer.ts @@ -405,15 +405,6 @@ function initViewportResizeObserver( return on('resize', updateDimension, win); } -function wrapEventWithUserTriggeredFlag( - v: inputValue, - enable: boolean, -): inputValue { - const value = { ...v }; - if (!enable) delete value.userTriggered; - return value; -} - export const INPUT_TAGS = ['INPUT', 'TEXTAREA', 'SELECT']; const lastInputValueMap: WeakMap = new WeakMap(); function initInputObserver({ @@ -477,10 +468,9 @@ function initInputObserver({ } cbWithDedup( target, - callbackWrapper(wrapEventWithUserTriggeredFlag)( - { text, isChecked, userTriggered }, - userTriggeredOnInput, - ), + userTriggeredOnInput + ? { text, isChecked, userTriggered } + : { text, isChecked }, ); // if a radio was checked // the other radios with the same name attribute will be unchecked. @@ -490,16 +480,12 @@ function initInputObserver({ .querySelectorAll(`input[type="radio"][name="${name}"]`) .forEach((el) => { if (el !== target) { + const text = (el as HTMLInputElement).value; cbWithDedup( el, - callbackWrapper(wrapEventWithUserTriggeredFlag)( - { - text: (el as HTMLInputElement).value, - isChecked: !isChecked, - userTriggered: false, - }, - userTriggeredOnInput, - ), + userTriggeredOnInput + ? { text, isChecked: !isChecked, userTriggered: false } + : { text, isChecked: !isChecked }, ); } }); diff --git a/packages/rrweb/src/record/observers/canvas/2d.ts b/packages/rrweb/src/record/observers/canvas/2d.ts index d74a4edc0c..b496b6b93a 100644 --- a/packages/rrweb/src/record/observers/canvas/2d.ts +++ b/packages/rrweb/src/record/observers/canvas/2d.ts @@ -45,7 +45,7 @@ export default function initCanvas2DMutationObserver( // Using setTimeout as toDataURL can be heavy // and we'd rather not block the main thread setTimeout(() => { - const recordArgs = serializeArgs([...args], win, this); + const recordArgs = serializeArgs(args, win, this); cb(this.canvas, { type: CanvasContext['2D'], property: prop, diff --git a/packages/rrweb/src/record/observers/canvas/serialize-args.ts b/packages/rrweb/src/record/observers/canvas/serialize-args.ts index adc15a91b9..30e20fcb0c 100644 --- a/packages/rrweb/src/record/observers/canvas/serialize-args.ts +++ b/packages/rrweb/src/record/observers/canvas/serialize-args.ts @@ -133,7 +133,7 @@ export const serializeArgs = ( win: IWindow, ctx: RenderingContext, ) => { - return [...args].map((arg) => serializeArg(arg, win, ctx)); + return args.map((arg) => serializeArg(arg, win, ctx)); }; export const isInstanceOfWebGLObject = ( diff --git a/packages/rrweb/src/record/observers/canvas/webgl.ts b/packages/rrweb/src/record/observers/canvas/webgl.ts index 6a4fe6c849..680890f666 100644 --- a/packages/rrweb/src/record/observers/canvas/webgl.ts +++ b/packages/rrweb/src/record/observers/canvas/webgl.ts @@ -53,7 +53,7 @@ function patchGLPrototype( 'tagName' in this.canvas && !isBlocked(this.canvas, blockClass, blockSelector, true) ) { - const recordArgs = serializeArgs([...args], win, this); + const recordArgs = serializeArgs(args, win, this); const mutation: canvasMutationWithType = { type, property: prop, From 05478c36dde03a118099783d908bb3e465e9859c Mon Sep 17 00:00:00 2001 From: Michael Dellanoce Date: Fri, 3 Nov 2023 18:03:59 -0400 Subject: [PATCH 036/123] perf(rrweb): attribute mutation optimization (#1343) --- .changeset/moody-dots-refuse.md | 5 +++++ packages/rrweb/src/record/mutation.ts | 7 ++++--- .../rrweb/test/benchmark/dom-mutation.test.ts | 6 ++++++ .../benchmark-dom-mutation-attributes.html | 21 +++++++++++++++++++ 4 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 .changeset/moody-dots-refuse.md create mode 100644 packages/rrweb/test/html/benchmark-dom-mutation-attributes.html diff --git a/.changeset/moody-dots-refuse.md b/.changeset/moody-dots-refuse.md new file mode 100644 index 0000000000..32270da384 --- /dev/null +++ b/.changeset/moody-dots-refuse.md @@ -0,0 +1,5 @@ +--- +'rrweb': patch +--- + +use WeakMap for faster attributeCursor lookup while processing attribute mutations diff --git a/packages/rrweb/src/record/mutation.ts b/packages/rrweb/src/record/mutation.ts index 80943d96ab..440f308696 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -142,6 +142,7 @@ export default class MutationBuffer { private texts: textCursor[] = []; private attributes: attributeCursor[] = []; + private attributeMap = new WeakMap(); private removes: removedNodeMutation[] = []; private mapRemoves: Node[] = []; @@ -485,6 +486,7 @@ export default class MutationBuffer { // reset this.texts = []; this.attributes = []; + this.attributeMap = new WeakMap(); this.removes = []; this.addedSet = new Set(); this.movedSet = new Set(); @@ -554,9 +556,7 @@ export default class MutationBuffer { return; } - let item: attributeCursor | undefined = this.attributes.find( - (a) => a.node === m.target, - ); + let item = this.attributeMap.get(m.target); if ( target.tagName === 'IFRAME' && attributeName === 'src' && @@ -578,6 +578,7 @@ export default class MutationBuffer { _unchangedStyles: {}, }; this.attributes.push(item); + this.attributeMap.set(m.target, item); } // Keep this property on inputs that used to be password inputs diff --git a/packages/rrweb/test/benchmark/dom-mutation.test.ts b/packages/rrweb/test/benchmark/dom-mutation.test.ts index 3da794db45..a4124c3f98 100644 --- a/packages/rrweb/test/benchmark/dom-mutation.test.ts +++ b/packages/rrweb/test/benchmark/dom-mutation.test.ts @@ -42,6 +42,12 @@ const suites: Array< eval: 'window.workload()', times: 5, }, + { + title: 'modify attributes on 10000 DOM nodes', + html: 'benchmark-dom-mutation-attributes.html', + eval: 'window.workload()', + times: 10, + }, ]; function avg(v: number[]): number { diff --git a/packages/rrweb/test/html/benchmark-dom-mutation-attributes.html b/packages/rrweb/test/html/benchmark-dom-mutation-attributes.html new file mode 100644 index 0000000000..3d00b26b4d --- /dev/null +++ b/packages/rrweb/test/html/benchmark-dom-mutation-attributes.html @@ -0,0 +1,21 @@ + + + + From 9e65dda258c9b8169a4a6486b5c018f42f6c512a Mon Sep 17 00:00:00 2001 From: huangkairan <56213366+huangkairan@users.noreply.github.com> Date: Sat, 4 Nov 2023 06:10:00 +0800 Subject: [PATCH 037/123] fix(web-extension): beforeunload logic (#1330) --- .changeset/witty-kids-talk.md | 5 +++++ packages/web-extension/src/content/index.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/witty-kids-talk.md diff --git a/.changeset/witty-kids-talk.md b/.changeset/witty-kids-talk.md new file mode 100644 index 0000000000..4a9d4f000a --- /dev/null +++ b/.changeset/witty-kids-talk.md @@ -0,0 +1,5 @@ +--- +'@rrweb/web-extension': patch +--- + +🐞 fix(web-extension): beforeunload logic diff --git a/packages/web-extension/src/content/index.ts b/packages/web-extension/src/content/index.ts index 5f99e974aa..fce329e711 100644 --- a/packages/web-extension/src/content/index.ts +++ b/packages/web-extension/src/content/index.ts @@ -155,8 +155,8 @@ async function initMainPage() { // Before unload pages, cache the new events in the local storage. window.addEventListener('beforeunload', (event) => { + if (!newEvents.length) return; event.preventDefault(); - if (newEvents.length === 0) return; void Browser.storage.local.set({ [LocalDataKey.bufferedEvents]: bufferedEvents.concat(newEvents), }); From 5add06fd933842b78f2ab40e59312e737fcaee93 Mon Sep 17 00:00:00 2001 From: Lukas Boehler Date: Fri, 3 Nov 2023 23:17:10 +0100 Subject: [PATCH 038/123] Added Gleap.io to "Who's using rrweb?" (#1332) Co-authored-by: Justin Halsall --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index d198499df9..cdcddce146 100644 --- a/README.md +++ b/README.md @@ -226,5 +226,10 @@ In addition to adding integration tests and unit tests, rrweb also provides a RE Intercept, Modify, Record & Replay HTTP Requests. + + + In-app bug reporting & customer feedback platform. + + From 40f484d088390b480f088d1b1c1c152641cd5878 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Fri, 3 Nov 2023 19:53:49 -0230 Subject: [PATCH 039/123] fix(web-extension): Fix types in vite config (#1333) --- .changeset/mighty-bulldogs-begin.md | 5 +++++ packages/web-extension/vite.config.ts | 23 ++++++++++++++--------- 2 files changed, 19 insertions(+), 9 deletions(-) create mode 100644 .changeset/mighty-bulldogs-begin.md diff --git a/.changeset/mighty-bulldogs-begin.md b/.changeset/mighty-bulldogs-begin.md new file mode 100644 index 0000000000..b2623ab7c8 --- /dev/null +++ b/.changeset/mighty-bulldogs-begin.md @@ -0,0 +1,5 @@ +--- +'@rrweb/web-extension': patch +--- + +Update `vite.config.ts` to account for all potential entry types. diff --git a/packages/web-extension/vite.config.ts b/packages/web-extension/vite.config.ts index 95809cb727..76d2c631a3 100644 --- a/packages/web-extension/vite.config.ts +++ b/packages/web-extension/vite.config.ts @@ -1,9 +1,4 @@ -import { - defineConfig, - LibraryFormats, - LibraryOptions, - PluginOption, -} from 'vite'; +import { defineConfig, LibraryFormats, PluginOption } from 'vite'; import webExtension, { readJsonFile } from 'vite-plugin-web-extension'; import zip from 'vite-plugin-zip-pack'; import * as path from 'path'; @@ -17,9 +12,19 @@ function useSpecialFormat( return { name: 'use-special-format', config(config) { - const shouldUse = entriesToUse.includes( - (config.build?.lib as LibraryOptions)?.entry, - ); + // entry can be string | string[] | {[entryAlias: string]: string} + const entry = config.build?.lib && config.build.lib.entry; + let shouldUse = false; + + if (typeof entry === 'string') { + shouldUse = entriesToUse.includes(entry); + } else if (Array.isArray(entry)) { + shouldUse = entriesToUse.some((e) => entry.includes(e)); + } else if (entry && typeof entry === 'object') { + const entryKeys = Object.keys(entry); + shouldUse = entriesToUse.some((e) => entryKeys.includes(e)); + } + if (shouldUse) { config.build = config.build ?? {}; // @ts-expect-error: lib needs to be an object, forcing it. From dbd15a949263befa8d019fc5f9df8ee967398e0f Mon Sep 17 00:00:00 2001 From: Eoghan Murray Date: Mon, 6 Nov 2023 10:10:07 +0000 Subject: [PATCH 040/123] Md create html document (#1321) * only call createHTMLDocument where it is needed * Perf: create the mutation document once as a 'singleton' as it can be reused --------- Co-authored-by: Michael Dellanoce --- packages/rrweb/src/record/mutation.ts | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/rrweb/src/record/mutation.ts b/packages/rrweb/src/record/mutation.ts index 440f308696..7c209605d0 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -190,6 +190,7 @@ export default class MutationBuffer { private shadowDomManager: observerParam['shadowDomManager']; private canvasManager: observerParam['canvasManager']; private processedNodeManager: observerParam['processedNodeManager']; + private unattachedDoc: HTMLDocument; public init(options: MutationBufferParam) { ( @@ -500,14 +501,6 @@ export default class MutationBuffer { if (isIgnored(m.target, this.mirror)) { return; } - let unattachedDoc; - try { - // avoid upsetting original document from a Content Security point of view - unattachedDoc = document.implementation.createHTMLDocument(); - } catch (e) { - // fallback to more direct method - unattachedDoc = this.doc; - } switch (m.type) { case 'characterData': { const value = m.target.textContent; @@ -600,7 +593,17 @@ export default class MutationBuffer { value, ); if (attributeName === 'style') { - const old = unattachedDoc.createElement('span'); + if (!this.unattachedDoc) { + try { + // avoid upsetting original document from a Content Security point of view + this.unattachedDoc = + document.implementation.createHTMLDocument(); + } catch (e) { + // fallback to more direct method + this.unattachedDoc = this.doc; + } + } + const old = this.unattachedDoc.createElement('span'); if (m.oldValue) { old.setAttribute('style', m.oldValue); } From 8aea5b00a4dfe5a6f59bd2ae72bb624f45e51e81 Mon Sep 17 00:00:00 2001 From: Yun Feng Date: Wed, 8 Nov 2023 01:26:13 +1100 Subject: [PATCH 041/123] Feat: Add support for replaying :defined pseudo-class of custom elements (#1155) * Feat: Add support for replaying :defined pseudo-class of custom elements * add isCustom flag to serialized elements Applying Justin's review suggestion * fix code lint error * add custom element event * fix: tests (#1348) * Update packages/rrweb/src/record/observer.ts * Update packages/rrweb/src/record/observer.ts --------- Co-authored-by: Nafees Nehar Co-authored-by: Justin Halsall --- .changeset/fluffy-planes-retire.md | 5 ++ .changeset/smart-ears-refuse.md | 7 ++ packages/rrweb-snapshot/src/rebuild.ts | 12 +++ packages/rrweb-snapshot/src/snapshot.ts | 8 ++ packages/rrweb-snapshot/src/types.ts | 2 + .../__snapshots__/integration.test.ts.snap | 1 + packages/rrweb-snapshot/tsconfig.json | 1 + packages/rrweb/src/record/iframe-manager.ts | 1 + packages/rrweb/src/record/index.ts | 11 +++ packages/rrweb/src/record/observer.ts | 48 ++++++++++ packages/rrweb/src/types.ts | 2 + .../events/custom-element-define-class.ts | 89 +++++++++++++++++++ packages/rrweb/test/replayer.test.ts | 16 ++++ packages/types/src/index.ts | 17 +++- 14 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 .changeset/fluffy-planes-retire.md create mode 100644 .changeset/smart-ears-refuse.md create mode 100644 packages/rrweb/test/events/custom-element-define-class.ts diff --git a/.changeset/fluffy-planes-retire.md b/.changeset/fluffy-planes-retire.md new file mode 100644 index 0000000000..41e9601704 --- /dev/null +++ b/.changeset/fluffy-planes-retire.md @@ -0,0 +1,5 @@ +--- +'rrweb': patch +--- + +Feat: Add support for replaying :defined pseudo-class of custom elements diff --git a/.changeset/smart-ears-refuse.md b/.changeset/smart-ears-refuse.md new file mode 100644 index 0000000000..0aaaabcf0f --- /dev/null +++ b/.changeset/smart-ears-refuse.md @@ -0,0 +1,7 @@ +--- +'rrweb-snapshot': patch +--- + +Feat: Add 'isCustom' flag to serialized elements. + +This flag is used to indicate whether the element is a custom element or not. This is useful for replaying the :defined pseudo-class of custom elements. diff --git a/packages/rrweb-snapshot/src/rebuild.ts b/packages/rrweb-snapshot/src/rebuild.ts index 5cf52ebd38..c3b15babba 100644 --- a/packages/rrweb-snapshot/src/rebuild.ts +++ b/packages/rrweb-snapshot/src/rebuild.ts @@ -142,6 +142,18 @@ function buildNode( if (n.isSVG) { node = doc.createElementNS('http://www.w3.org/2000/svg', tagName); } else { + if ( + // If the tag name is a custom element name + n.isCustom && + // If the browser supports custom elements + doc.defaultView?.customElements && + // If the custom element hasn't been defined yet + !doc.defaultView.customElements.get(n.tagName) + ) + doc.defaultView.customElements.define( + n.tagName, + class extends doc.defaultView.HTMLElement {}, + ); node = doc.createElement(tagName); } /** diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index 0963e6cfef..e6b25dc92b 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -801,6 +801,13 @@ function serializeElementNode( delete attributes.src; // prevent auto loading } + let isCustomElement: true | undefined; + try { + if (customElements.get(tagName)) isCustomElement = true; + } catch (e) { + // In case old browsers don't support customElements + } + return { type: NodeType.Element, tagName, @@ -809,6 +816,7 @@ function serializeElementNode( isSVG: isSVGElement(n as Element) || undefined, needBlock, rootId, + isCustom: isCustomElement, }; } diff --git a/packages/rrweb-snapshot/src/types.ts b/packages/rrweb-snapshot/src/types.ts index e573dfc1e0..90d31c171a 100644 --- a/packages/rrweb-snapshot/src/types.ts +++ b/packages/rrweb-snapshot/src/types.ts @@ -38,6 +38,8 @@ export type elementNode = { childNodes: serializedNodeWithId[]; isSVG?: true; needBlock?: boolean; + // This is a custom element or not. + isCustom?: true; }; export type textNode = { diff --git a/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap b/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap index a50f27cebe..77beb3be81 100644 --- a/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap +++ b/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap @@ -839,6 +839,7 @@ exports[`shadow DOM integration tests snapshot shadow DOM 1`] = ` \\"isShadow\\": true } ], + \\"isCustom\\": true, \\"id\\": 16, \\"isShadowHost\\": true }, diff --git a/packages/rrweb-snapshot/tsconfig.json b/packages/rrweb-snapshot/tsconfig.json index 879f459ae4..58577aa6a9 100644 --- a/packages/rrweb-snapshot/tsconfig.json +++ b/packages/rrweb-snapshot/tsconfig.json @@ -2,6 +2,7 @@ "compilerOptions": { "composite": true, "module": "ESNext", + "target": "ES6", "moduleResolution": "Node", "noImplicitAny": true, "strictNullChecks": true, diff --git a/packages/rrweb/src/record/iframe-manager.ts b/packages/rrweb/src/record/iframe-manager.ts index 377b7bc0ff..26985cc49a 100644 --- a/packages/rrweb/src/record/iframe-manager.ts +++ b/packages/rrweb/src/record/iframe-manager.ts @@ -235,6 +235,7 @@ export class IframeManager { } } } + return false; } private replace>( diff --git a/packages/rrweb/src/record/index.ts b/packages/rrweb/src/record/index.ts index 7308ac6d04..3b4475cfc9 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -525,6 +525,17 @@ function record( }), ); }, + customElementCb: (c) => { + wrappedEmit( + wrapEvent({ + type: EventType.IncrementalSnapshot, + data: { + source: IncrementalSource.CustomElement, + ...c, + }, + }), + ); + }, blockClass, ignoreClass, ignoreSelector, diff --git a/packages/rrweb/src/record/observer.ts b/packages/rrweb/src/record/observer.ts index a8dde3319f..0aa0f9856b 100644 --- a/packages/rrweb/src/record/observer.ts +++ b/packages/rrweb/src/record/observer.ts @@ -46,6 +46,7 @@ import { IWindow, SelectionRange, selectionCallback, + customElementCallback, } from '@rrweb/types'; import MutationBuffer from './mutation'; import { callbackWrapper } from './error-handler'; @@ -1169,6 +1170,44 @@ function initSelectionObserver(param: observerParam): listenerHandler { return on('selectionchange', updateSelection); } +function initCustomElementObserver({ + doc, + customElementCb, +}: observerParam): listenerHandler { + const win = doc.defaultView as IWindow; + // eslint-disable-next-line @typescript-eslint/no-empty-function + if (!win || !win.customElements) return () => {}; + const restoreHandler = patch( + win.customElements, + 'define', + function ( + original: ( + name: string, + constructor: CustomElementConstructor, + options?: ElementDefinitionOptions, + ) => void, + ) { + return function ( + name: string, + constructor: CustomElementConstructor, + options?: ElementDefinitionOptions, + ) { + try { + customElementCb({ + define: { + name, + }, + }); + } catch (e) { + console.warn(`Custom element callback failed for ${name}`); + } + return original.apply(this, [name, constructor, options]); + }; + }, + ); + return restoreHandler; +} + function mergeHooks(o: observerParam, hooks: hooksParam) { const { mutationCb, @@ -1183,6 +1222,7 @@ function mergeHooks(o: observerParam, hooks: hooksParam) { canvasMutationCb, fontCb, selectionCb, + customElementCb, } = o; o.mutationCb = (...p: Arguments) => { if (hooks.mutation) { @@ -1256,6 +1296,12 @@ function mergeHooks(o: observerParam, hooks: hooksParam) { } selectionCb(...p); }; + o.customElementCb = (...c: Arguments) => { + if (hooks.customElement) { + hooks.customElement(...c); + } + customElementCb(...c); + }; } export function initObservers( @@ -1302,6 +1348,7 @@ export function initObservers( } } const selectionObserver = initSelectionObserver(o); + const customElementObserver = initCustomElementObserver(o); // plugins const pluginHandlers: listenerHandler[] = []; @@ -1325,6 +1372,7 @@ export function initObservers( styleDeclarationObserver(); fontObserver(); selectionObserver(); + customElementObserver(); pluginHandlers.forEach((h) => h()); }); } diff --git a/packages/rrweb/src/types.ts b/packages/rrweb/src/types.ts index 1ceb44222b..e815ad753b 100644 --- a/packages/rrweb/src/types.ts +++ b/packages/rrweb/src/types.ts @@ -17,6 +17,7 @@ import type { addedNodeMutation, blockClass, canvasMutationCallback, + customElementCallback, eventWithTime, fontCallback, hooksParam, @@ -97,6 +98,7 @@ export type observerParam = { styleSheetRuleCb: styleSheetRuleCallback; styleDeclarationCb: styleDeclarationCallback; canvasMutationCb: canvasMutationCallback; + customElementCb: customElementCallback; fontCb: fontCallback; sampling: SamplingStrategy; recordDOM: boolean; diff --git a/packages/rrweb/test/events/custom-element-define-class.ts b/packages/rrweb/test/events/custom-element-define-class.ts new file mode 100644 index 0000000000..3f9bd9fa6b --- /dev/null +++ b/packages/rrweb/test/events/custom-element-define-class.ts @@ -0,0 +1,89 @@ +import { EventType } from '@rrweb/types'; +import type { eventWithTime } from '@rrweb/types'; + +const now = Date.now(); +const events: eventWithTime[] = [ + { + type: EventType.DomContentLoaded, + data: {}, + timestamp: now, + }, + { + type: EventType.Load, + data: {}, + timestamp: now + 100, + }, + { + type: EventType.Meta, + data: { + href: 'http://localhost', + width: 1000, + height: 800, + }, + timestamp: now + 100, + }, + // full snapshot: + { + data: { + node: { + id: 1, + type: 0, + childNodes: [ + { id: 2, name: 'html', type: 1, publicId: '', systemId: '' }, + { + id: 3, + type: 2, + tagName: 'html', + attributes: { lang: 'en' }, + childNodes: [ + { + id: 4, + type: 2, + tagName: 'head', + attributes: {}, + childNodes: [ + { + id: 5, + type: 2, + tagName: 'style', + childNodes: [ + { + id: 6, + type: 3, + isStyle: true, + // Set style of defined custom element to display: block + // Set undefined custom element to display: none + textContent: + 'custom-element:not(:defined) { display: none;} \n custom-element:defined { display: block; }', + }, + ], + }, + ], + }, + { + id: 7, + type: 2, + tagName: 'body', + attributes: {}, + childNodes: [ + { + id: 8, + type: 2, + tagName: 'custom-element', + childNodes: [], + isCustom: true, + }, + ], + }, + ], + }, + ], + }, + initialOffset: { top: 0, left: 0 }, + }, + type: EventType.FullSnapshot, + timestamp: now + 100, + }, +]; + +export default events; diff --git a/packages/rrweb/test/replayer.test.ts b/packages/rrweb/test/replayer.test.ts index 7756710410..183d2417fb 100644 --- a/packages/rrweb/test/replayer.test.ts +++ b/packages/rrweb/test/replayer.test.ts @@ -22,6 +22,7 @@ import adoptedStyleSheet from './events/adopted-style-sheet'; import adoptedStyleSheetModification from './events/adopted-style-sheet-modification'; import documentReplacementEvents from './events/document-replacement'; import hoverInIframeShadowDom from './events/iframe-shadowdom-hover'; +import customElementDefineClass from './events/custom-element-define-class'; import { ReplayerEvents } from '@rrweb/types'; interface ISuite { @@ -1076,4 +1077,19 @@ describe('replayer', function () { ), ).toBe(':hover'); }); + + it('should replay styles with :define pseudo-class', async () => { + await page.evaluate(`events = ${JSON.stringify(customElementDefineClass)}`); + + const displayValue = await page.evaluate(` + const { Replayer } = rrweb; + const replayer = new Replayer(events); + replayer.pause(200); + const customElement = replayer.iframe.contentDocument.querySelector('custom-element'); + window.getComputedStyle(customElement).display; + `); + // If the custom element is not defined, the display value will be 'none'. + // If the custom element is defined, the display value will be 'block'. + expect(displayValue).toEqual('block'); + }); }); diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index e6f6f15cd3..d4584847ee 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -83,6 +83,7 @@ export enum IncrementalSource { StyleDeclaration, Selection, AdoptedStyleSheet, + CustomElement, } export type mutationData = { @@ -142,6 +143,10 @@ export type adoptedStyleSheetData = { source: IncrementalSource.AdoptedStyleSheet; } & adoptedStyleSheetParam; +export type customElementData = { + source: IncrementalSource.CustomElement; +} & customElementParam; + export type incrementalData = | mutationData | mousemoveData @@ -155,7 +160,8 @@ export type incrementalData = | fontData | selectionData | styleDeclarationData - | adoptedStyleSheetData; + | adoptedStyleSheetData + | customElementData; export type event = | domContentLoadedEvent @@ -262,6 +268,7 @@ export type hooksParam = { canvasMutation?: canvasMutationCallback; font?: fontCallback; selection?: selectionCallback; + customElement?: customElementCallback; }; // https://dom.spec.whatwg.org/#interface-mutationrecord @@ -593,6 +600,14 @@ export type selectionParam = { export type selectionCallback = (p: selectionParam) => void; +export type customElementParam = { + define?: { + name: string; + }; +}; + +export type customElementCallback = (c: customElementParam) => void; + export type DeprecatedMirror = { map: { [key: number]: INode; From 07ac5c9e1371824ec3ffb705f9250bbe10f4b73e Mon Sep 17 00:00:00 2001 From: Eoghan Murray Date: Fri, 24 Nov 2023 16:06:02 +0000 Subject: [PATCH 042/123] Masking: Avoid the repeated calls to `closest` when recursing through the DOM (#1349) * masking performance: avoid the repeated calls to `closest` when recursing through the DOM - needsMask===true means that an ancestor has tested positively for masking, and so this node and all descendents should be masked - needsMask===false means that no ancestors have tested positively for masking, we should check each node encountered - needsMask===undefined means that we don't know whether ancestors are masked or not (e.g. after a mutation) and should look up the tree * Add tests including an explicit characterData mutation tests * Further performance improvement: avoid calls to `el.matches` when on a leaf node, e.g. a `
` --------- Authored-by: eoghanmurray Based on initial PR #1338 by Alexey Babik --- .changeset/thin-vans-applaud.md | 6 + packages/rrweb-snapshot/src/snapshot.ts | 63 +++-- packages/rrweb/src/record/mutation.ts | 1 + .../__snapshots__/integration.test.ts.snap | 237 ++++++++++++++++++ packages/rrweb/test/integration.test.ts | 39 +++ packages/rrweb/test/utils.ts | 1 + 6 files changed, 323 insertions(+), 24 deletions(-) create mode 100644 .changeset/thin-vans-applaud.md diff --git a/.changeset/thin-vans-applaud.md b/.changeset/thin-vans-applaud.md new file mode 100644 index 0000000000..e5d8d32a63 --- /dev/null +++ b/.changeset/thin-vans-applaud.md @@ -0,0 +1,6 @@ +--- +'rrweb-snapshot': patch +'rrweb': patch +--- + +Snapshot performance when masking text: Avoid the repeated calls to `closest` when recursing through the DOM diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index e6b25dc92b..6d2f2ed2e8 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -310,6 +310,7 @@ export function needMaskingText( node: Node, maskTextClass: string | RegExp, maskTextSelector: string | null, + checkAncestors: boolean, ): boolean { try { const el: HTMLElement | null = @@ -317,17 +318,21 @@ export function needMaskingText( ? (node as HTMLElement) : node.parentElement; if (el === null) return false; - if (typeof maskTextClass === 'string') { - if (el.classList.contains(maskTextClass)) return true; - if (el.closest(`.${maskTextClass}`)) return true; + if (checkAncestors) { + if (el.closest(`.${maskTextClass}`)) return true; + } else { + if (el.classList.contains(maskTextClass)) return true; + } } else { - if (classMatchesRegex(el, maskTextClass, true)) return true; + if (classMatchesRegex(el, maskTextClass, checkAncestors)) return true; } - if (maskTextSelector) { - if (el.matches(maskTextSelector)) return true; - if (el.closest(maskTextSelector)) return true; + if (checkAncestors) { + if (el.closest(maskTextSelector)) return true; + } else { + if (el.matches(maskTextSelector)) return true; + } } } catch (e) { // @@ -426,8 +431,7 @@ function serializeNode( mirror: Mirror; blockClass: string | RegExp; blockSelector: string | null; - maskTextClass: string | RegExp; - maskTextSelector: string | null; + needsMask: boolean | undefined; inlineStylesheet: boolean; maskInputOptions: MaskInputOptions; maskTextFn: MaskTextFn | undefined; @@ -447,8 +451,7 @@ function serializeNode( mirror, blockClass, blockSelector, - maskTextClass, - maskTextSelector, + needsMask, inlineStylesheet, maskInputOptions = {}, maskTextFn, @@ -500,8 +503,7 @@ function serializeNode( }); case n.TEXT_NODE: return serializeTextNode(n as Text, { - maskTextClass, - maskTextSelector, + needsMask, maskTextFn, rootId, }); @@ -531,13 +533,12 @@ function getRootId(doc: Document, mirror: Mirror): number | undefined { function serializeTextNode( n: Text, options: { - maskTextClass: string | RegExp; - maskTextSelector: string | null; + needsMask: boolean | undefined; maskTextFn: MaskTextFn | undefined; rootId: number | undefined; }, ): serializedNode { - const { maskTextClass, maskTextSelector, maskTextFn, rootId } = options; + const { needsMask, maskTextFn, rootId } = options; // The parent node may not be a html element which has a tagName attribute. // So just let it be undefined which is ok in this use case. const parentTagName = n.parentNode && (n.parentNode as HTMLElement).tagName; @@ -568,12 +569,7 @@ function serializeTextNode( if (isScript) { textContent = 'SCRIPT_PLACEHOLDER'; } - if ( - !isStyle && - !isScript && - textContent && - needMaskingText(n, maskTextClass, maskTextSelector) - ) { + if (!isStyle && !isScript && textContent && needsMask) { textContent = maskTextFn ? maskTextFn(textContent, n.parentElement) : textContent.replace(/[\S]/g, '*'); @@ -935,6 +931,7 @@ export function serializeNodeWithId( inlineStylesheet: boolean; newlyAddedElement?: boolean; maskInputOptions?: MaskInputOptions; + needsMask?: boolean; maskTextFn: MaskTextFn | undefined; maskInputFn: MaskInputFn | undefined; slimDOMOptions: SlimDOMOptions; @@ -980,14 +977,29 @@ export function serializeNodeWithId( keepIframeSrcFn = () => false, newlyAddedElement = false, } = options; + let { needsMask } = options; let { preserveWhiteSpace = true } = options; + + if ( + !needsMask && + n.childNodes // we can avoid the check on leaf elements, as masking is applied to child text nodes only + ) { + // perf: if needsMask = true, children won't also need to check + const checkAncestors = needsMask === undefined; // if false, we've already checked ancestors + needsMask = needMaskingText( + n as Element, + maskTextClass, + maskTextSelector, + checkAncestors, + ); + } + const _serializedNode = serializeNode(n, { doc, mirror, blockClass, blockSelector, - maskTextClass, - maskTextSelector, + needsMask, inlineStylesheet, maskInputOptions, maskTextFn, @@ -1058,6 +1070,7 @@ export function serializeNodeWithId( mirror, blockClass, blockSelector, + needsMask, maskTextClass, maskTextSelector, skipChild, @@ -1118,6 +1131,7 @@ export function serializeNodeWithId( mirror, blockClass, blockSelector, + needsMask, maskTextClass, maskTextSelector, skipChild: false, @@ -1165,6 +1179,7 @@ export function serializeNodeWithId( mirror, blockClass, blockSelector, + needsMask, maskTextClass, maskTextSelector, skipChild: false, diff --git a/packages/rrweb/src/record/mutation.ts b/packages/rrweb/src/record/mutation.ts index 7c209605d0..2f6b6550ff 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -515,6 +515,7 @@ export default class MutationBuffer { m.target, this.maskTextClass, this.maskTextSelector, + true, // checkAncestors ) && value ? this.maskTextFn ? this.maskTextFn(value, closestElementOfNode(m.target)) diff --git a/packages/rrweb/test/__snapshots__/integration.test.ts.snap b/packages/rrweb/test/__snapshots__/integration.test.ts.snap index e320254111..e3fb552c7e 100644 --- a/packages/rrweb/test/__snapshots__/integration.test.ts.snap +++ b/packages/rrweb/test/__snapshots__/integration.test.ts.snap @@ -793,6 +793,243 @@ exports[`record integration tests can mask character data mutations 1`] = ` } ] } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [ + { + \\"id\\": 22, + \\"value\\": \\"****** *******\\" + } + ], + \\"attributes\\": [], + \\"removes\\": [], + \\"adds\\": [] + } + } +]" +`; + +exports[`record integration tests can mask character data mutations with regexp 1`] = ` +"[ + { + \\"type\\": 0, + \\"data\\": {} + }, + { + \\"type\\": 1, + \\"data\\": {} + }, + { + \\"type\\": 4, + \\"data\\": { + \\"href\\": \\"about:blank\\", + \\"width\\": 1920, + \\"height\\": 1080 + } + }, + { + \\"type\\": 2, + \\"data\\": { + \\"node\\": { + \\"type\\": 0, + \\"childNodes\\": [ + { + \\"type\\": 1, + \\"name\\": \\"html\\", + \\"publicId\\": \\"\\", + \\"systemId\\": \\"\\", + \\"id\\": 2 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"html\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"head\\", + \\"attributes\\": {}, + \\"childNodes\\": [], + \\"id\\": 4 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"body\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 6 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"p\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"mutation observer\\", + \\"id\\": 8 + } + ], + \\"id\\": 7 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 9 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"ul\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 11 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"li\\", + \\"attributes\\": {}, + \\"childNodes\\": [], + \\"id\\": 12 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 13 + } + ], + \\"id\\": 10 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 14 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"canvas\\", + \\"attributes\\": {}, + \\"childNodes\\": [], + \\"id\\": 15 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n\\\\n \\", + \\"id\\": 16 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"script\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", + \\"id\\": 18 + } + ], + \\"id\\": 17 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\\\n\\", + \\"id\\": 19 + } + ], + \\"id\\": 5 + } + ], + \\"id\\": 3 + } + ], + \\"id\\": 1 + }, + \\"initialOffset\\": { + \\"left\\": 0, + \\"top\\": 0 + } + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [ + { + \\"id\\": 10, + \\"attributes\\": { + \\"class\\": \\"custom-mask\\" + } + }, + { + \\"id\\": 7, + \\"attributes\\": { + \\"class\\": \\"custom-mask\\" + } + } + ], + \\"removes\\": [ + { + \\"parentId\\": 7, + \\"id\\": 8 + } + ], + \\"adds\\": [ + { + \\"parentId\\": 10, + \\"nextId\\": null, + \\"node\\": { + \\"type\\": 2, + \\"tagName\\": \\"li\\", + \\"attributes\\": {}, + \\"childNodes\\": [], + \\"id\\": 20 + } + }, + { + \\"parentId\\": 20, + \\"nextId\\": null, + \\"node\\": { + \\"type\\": 3, + \\"textContent\\": \\"*** **** ****\\", + \\"id\\": 21 + } + }, + { + \\"parentId\\": 7, + \\"nextId\\": null, + \\"node\\": { + \\"type\\": 3, + \\"textContent\\": \\"*******\\", + \\"id\\": 22 + } + } + ] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [ + { + \\"id\\": 21, + \\"value\\": \\"********** ****** ** ****** *** **** ****\\" + } + ], + \\"attributes\\": [], + \\"removes\\": [], + \\"adds\\": [] + } } ]" `; diff --git a/packages/rrweb/test/integration.test.ts b/packages/rrweb/test/integration.test.ts index c627be84cb..0d4c871854 100644 --- a/packages/rrweb/test/integration.test.ts +++ b/packages/rrweb/test/integration.test.ts @@ -1207,6 +1207,45 @@ describe('record integration tests', function (this: ISuite) { p.innerText = 'mutated'; }); + await page.evaluate(() => { + // generate a characterData mutation; innerText doesn't do that + const p = document.querySelector('p') as HTMLParagraphElement; + (p.childNodes[0] as Text).insertData(0, 'doubly '); + }); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + + it('can mask character data mutations with regexp', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'mutation-observer.html', { + maskTextClass: /custom/, + }), + ); + + await page.evaluate(() => { + const li = document.createElement('li'); + const ul = document.querySelector('ul') as HTMLUListElement; + const p = document.querySelector('p') as HTMLParagraphElement; + [ul, p].forEach((element) => { + element.className = 'custom-mask'; + }); + ul.appendChild(li); + li.innerText = 'new list item'; + p.innerText = 'mutated'; + }); + + await page.evaluate(() => { + // generate a characterData mutation; innerText doesn't do that + const li = document.querySelector('li:not(:empty)') as HTMLLIElement; + (li.childNodes[0] as Text).insertData(0, 'descendent should be masked '); + }); + const snapshots = (await page.evaluate( 'window.snapshots', )) as eventWithTime[]; diff --git a/packages/rrweb/test/utils.ts b/packages/rrweb/test/utils.ts index 5a90f62031..6cd93281f9 100644 --- a/packages/rrweb/test/utils.ts +++ b/packages/rrweb/test/utils.ts @@ -693,6 +693,7 @@ export function generateRecordSnippet(options: recordOptions) { maskAllInputs: ${options.maskAllInputs}, maskInputOptions: ${JSON.stringify(options.maskAllInputs)}, userTriggeredOnInput: ${options.userTriggeredOnInput}, + maskTextClass: ${options.maskTextClass}, maskTextFn: ${options.maskTextFn}, maskInputFn: ${options.maskInputFn}, recordCanvas: ${options.recordCanvas}, From a2be77b82826c4be0e7f3c7c9f7ee50476d5f6f8 Mon Sep 17 00:00:00 2001 From: Eoghan Murray Date: Fri, 1 Dec 2023 13:18:58 +0000 Subject: [PATCH 043/123] Fix serialization and mutation of +