From 0333f38b452302b0546e2fee2c7b3843639dabbb Mon Sep 17 00:00:00 2001 From: Joris Machielse Date: Fri, 2 Oct 2020 09:31:21 +0200 Subject: [PATCH 01/32] =?UTF-8?q?Register=20Enter=20event=20@=20porting=20?= =?UTF-8?q?from=20@Juice10=E2=80=99s=20rrweb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit source: @Juice10/record-once-rrweb/commit/d734cf95dbaf7442547 --- src/record/observer.ts | 12 +++++++++--- src/types.ts | 5 +++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/record/observer.ts b/src/record/observer.ts index 792cd7ff7f..1e0e1afe1f 100644 --- a/src/record/observer.ts +++ b/src/record/observer.ts @@ -221,7 +221,7 @@ function initInputObserver( maskInputOptions: MaskInputOptions, sampling: SamplingStrategy, ): listenerHandler { - function eventHandler(event: Event) { + function eventHandler(event: KeyboardEvent) { // was Event const { target } = event; if ( !target || @@ -231,6 +231,11 @@ function initInputObserver( ) { return; } + + if (event.type === 'keyup' && event.key === 'Enter') { + return cbWithDedup(target, { key: 'Enter' }); + } + const type: string | undefined = (target as HTMLInputElement).type; if ( type === 'password' || @@ -272,7 +277,8 @@ function initInputObserver( if ( !lastInputValue || lastInputValue.text !== v.text || - lastInputValue.isChecked !== v.isChecked + lastInputValue.isChecked !== v.isChecked || + lastInputValue.key !== v.key ) { lastInputValueMap.set(target, v); const id = mirror.getId(target as INode); @@ -304,7 +310,7 @@ function initInputObserver( hookSetter(p[0], p[1], { set() { // mock to a normal event - eventHandler({ target: this } as Event); + eventHandler({ target: this } as KeyboardEvent); // was Event }, }), ), diff --git a/src/types.ts b/src/types.ts index c68069fa4c..1298c4bd94 100644 --- a/src/types.ts +++ b/src/types.ts @@ -356,8 +356,9 @@ export type viewportResizeDimention = { export type viewportResizeCallback = (d: viewportResizeDimention) => void; export type inputValue = { - text: string; - isChecked: boolean; + text?: string; + isChecked?: boolean; + key?: string; }; export type inputCallback = (v: inputValue & { id: number }) => void; From 425a04092d8cb036d83bd9e230be7ab8aebe6354 Mon Sep 17 00:00:00 2001 From: Joris Machielse Date: Fri, 2 Oct 2020 09:39:22 +0200 Subject: [PATCH 02/32] @Juice10: Add a flag for rrweb generated events Port of @Juice10/record-once-rrweb/commit/0aef9569a7c5eabe167a9abc8aecf8fd5987bf0a --- src/record/observer.ts | 7 +++++-- src/types.ts | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/record/observer.ts b/src/record/observer.ts index 1e0e1afe1f..357aaf4b0c 100644 --- a/src/record/observer.ts +++ b/src/record/observer.ts @@ -223,6 +223,8 @@ function initInputObserver( ): listenerHandler { function eventHandler(event: KeyboardEvent) { // was Event const { target } = event; + const rrwebGenerated = !event.isTrusted; + if ( !target || !(target as Element).tagName || @@ -233,7 +235,7 @@ function initInputObserver( } if (event.type === 'keyup' && event.key === 'Enter') { - return cbWithDedup(target, { key: 'Enter' }); + return cbWithDedup(target, { key: 'Enter', rrwebGenerated }); } const type: string | undefined = (target as HTMLInputElement).type; @@ -255,7 +257,7 @@ function initInputObserver( ) { text = '*'.repeat(text.length); } - cbWithDedup(target, { text, isChecked }); + cbWithDedup(target, { text, isChecked, rrwebGenerated }); // if a radio was checked // the other radios with the same name attribute will be unchecked. const name: string | undefined = (target as HTMLInputElement).name; @@ -267,6 +269,7 @@ function initInputObserver( cbWithDedup(el, { text: (el as HTMLInputElement).value, isChecked: !isChecked, + rrwebGenerated: true, }); } }); diff --git a/src/types.ts b/src/types.ts index 1298c4bd94..2501776b33 100644 --- a/src/types.ts +++ b/src/types.ts @@ -359,6 +359,7 @@ export type inputValue = { text?: string; isChecked?: boolean; key?: string; + rrwebGenerated: boolean; }; export type inputCallback = (v: inputValue & { id: number }) => void; From 0cf62c08571b27513d46c114dd94eedc67bebcfe Mon Sep 17 00:00:00 2001 From: Joris Machielse Date: Fri, 2 Oct 2020 11:53:09 +0200 Subject: [PATCH 03/32] Do not ignore password fields, but allow them to be masked instead --- guide.md | 2 +- scripts/repl.ts | 6 ++++-- src/record/index.ts | 1 + src/record/observer.ts | 1 - 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/guide.md b/guide.md index 81e26058c1..2dead127c2 100644 --- a/guide.md +++ b/guide.md @@ -108,7 +108,7 @@ You may find some contents on the webpage which are not willing to be recorded, - An element with the class name `.rr-block` will not be recorded. Instead, it will replay as a placeholder with the same dimension. - An element with the class name `.rr-ignore` will not record its input events. -- `input[type="password"]` will be ignored as default. +- You’ll probably want to mask `input[type="password"]` by adding `maskInputOptions: {password: true}` #### Checkout diff --git a/scripts/repl.ts b/scripts/repl.ts index 417552540a..bcf8013da6 100644 --- a/scripts/repl.ts +++ b/scripts/repl.ts @@ -96,7 +96,8 @@ function getCode(): string { rrweb.record({ emit: event => window._replLog(event), recordCanvas: true, - collectFonts: true + collectFonts: true, + maskInputOptions: { password: true } }); `); page.on('framenavigated', async () => { @@ -107,7 +108,8 @@ function getCode(): string { rrweb.record({ emit: event => window._replLog(event), recordCanvas: true, - collectFonts: true + collectFonts: true, + maskInputOptions: { password: true } }); `); } diff --git a/src/record/index.ts b/src/record/index.ts index b5c508427a..5ea1b9c2d3 100644 --- a/src/record/index.ts +++ b/src/record/index.ts @@ -62,6 +62,7 @@ function record( email: true, month: true, number: true, + password: true, range: true, search: true, tel: true, diff --git a/src/record/observer.ts b/src/record/observer.ts index 357aaf4b0c..04604819e2 100644 --- a/src/record/observer.ts +++ b/src/record/observer.ts @@ -240,7 +240,6 @@ function initInputObserver( const type: string | undefined = (target as HTMLInputElement).type; if ( - type === 'password' || (target as HTMLElement).classList.contains(ignoreClass) ) { return; From 0159fa1c8377434c0e84a77a2898b71e10ac33c6 Mon Sep 17 00:00:00 2001 From: Joris Machielse Date: Fri, 2 Oct 2020 12:11:39 +0200 Subject: [PATCH 04/32] Copied electron-inject.js from @Juice10/record-once-rrweb And configured some new rrweb options --- src/electron-inject.js | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/electron-inject.js diff --git a/src/electron-inject.js b/src/electron-inject.js new file mode 100644 index 0000000000..8d02c6b077 --- /dev/null +++ b/src/electron-inject.js @@ -0,0 +1,37 @@ +/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, + no-underscore-dangle, no-console */ + +const { ipcRenderer } = require('electron'); + +process.once('loaded', () => { + console.log('loaded electron-inject.js'); +}); + +const record = require('rrweb/record').default; + +window.__IS_RECORDING__ = true; + +record({ + emit: (event) => { + console.log(event); + + const message = { + event, + window: { + scrollX: window.scrollX, + scrollY: window.scrollY, + innerWidth: window.innerWidth, + innerHeight: window.innerHeight, + }, + }; + ipcRenderer.send('recordedEvent', JSON.stringify(message)); + }, + recordCanvas: true, + collectFonts: true, + maskInputOptions: { + password: true, + }, + sampling: { + mousemove: false, + }, +}); \ No newline at end of file From 92ca08b276d5968e20a83a64174cf99d44dd9b6b Mon Sep 17 00:00:00 2001 From: Joris Machielse Date: Fri, 2 Oct 2020 12:31:33 +0200 Subject: [PATCH 05/32] Added build config from @Juice10/record-once-rrweb --- .gitignore | 1 + package.json | 19 ++++++++++-- webpack.config-inject.js | 62 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 webpack.config-inject.js diff --git a/.gitignore b/.gitignore index 8b30d6c161..6604722a44 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ package-lock.json yarn.lock build dist +dist-electron es lib diff --git a/package.json b/package.json index 467c4866c0..4384804b9c 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,15 @@ "test:watch": "PUPPETEER_HEADLESS=true npm run test -- --watch --watch-extensions js,ts", "repl": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true ts-node scripts/repl.ts", "bundle:browser": "cross-env BROWSER_ONLY=true rollup --config", - "bundle": "rollup --config", - "typings": "tsc -d --declarationDir typings" + "bundle:inject": "npx webpack --config webpack.config-inject.js", + "bundle:default": "rollup --config", + "bundle": "run-s bundle:inject bundle:default", + "dev": "run-p dev:**", + "dev:default": "rollup --watch --config", + "dev:inject": "npx webpack --watch --config webpack.config-inject.js", + "typings": "tsc -d --declarationDir typings", + "start:client": "webpack-dev-server --config webpack.config.js", + "start": "babel-watch ./scrubber/server.js" }, "repository": { "type": "git", @@ -24,6 +31,7 @@ "typings": "typings/entries/all.d.ts", "files": [ "dist", + "dist-electron", "lib", "es", "typings" @@ -45,6 +53,7 @@ "inquirer": "^6.2.1", "jest-snapshot": "^23.6.0", "mocha": "^5.2.0", + "npm-run-all": "^4.1.5", "puppeteer": "^1.11.0", "rollup": "^2.3.3", "rollup-plugin-commonjs": "^9.2.0", @@ -55,7 +64,11 @@ "ts-node": "^7.0.1", "tslib": "^1.9.3", "tslint": "^4.5.1", - "typescript": "^3.9.5" + "typescript": "^3.9.5", + "webpack-cli": "^3.3.12", + "webpack-dev-middleware": "^3.7.2", + "webpack-dev-server": "^3.11.0", + "webpack-hot-middleware": "^2.25.0" }, "dependencies": { "@types/css-font-loading-module": "0.0.4", diff --git a/webpack.config-inject.js b/webpack.config-inject.js new file mode 100644 index 0000000000..9013e3a017 --- /dev/null +++ b/webpack.config-inject.js @@ -0,0 +1,62 @@ +const path = require('path'); + +module.exports = { + mode: 'development', + entry: { + app: ['./src/electron-inject'], + }, + output: { + path: path.resolve(__dirname, 'dist-electron'), + filename: 'index.js', + }, + target: 'electron-preload', + resolve: { + extensions: ['.tsx', '.ts', '.js', '.mjs'], + + alias: { + 'rrweb/record$': path.resolve(__dirname, 'src/record/index.ts'), + rrweb$: path.resolve(__dirname, 'src/index.ts'), + }, + }, + module: { + + rules: [ + { + test: /\.tsx?$/, + use: 'ts-loader', + exclude: /node_modules/, + }, + { + test: /\.css$/i, + use: ['style-loader', 'css-loader'], + }, + { + test: /\.mjs$/, + include: /node_modules/, + type: 'javascript/auto', + }, + { + test: /scrubber\/scripts\.js$/, + exclude: /(node_modules|bower_components)/, + use: [ + { + loader: 'babel-loader', + options: { + presets: [ + [ + '@babel/preset-env', + { + modules: 'auto', // commonjs,amd,umd,systemjs,false + useBuiltIns: 'usage', + targets: '> 0.25%, not dead', + corejs: 3, + }, + ], + ], + }, + }, + ], + }, + ], + }, +}; \ No newline at end of file From 2563ecdb7059b96eb2438d6de1ab60e0d0be7fbd Mon Sep 17 00:00:00 2001 From: Joris Machielse Date: Fri, 2 Oct 2020 12:42:05 +0200 Subject: [PATCH 06/32] Correcting bundle:inject --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4384804b9c..479b48b043 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "test:watch": "PUPPETEER_HEADLESS=true npm run test -- --watch --watch-extensions js,ts", "repl": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true ts-node scripts/repl.ts", "bundle:browser": "cross-env BROWSER_ONLY=true rollup --config", - "bundle:inject": "npx webpack --config webpack.config-inject.js", + "bundle:inject": "npx webpack --config webpack.config-inject.js --mode production", "bundle:default": "rollup --config", "bundle": "run-s bundle:inject bundle:default", "dev": "run-p dev:**", From 943b18317c3b06c169c2ebf63e1b974818f4f66f Mon Sep 17 00:00:00 2001 From: Joris Machielse Date: Fri, 2 Oct 2020 13:03:24 +0200 Subject: [PATCH 07/32] Correct dev dependencies --- package.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/package.json b/package.json index 479b48b043..e943f25699 100644 --- a/package.json +++ b/package.json @@ -43,17 +43,26 @@ }, "homepage": "https://github.com/rrweb-io/rrweb#readme", "devDependencies": { + "@babel/core": "^7.11.6", + "@babel/preset-env": "^7.11.5", "@types/chai": "^4.1.6", "@types/inquirer": "0.0.43", "@types/mocha": "^5.2.5", "@types/node": "^10.11.7", + "@types/node-fetch": "^2.5.7", "@types/puppeteer": "^1.11.1", + "babel-loader": "^8.1.0", + "babel-watch": "^7.0.0", "chai": "^4.2.0", + "core-js": "^3.6.5", "cross-env": "^5.2.0", + "css-loader": "^4.3.0", "inquirer": "^6.2.1", "jest-snapshot": "^23.6.0", "mocha": "^5.2.0", + "node-fetch": "^2.6.1", "npm-run-all": "^4.1.5", + "path": "^0.12.7", "puppeteer": "^1.11.0", "rollup": "^2.3.3", "rollup-plugin-commonjs": "^9.2.0", @@ -61,10 +70,13 @@ "rollup-plugin-postcss": "^3.1.1", "rollup-plugin-terser": "^5.3.0", "rollup-plugin-typescript": "^1.0.0", + "style-loader": "^1.2.1", + "ts-loader": "^8.0.4", "ts-node": "^7.0.1", "tslib": "^1.9.3", "tslint": "^4.5.1", "typescript": "^3.9.5", + "webpack": "^4.44.2", "webpack-cli": "^3.3.12", "webpack-dev-middleware": "^3.7.2", "webpack-dev-server": "^3.11.0", From 27fbb31eef3c6478fae07e89f01ad6bc9af9c50c Mon Sep 17 00:00:00 2001 From: Joris Machielse Date: Fri, 2 Oct 2020 13:04:10 +0200 Subject: [PATCH 08/32] Copied checks from @Juice10/record-once-rrweb/commit/903ab8d883593b5167f052ff1a74031f6a7491c8 --- src/replay/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/replay/index.ts b/src/replay/index.ts index 4a547f9b4d..6386adfdf6 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -1058,8 +1058,8 @@ export class Replayer { return this.debugNodeNotFound(d, d.id); } try { - ((target as Node) as HTMLInputElement).checked = d.isChecked; - ((target as Node) as HTMLInputElement).value = d.text; + if (d.isChecked) ((target as Node) as HTMLInputElement).checked = d.isChecked; + if (d.text) ((target as Node) as HTMLInputElement).value = d.text; } catch (error) { // for safe } From f569556f2dbeed89e346ea90826ca1f8404df395 Mon Sep 17 00:00:00 2001 From: Joris Machielse Date: Fri, 2 Oct 2020 13:36:23 +0200 Subject: [PATCH 09/32] =?UTF-8?q?Attempting=20a=20postinstall=20hook?= =?UTF-8?q?=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index e943f25699..f1c3463e71 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "dev:inject": "npx webpack --watch --config webpack.config-inject.js", "typings": "tsc -d --declarationDir typings", "start:client": "webpack-dev-server --config webpack.config.js", - "start": "babel-watch ./scrubber/server.js" + "start": "babel-watch ./scrubber/server.js", + "postinstall": "npm run bundle; npm run typings" }, "repository": { "type": "git", From c210d265210274e6b21e0a75f18ab5642de34489 Mon Sep 17 00:00:00 2001 From: Joris Machielse Date: Fri, 2 Oct 2020 13:40:27 +0200 Subject: [PATCH 10/32] Do not run typings post install --- package.json | 2 +- typings/types.d.ts | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index f1c3463e71..d06ac66502 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "typings": "tsc -d --declarationDir typings", "start:client": "webpack-dev-server --config webpack.config.js", "start": "babel-watch ./scrubber/server.js", - "postinstall": "npm run bundle; npm run typings" + "postinstall": "npm run bundle" }, "repository": { "type": "git", diff --git a/typings/types.d.ts b/typings/types.d.ts index cdb25b0165..3902162e1f 100644 --- a/typings/types.d.ts +++ b/typings/types.d.ts @@ -262,8 +262,10 @@ export declare type viewportResizeDimention = { }; export declare type viewportResizeCallback = (d: viewportResizeDimention) => void; export declare type inputValue = { - text: string; - isChecked: boolean; + text?: string; + isChecked?: boolean; + key?: string; + rrwebGenerated: boolean; }; export declare type inputCallback = (v: inputValue & { id: number; From 2831dcfd08f1786009eb50325f72be5da2c51434 Mon Sep 17 00:00:00 2001 From: Joris Machielse Date: Fri, 2 Oct 2020 13:41:21 +0200 Subject: [PATCH 11/32] Hopefully this does work --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d06ac66502..4cc614107b 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "typings": "tsc -d --declarationDir typings", "start:client": "webpack-dev-server --config webpack.config.js", "start": "babel-watch ./scrubber/server.js", - "postinstall": "npm run bundle" + "postinstall": "npm run bundle:inject bundle:default" }, "repository": { "type": "git", From 5d9eeea83d324678143bd320f604f4c2b467d289 Mon Sep 17 00:00:00 2001 From: Joris Machielse Date: Wed, 20 Jan 2021 13:40:19 +0100 Subject: [PATCH 12/32] Removed electron injection --- .gitignore | 1 - package.json | 1 - src/electron-inject.js | 37 ------------------------ webpack.config-inject.js | 62 ---------------------------------------- 4 files changed, 101 deletions(-) delete mode 100644 src/electron-inject.js delete mode 100644 webpack.config-inject.js diff --git a/.gitignore b/.gitignore index 6604722a44..8b30d6c161 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ package-lock.json yarn.lock build dist -dist-electron es lib diff --git a/package.json b/package.json index 4cc614107b..932e465408 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,6 @@ "typings": "typings/entries/all.d.ts", "files": [ "dist", - "dist-electron", "lib", "es", "typings" diff --git a/src/electron-inject.js b/src/electron-inject.js deleted file mode 100644 index 8d02c6b077..0000000000 --- a/src/electron-inject.js +++ /dev/null @@ -1,37 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, - no-underscore-dangle, no-console */ - -const { ipcRenderer } = require('electron'); - -process.once('loaded', () => { - console.log('loaded electron-inject.js'); -}); - -const record = require('rrweb/record').default; - -window.__IS_RECORDING__ = true; - -record({ - emit: (event) => { - console.log(event); - - const message = { - event, - window: { - scrollX: window.scrollX, - scrollY: window.scrollY, - innerWidth: window.innerWidth, - innerHeight: window.innerHeight, - }, - }; - ipcRenderer.send('recordedEvent', JSON.stringify(message)); - }, - recordCanvas: true, - collectFonts: true, - maskInputOptions: { - password: true, - }, - sampling: { - mousemove: false, - }, -}); \ No newline at end of file diff --git a/webpack.config-inject.js b/webpack.config-inject.js deleted file mode 100644 index 9013e3a017..0000000000 --- a/webpack.config-inject.js +++ /dev/null @@ -1,62 +0,0 @@ -const path = require('path'); - -module.exports = { - mode: 'development', - entry: { - app: ['./src/electron-inject'], - }, - output: { - path: path.resolve(__dirname, 'dist-electron'), - filename: 'index.js', - }, - target: 'electron-preload', - resolve: { - extensions: ['.tsx', '.ts', '.js', '.mjs'], - - alias: { - 'rrweb/record$': path.resolve(__dirname, 'src/record/index.ts'), - rrweb$: path.resolve(__dirname, 'src/index.ts'), - }, - }, - module: { - - rules: [ - { - test: /\.tsx?$/, - use: 'ts-loader', - exclude: /node_modules/, - }, - { - test: /\.css$/i, - use: ['style-loader', 'css-loader'], - }, - { - test: /\.mjs$/, - include: /node_modules/, - type: 'javascript/auto', - }, - { - test: /scrubber\/scripts\.js$/, - exclude: /(node_modules|bower_components)/, - use: [ - { - loader: 'babel-loader', - options: { - presets: [ - [ - '@babel/preset-env', - { - modules: 'auto', // commonjs,amd,umd,systemjs,false - useBuiltIns: 'usage', - targets: '> 0.25%, not dead', - corejs: 3, - }, - ], - ], - }, - }, - ], - }, - ], - }, -}; \ No newline at end of file From 9e4c36f6aed4152fe07b36fec73d3b21d322e489 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Thu, 18 Feb 2021 12:10:54 +0100 Subject: [PATCH 13/32] Revert "Added build config from @Juice10/record-once-rrweb" This reverts commit 92ca08b276d5968e20a83a64174cf99d44dd9b6b. --- package.json | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index de76f52e08..22a8d15b18 100644 --- a/package.json +++ b/package.json @@ -7,16 +7,8 @@ "test:watch": "PUPPETEER_HEADLESS=true npm run test -- --watch --watch-extensions js,ts", "repl": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true ts-node scripts/repl.ts", "bundle:browser": "cross-env BROWSER_ONLY=true rollup --config", - "bundle:inject": "npx webpack --config webpack.config-inject.js --mode production", - "bundle:default": "rollup --config", - "bundle": "run-s bundle:inject bundle:default", - "dev": "run-p dev:**", - "dev:default": "rollup --watch --config", - "dev:inject": "npx webpack --watch --config webpack.config-inject.js", - "typings": "tsc -d --declarationDir typings", - "start:client": "webpack-dev-server --config webpack.config.js", - "start": "babel-watch ./scrubber/server.js", - "postinstall": "npm run bundle:inject bundle:default" + "bundle": "rollup --config", + "typings": "tsc -d --declarationDir typings" }, "repository": { "type": "git", @@ -73,12 +65,7 @@ "ts-node": "^7.0.1", "tslib": "^1.9.3", "tslint": "^4.5.1", - "typescript": "^3.9.5", - "webpack": "^4.44.2", - "webpack-cli": "^3.3.12", - "webpack-dev-middleware": "^3.7.2", - "webpack-dev-server": "^3.11.0", - "webpack-hot-middleware": "^2.25.0" + "typescript": "^3.9.5" }, "dependencies": { "@types/css-font-loading-module": "0.0.4", From 7c269d75861ab8d46a392df0fc414bbc8ab6f82e Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Thu, 18 Feb 2021 13:24:59 +0100 Subject: [PATCH 14/32] add ability to mask passwords --- guide.md | 40 +- guide.zh_CN.md | 40 +- src/record/index.ts | 3 +- src/record/observer.ts | 5 +- test/__snapshots__/integration.test.ts.snap | 879 +++++++++----------- test/html/form.html | 3 + test/html/ignore.html | 1 - test/integration.test.ts | 4 +- 8 files changed, 441 insertions(+), 534 deletions(-) diff --git a/guide.md b/guide.md index 3912210123..4018117c96 100644 --- a/guide.md +++ b/guide.md @@ -135,25 +135,25 @@ setInterval(save, 10 * 1000); The parameter of `rrweb.record` accepts the following options. -| key | default | description | -| ---------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| emit | required | the callback function to get emitted events | -| checkoutEveryNth | - | take a full snapshot after every N events
refer to the [checkout](#checkout) chapter | -| checkoutEveryNms | - | take a full snapshot after every N ms
refer to the [checkout](#checkout) chapter | -| blockClass | 'rr-block' | Use a string or RegExp to configure which elements 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 | -| blockSelector | null | Use a string or RegExp to configure which selector should be blocked, refer to the [privacy](#privacy) chapter | -| maskAllInputs | false | mask all input content as \* | -| maskInputOptions | {} | mask some kinds of input \*
refer to the [list](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L72) | -| maskInputFn | - | customize mask input content recording logic | -| slimDOMOptions | {} | remove unnecessary parts of the DOM
refer to the [list](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L91) | -| inlineStylesheet | true | whether to inline the stylesheet in the events | -| hooks | {} | hooks for events
refer to the [list](https://github.com/rrweb-io/rrweb/blob/9488deb6d54a5f04350c063d942da5e96ab74075/src/types.ts#L207) | -| packFn | - | refer to the [storage optimization recipe](./docs/recipes/optimize-storage.md) | -| sampling | - | refer to the [storage optimization recipe](./docs/recipes/optimize-storage.md) | -| recordCanvas | false | whether to record the canvas element | -| collectFonts | false | whether to collect fonts in the website | -| recordLog | false | whether to record console output, refer to the [console recipe](./docs/recipes/console.md) | +| key | default | description | +| ---------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| emit | required | the callback function to get emitted events | +| checkoutEveryNth | - | take a full snapshot after every N events
refer to the [checkout](#checkout) chapter | +| checkoutEveryNms | - | take a full snapshot after every N ms
refer to the [checkout](#checkout) chapter | +| blockClass | 'rr-block' | Use a string or RegExp to configure which elements 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 | +| blockSelector | null | Use a string or RegExp to configure which selector should be blocked, refer to the [privacy](#privacy) chapter | +| maskAllInputs | false | mask all input content as \* | +| maskInputOptions | { password: true } | mask some kinds of input \*
refer to the [list](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L72) | +| maskInputFn | - | customize mask input content recording logic | +| slimDOMOptions | {} | remove unnecessary parts of the DOM
refer to the [list](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L91) | +| inlineStylesheet | true | whether to inline the stylesheet in the events | +| hooks | {} | hooks for events
refer to the [list](https://github.com/rrweb-io/rrweb/blob/9488deb6d54a5f04350c063d942da5e96ab74075/src/types.ts#L207) | +| packFn | - | refer to the [storage optimization recipe](./docs/recipes/optimize-storage.md) | +| sampling | - | refer to the [storage optimization recipe](./docs/recipes/optimize-storage.md) | +| recordCanvas | false | whether to record the canvas element | +| collectFonts | false | whether to collect fonts in the website | +| recordLog | false | whether to record console output, refer to the [console recipe](./docs/recipes/console.md) | #### Privacy @@ -161,8 +161,8 @@ You may find some contents on the webpage which are not willing to be recorded, - An element with the class name `.rr-block` will not be recorded. Instead, it will replay as a placeholder with the same dimension. - An element with the class name `.rr-ignore` will not record its input events. -- `input[type="password"]` will be ignored as default. - Mask options to mask the content in input elements. +- `input[type="password"]` will be masked as default. #### Checkout diff --git a/guide.zh_CN.md b/guide.zh_CN.md index 4280a58da3..967d2ab230 100644 --- a/guide.zh_CN.md +++ b/guide.zh_CN.md @@ -131,25 +131,25 @@ setInterval(save, 10 * 1000); `rrweb.record(config)` 的 config 部分接受以下参数 -| key | 默认值 | 功能 | -| ---------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| emit | 必填 | 获取当前录制的数据 | -| checkoutEveryNth | - | 每 N 次事件重新制作一次全量快照
详见[“重新制作快照”](#重新制作快照)章节 | -| checkoutEveryNms | - | 每 N 毫秒重新制作一次全量快照
详见[“重新制作快照”](#重新制作快照)章节 | -| blockClass | 'rr-block' | 字符串或正则表达式,可用于自定义屏蔽元素的类名,详见[“隐私”](#隐私)章节 | -| blockSelector | null | 字符串或正则表达式,可用于自定义屏蔽元素的选择器,详见[“隐私”](#隐私)章节 | -| ignoreClass | 'rr-ignore' | 字符串或正则表达式,可用于自定义忽略元素的类名,详见[“隐私”](#隐私)章节 | -| maskAllInputs | false | 将所有输入内容记录为 \* | -| maskInputOptions | {} | 选择将特定类型的输入框内容记录为 \*
类型详见[列表](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L72) | -| maskInputFn | - | 自定义特定类型的输入框内容记录逻辑 | -| slimDOMOptions | {} | 去除 DOM 中不必要的部分
类型详见[列表](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L91) | -| inlineStylesheet | true | 是否将样式表内联 | -| hooks | {} | 各类事件的回调
类型详见[列表](https://github.com/rrweb-io/rrweb/blob/9488deb6d54a5f04350c063d942da5e96ab74075/src/types.ts#L207) | -| packFn | - | 数据压缩函数,详见[优化存储策略](./docs/recipes/optimize-storage.zh_CN.md) | -| sampling | - | 数据抽样策略,详见[优化存储策略](./docs/recipes/optimize-storage.zh_CN.md) | -| recordCanvas | false | 是否记录 canvas 内容 | -| collectFonts | false | 是否记录页面中的字体文件 | -| recordLog | false | 是否记录 console 输出,详见[console 录制和播放](./docs/recipes/console.zh_CN.md) | +| key | 默认值 | 功能 | +| ---------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| emit | 必填 | 获取当前录制的数据 | +| checkoutEveryNth | - | 每 N 次事件重新制作一次全量快照
详见[“重新制作快照”](#重新制作快照)章节 | +| checkoutEveryNms | - | 每 N 毫秒重新制作一次全量快照
详见[“重新制作快照”](#重新制作快照)章节 | +| blockClass | 'rr-block' | 字符串或正则表达式,可用于自定义屏蔽元素的类名,详见[“隐私”](#隐私)章节 | +| blockSelector | null | 字符串或正则表达式,可用于自定义屏蔽元素的选择器,详见[“隐私”](#隐私)章节 | +| ignoreClass | 'rr-ignore' | 字符串或正则表达式,可用于自定义忽略元素的类名,详见[“隐私”](#隐私)章节 | +| maskAllInputs | false | 将所有输入内容记录为 \* | +| maskInputOptions | { password: true } | 选择将特定类型的输入框内容记录为 \*
类型详见[列表](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L72) | +| maskInputFn | - | 自定义特定类型的输入框内容记录逻辑 | +| slimDOMOptions | {} | 去除 DOM 中不必要的部分
类型详见[列表](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L91) | +| inlineStylesheet | true | 是否将样式表内联 | +| hooks | {} | 各类事件的回调
类型详见[列表](https://github.com/rrweb-io/rrweb/blob/9488deb6d54a5f04350c063d942da5e96ab74075/src/types.ts#L207) | +| packFn | - | 数据压缩函数,详见[优化存储策略](./docs/recipes/optimize-storage.zh_CN.md) | +| sampling | - | 数据抽样策略,详见[优化存储策略](./docs/recipes/optimize-storage.zh_CN.md) | +| recordCanvas | false | 是否记录 canvas 内容 | +| collectFonts | false | 是否记录页面中的字体文件 | +| recordLog | false | 是否记录 console 输出,详见[console 录制和播放](./docs/recipes/console.zh_CN.md) | #### 隐私 @@ -157,8 +157,8 @@ setInterval(save, 10 * 1000); - 在 HTML 元素中添加类名 `.rr-block` 将会避免该元素及其子元素被录制,回放时取而代之的是一个同等宽高的占位元素。 - 在 HTML 元素中添加类名 `.rr-ignore` 将会避免录制该元素的输入事件。 -- `input[type="password"]` 类型的密码输入框默认不会录制输入事件。 - 配置中还有更为丰富的隐私保护选项。 +- `input[type="password"]` 类型的密码输入框默认不会录制输入事件。 #### 重新制作快照 diff --git a/src/record/index.ts b/src/record/index.ts index 70333c0747..03c041914d 100644 --- a/src/record/index.ts +++ b/src/record/index.ts @@ -78,10 +78,11 @@ function record( week: true, textarea: true, select: true, + password: true, } : _maskInputOptions !== undefined ? _maskInputOptions - : {}; + : { password: true }; const slimDOMOptions: SlimDOMOptions = _slimDOMOptions === true || _slimDOMOptions === 'all' diff --git a/src/record/observer.ts b/src/record/observer.ts index d71a8b0fd1..26e429e5c6 100644 --- a/src/record/observer.ts +++ b/src/record/observer.ts @@ -298,10 +298,7 @@ function initInputObserver( return; } const type: string | undefined = (target as HTMLInputElement).type; - if ( - type === 'password' || - (target as HTMLElement).classList.contains(ignoreClass) - ) { + if ((target as HTMLElement).classList.contains(ignoreClass)) { return; } let text = (target as HTMLInputElement).value; diff --git a/test/__snapshots__/integration.test.ts.snap b/test/__snapshots__/integration.test.ts.snap index f205fe9562..391cdceef8 100644 --- a/test/__snapshots__/integration.test.ts.snap +++ b/test/__snapshots__/integration.test.ts.snap @@ -1229,8 +1229,42 @@ exports[`form 1`] = ` }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", + \\"textContent\\": \\"\\\\n \\", \\"id\\": 51 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"password\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 53 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"password\\" + }, + \\"childNodes\\": [], + \\"id\\": 54 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 55 + } + ], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 56 } ], \\"id\\": 18 @@ -1238,7 +1272,7 @@ exports[`form 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n\\\\n \\", - \\"id\\": 52 + \\"id\\": 57 }, { \\"type\\": 2, @@ -1248,15 +1282,15 @@ exports[`form 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 54 + \\"id\\": 59 } ], - \\"id\\": 53 + \\"id\\": 58 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\\\n\\", - \\"id\\": 55 + \\"id\\": 60 } ], \\"id\\": 16 @@ -2571,7 +2605,7 @@ exports[`ignore 1`] = ` \\"type\\": 2, \\"tagName\\": \\"label\\", \\"attributes\\": { - \\"for\\": \\"password\\" + \\"for\\": \\"ignore text\\" }, \\"childNodes\\": [ { @@ -2583,7 +2617,8 @@ exports[`ignore 1`] = ` \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"password\\" + \\"type\\": \\"text\\", + \\"class\\": \\"rr-ignore\\" }, \\"childNodes\\": [], \\"id\\": 22 @@ -2596,45 +2631,10 @@ exports[`ignore 1`] = ` ], \\"id\\": 20 }, - { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 24 - }, - { - \\"type\\": 2, - \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"ignore text\\" - }, - \\"childNodes\\": [ - { - \\"type\\": 3, - \\"textContent\\": \\" \\", - \\"id\\": 26 - }, - { - \\"type\\": 2, - \\"tagName\\": \\"input\\", - \\"attributes\\": { - \\"type\\": \\"text\\", - \\"class\\": \\"rr-ignore\\" - }, - \\"childNodes\\": [], - \\"id\\": 27 - }, - { - \\"type\\": 3, - \\"textContent\\": \\" \\", - \\"id\\": 28 - } - ], - \\"id\\": 25 - }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 29 + \\"id\\": 24 } ], \\"id\\": 18 @@ -2642,7 +2642,7 @@ exports[`ignore 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\", - \\"id\\": 30 + \\"id\\": 25 }, { \\"type\\": 2, @@ -2652,15 +2652,15 @@ exports[`ignore 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 32 + \\"id\\": 27 } ], - \\"id\\": 31 + \\"id\\": 26 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 33 + \\"id\\": 28 } ], \\"id\\": 16 @@ -2684,27 +2684,11 @@ exports[`ignore 1`] = ` \\"type\\": 5, \\"id\\": 22 } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 2, - \\"type\\": 6, - \\"id\\": 22 - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 2, - \\"type\\": 5, - \\"id\\": 27 - } } ]" `; -exports[`log`] = ` +exports[`log 1`] = ` "[ { \\"type\\": 0, @@ -2870,9 +2854,13 @@ exports[`log`] = ` \\"data\\": { \\"source\\": 11, \\"level\\": \\"assert\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:2:37\\" + ], \\"payload\\": [ \\"true\\", - \\"\\"assert\\"\\" + \\"\\\\\\"assert\\\\\\"\\" ] } }, @@ -2881,8 +2869,12 @@ exports[`log`] = ` \\"data\\": { \\"source\\": 11, \\"level\\": \\"count\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:3:37\\" + ], \\"payload\\": [ - \\"\\"count\\"\\" + \\"\\\\\\"count\\\\\\"\\" ] } }, @@ -2891,8 +2883,12 @@ exports[`log`] = ` \\"data\\": { \\"source\\": 11, \\"level\\": \\"countReset\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:4:37\\" + ], \\"payload\\": [ - \\"\\"count\\"\\" + \\"\\\\\\"count\\\\\\"\\" ] } }, @@ -2901,8 +2897,12 @@ exports[`log`] = ` \\"data\\": { \\"source\\": 11, \\"level\\": \\"debug\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:5:37\\" + ], \\"payload\\": [ - \\"\\"debug\\"\\" + \\"\\\\\\"debug\\\\\\"\\" ] } }, @@ -2911,8 +2911,12 @@ exports[`log`] = ` \\"data\\": { \\"source\\": 11, \\"level\\": \\"dir\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:6:37\\" + ], \\"payload\\": [ - \\"\\"dir\\"\\" + \\"\\\\\\"dir\\\\\\"\\" ] } }, @@ -2921,8 +2925,12 @@ exports[`log`] = ` \\"data\\": { \\"source\\": 11, \\"level\\": \\"dirxml\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:7:37\\" + ], \\"payload\\": [ - \\"\\"dirxml\\"\\" + \\"\\\\\\"dirxml\\\\\\"\\" ] } }, @@ -2931,6 +2939,10 @@ exports[`log`] = ` \\"data\\": { \\"source\\": 11, \\"level\\": \\"group\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:8:37\\" + ], \\"payload\\": [] } }, @@ -2939,6 +2951,10 @@ exports[`log`] = ` \\"data\\": { \\"source\\": 11, \\"level\\": \\"groupCollapsed\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:9:37\\" + ], \\"payload\\": [] } }, @@ -2947,8 +2963,12 @@ exports[`log`] = ` \\"data\\": { \\"source\\": 11, \\"level\\": \\"info\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:10:37\\" + ], \\"payload\\": [ - \\"\\"info\\"\\" + \\"\\\\\\"info\\\\\\"\\" ] } }, @@ -2957,8 +2977,12 @@ exports[`log`] = ` \\"data\\": { \\"source\\": 11, \\"level\\": \\"log\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:11:37\\" + ], \\"payload\\": [ - \\"\\"log\\"\\" + \\"\\\\\\"log\\\\\\"\\" ] } }, @@ -2967,8 +2991,12 @@ exports[`log`] = ` \\"data\\": { \\"source\\": 11, \\"level\\": \\"table\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:12:37\\" + ], \\"payload\\": [ - \\"\\"table\\"\\" + \\"\\\\\\"table\\\\\\"\\" ] } }, @@ -2977,6 +3005,10 @@ exports[`log`] = ` \\"data\\": { \\"source\\": 11, \\"level\\": \\"time\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:13:37\\" + ], \\"payload\\": [] } }, @@ -2985,6 +3017,10 @@ exports[`log`] = ` \\"data\\": { \\"source\\": 11, \\"level\\": \\"timeEnd\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:14:37\\" + ], \\"payload\\": [] } }, @@ -2993,6 +3029,10 @@ exports[`log`] = ` \\"data\\": { \\"source\\": 11, \\"level\\": \\"timeLog\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:15:37\\" + ], \\"payload\\": [] } }, @@ -3001,8 +3041,12 @@ exports[`log`] = ` \\"data\\": { \\"source\\": 11, \\"level\\": \\"trace\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:16:37\\" + ], \\"payload\\": [ - \\"\\"trace\\"\\" + \\"\\\\\\"trace\\\\\\"\\" ] } }, @@ -3011,8 +3055,12 @@ exports[`log`] = ` \\"data\\": { \\"source\\": 11, \\"level\\": \\"warn\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:17:37\\" + ], \\"payload\\": [ - \\"\\"warn\\"\\" + \\"\\\\\\"warn\\\\\\"\\" ] } }, @@ -3021,13 +3069,17 @@ exports[`log`] = ` \\"data\\": { \\"source\\": 11, \\"level\\": \\"clear\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:18:37\\" + ], \\"payload\\": [] } } ]" `; -exports[`log 1`] = ` +exports[`mask 1`] = ` "[ { \\"type\\": 0, @@ -3072,7 +3124,7 @@ exports[`log 1`] = ` \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", + \\"textContent\\": \\"\\\\n \\", \\"id\\": 5 }, { @@ -3086,7 +3138,7 @@ exports[`log 1`] = ` }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", + \\"textContent\\": \\"\\\\n \\", \\"id\\": 7 }, { @@ -3101,7 +3153,7 @@ exports[`log 1`] = ` }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", + \\"textContent\\": \\"\\\\n \\", \\"id\\": 9 }, { @@ -3116,7 +3168,7 @@ exports[`log 1`] = ` }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", + \\"textContent\\": \\"\\\\n \\", \\"id\\": 11 }, { @@ -3126,7 +3178,7 @@ exports[`log 1`] = ` \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"Log record\\", + \\"textContent\\": \\"form fields\\", \\"id\\": 13 } ], @@ -3134,7 +3186,7 @@ exports[`log 1`] = ` }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", + \\"textContent\\": \\"\\\\n\\", \\"id\\": 14 } ], @@ -3142,7 +3194,7 @@ exports[`log 1`] = ` }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", + \\"textContent\\": \\"\\\\n\\\\n\\", \\"id\\": 15 }, { @@ -3152,408 +3204,17 @@ exports[`log 1`] = ` \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", + \\"textContent\\": \\"\\\\n \\", \\"id\\": 17 }, { \\"type\\": 2, - \\"tagName\\": \\"script\\", + \\"tagName\\": \\"form\\", \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 19 - } - ], - \\"id\\": 18 - }, - { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 20 - } - ], - \\"id\\": 16 - } - ], - \\"id\\": 3 - } - ], - \\"id\\": 1 - }, - \\"initialOffset\\": { - \\"left\\": 0, - \\"top\\": 0 - } - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"assert\\", - \\"trace\\": [ - \\"__puppeteer_evalu\\", - \\"ion_script__:2:37\\" - ], - \\"payload\\": [ - \\"true\\", - \\"\\\\\\"assert\\\\\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"count\\", - \\"trace\\": [ - \\"__puppeteer_evalu\\", - \\"ion_script__:3:37\\" - ], - \\"payload\\": [ - \\"\\\\\\"count\\\\\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"countReset\\", - \\"trace\\": [ - \\"__puppeteer_evalu\\", - \\"ion_script__:4:37\\" - ], - \\"payload\\": [ - \\"\\\\\\"count\\\\\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"debug\\", - \\"trace\\": [ - \\"__puppeteer_evalu\\", - \\"ion_script__:5:37\\" - ], - \\"payload\\": [ - \\"\\\\\\"debug\\\\\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"dir\\", - \\"trace\\": [ - \\"__puppeteer_evalu\\", - \\"ion_script__:6:37\\" - ], - \\"payload\\": [ - \\"\\\\\\"dir\\\\\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"dirxml\\", - \\"trace\\": [ - \\"__puppeteer_evalu\\", - \\"ion_script__:7:37\\" - ], - \\"payload\\": [ - \\"\\\\\\"dirxml\\\\\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"group\\", - \\"trace\\": [ - \\"__puppeteer_evalu\\", - \\"ion_script__:8:37\\" - ], - \\"payload\\": [] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"groupCollapsed\\", - \\"trace\\": [ - \\"__puppeteer_evalu\\", - \\"ion_script__:9:37\\" - ], - \\"payload\\": [] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"info\\", - \\"trace\\": [ - \\"__puppeteer_evalu\\", - \\"ion_script__:10:37\\" - ], - \\"payload\\": [ - \\"\\\\\\"info\\\\\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"log\\", - \\"trace\\": [ - \\"__puppeteer_evalu\\", - \\"ion_script__:11:37\\" - ], - \\"payload\\": [ - \\"\\\\\\"log\\\\\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"table\\", - \\"trace\\": [ - \\"__puppeteer_evalu\\", - \\"ion_script__:12:37\\" - ], - \\"payload\\": [ - \\"\\\\\\"table\\\\\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"time\\", - \\"trace\\": [ - \\"__puppeteer_evalu\\", - \\"ion_script__:13:37\\" - ], - \\"payload\\": [] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"timeEnd\\", - \\"trace\\": [ - \\"__puppeteer_evalu\\", - \\"ion_script__:14:37\\" - ], - \\"payload\\": [] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"timeLog\\", - \\"trace\\": [ - \\"__puppeteer_evalu\\", - \\"ion_script__:15:37\\" - ], - \\"payload\\": [] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"trace\\", - \\"trace\\": [ - \\"__puppeteer_evalu\\", - \\"ion_script__:16:37\\" - ], - \\"payload\\": [ - \\"\\\\\\"trace\\\\\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"warn\\", - \\"trace\\": [ - \\"__puppeteer_evalu\\", - \\"ion_script__:17:37\\" - ], - \\"payload\\": [ - \\"\\\\\\"warn\\\\\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"clear\\", - \\"trace\\": [ - \\"__puppeteer_evalu\\", - \\"ion_script__:18:37\\" - ], - \\"payload\\": [] - } - } -]" -`; - -exports[`mask 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\\": \\"form fields\\", - \\"id\\": 13 - } - ], - \\"id\\": 12 - }, - { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n\\", - \\"id\\": 14 - } - ], - \\"id\\": 4 - }, - { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n\\\\n\\", - \\"id\\": 15 - }, - { - \\"type\\": 2, - \\"tagName\\": \\"body\\", - \\"attributes\\": {}, - \\"childNodes\\": [ - { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 17 - }, - { - \\"type\\": 2, - \\"tagName\\": \\"form\\", - \\"attributes\\": {}, - \\"childNodes\\": [ - { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", + \\"textContent\\": \\"\\\\n \\", \\"id\\": 19 }, { @@ -3775,8 +3436,42 @@ exports[`mask 1`] = ` }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", + \\"textContent\\": \\"\\\\n \\", \\"id\\": 51 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"password\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 53 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"password\\" + }, + \\"childNodes\\": [], + \\"id\\": 54 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 55 + } + ], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 56 } ], \\"id\\": 18 @@ -3784,7 +3479,7 @@ exports[`mask 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n\\\\n \\", - \\"id\\": 52 + \\"id\\": 57 }, { \\"type\\": 2, @@ -3794,15 +3489,15 @@ exports[`mask 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 54 + \\"id\\": 59 } ], - \\"id\\": 53 + \\"id\\": 58 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\\\n\\", - \\"id\\": 55 + \\"id\\": 60 } ], \\"id\\": 16 @@ -3969,6 +3664,94 @@ exports[`mask 1`] = ` \\"id\\": 32 } }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"*\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"**\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"***\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"****\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"*****\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"******\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"*******\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"********\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 6, + \\"id\\": 54 + } + }, { \\"type\\": 3, \\"data\\": { @@ -4463,8 +4246,42 @@ exports[`maskInputOptions 1`] = ` }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", + \\"textContent\\": \\"\\\\n \\", \\"id\\": 51 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"password\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 53 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"password\\" + }, + \\"childNodes\\": [], + \\"id\\": 54 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 55 + } + ], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 56 } ], \\"id\\": 18 @@ -4472,7 +4289,7 @@ exports[`maskInputOptions 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n\\\\n \\", - \\"id\\": 52 + \\"id\\": 57 }, { \\"type\\": 2, @@ -4482,15 +4299,15 @@ exports[`maskInputOptions 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 54 + \\"id\\": 59 } ], - \\"id\\": 53 + \\"id\\": 58 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\\\n\\", - \\"id\\": 55 + \\"id\\": 60 } ], \\"id\\": 16 @@ -4782,6 +4599,94 @@ exports[`maskInputOptions 1`] = ` \\"id\\": 37 } }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 6, + \\"id\\": 37 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"*\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"**\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"***\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"****\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"*****\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"******\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"*******\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"********\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, { \\"type\\": 3, \\"data\\": { diff --git a/test/html/form.html b/test/html/form.html index 14120fd30e..9d4a0c7116 100644 --- a/test/html/form.html +++ b/test/html/form.html @@ -28,6 +28,9 @@ + diff --git a/test/html/ignore.html b/test/html/ignore.html index 91e0652d9e..f46c2efd00 100644 --- a/test/html/ignore.html +++ b/test/html/ignore.html @@ -9,7 +9,6 @@
-
diff --git a/test/integration.test.ts b/test/integration.test.ts index 24ece5c096..6b687b405e 100644 --- a/test/integration.test.ts +++ b/test/integration.test.ts @@ -213,7 +213,6 @@ describe('record integration tests', function (this: ISuite) { await page.goto('about:blank'); await page.setContent(getHtml.call(this, 'ignore.html')); - await page.type('input[type="password"]', 'password'); await page.type('.rr-ignore', 'secret'); const snapshots = await page.evaluate('window.snapshots'); @@ -230,6 +229,7 @@ describe('record integration tests', function (this: ISuite) { await page.type('input[type="text"]', 'test'); await page.click('input[type="radio"]'); await page.click('input[type="checkbox"]'); + await page.type('input[type="password"]', 'password'); await page.type('textarea', 'textarea test'); await page.select('select', '1'); @@ -245,6 +245,7 @@ describe('record integration tests', function (this: ISuite) { maskInputOptions: { text: false, textarea: false, + password: true, }, }), ); @@ -253,6 +254,7 @@ describe('record integration tests', function (this: ISuite) { await page.click('input[type="radio"]'); await page.click('input[type="checkbox"]'); await page.type('textarea', 'textarea test'); + await page.type('input[type="password"]', 'password'); await page.select('select', '1'); const snapshots = await page.evaluate('window.snapshots'); From 222e2a00640722f95f26a799ec8f67922133957c Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Thu, 18 Feb 2021 14:34:49 +0100 Subject: [PATCH 15/32] Revert "Correct dev dependencies" This reverts commit 943b18317c3b06c169c2ebf63e1b974818f4f66f. --- package.json | 9 --------- 1 file changed, 9 deletions(-) diff --git a/package.json b/package.json index 22a8d15b18..710088beda 100644 --- a/package.json +++ b/package.json @@ -35,20 +35,13 @@ }, "homepage": "https://github.com/rrweb-io/rrweb#readme", "devDependencies": { - "@babel/core": "^7.11.6", - "@babel/preset-env": "^7.11.5", "@types/chai": "^4.1.6", "@types/inquirer": "0.0.43", "@types/mocha": "^5.2.5", "@types/node": "^10.11.7", - "@types/node-fetch": "^2.5.7", "@types/puppeteer": "^1.11.1", - "babel-loader": "^8.1.0", - "babel-watch": "^7.0.0", "chai": "^4.2.0", - "core-js": "^3.6.5", "cross-env": "^5.2.0", - "css-loader": "^4.3.0", "inquirer": "^6.2.1", "jest-snapshot": "^23.6.0", "mocha": "^5.2.0", @@ -60,8 +53,6 @@ "rollup-plugin-postcss": "^3.1.1", "rollup-plugin-terser": "^5.3.0", "rollup-plugin-typescript": "^1.0.0", - "style-loader": "^1.2.1", - "ts-loader": "^8.0.4", "ts-node": "^7.0.1", "tslib": "^1.9.3", "tslint": "^4.5.1", From 11f822ae7d0295ffa16c122d953166bd17af6f68 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Thu, 18 Feb 2021 15:06:58 +0100 Subject: [PATCH 16/32] add `userTriggered` --- src/record/observer.ts | 4 +++- src/types.ts | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/record/observer.ts b/src/record/observer.ts index d71a8b0fd1..0973515a2b 100644 --- a/src/record/observer.ts +++ b/src/record/observer.ts @@ -289,6 +289,7 @@ function initInputObserver( ): listenerHandler { function eventHandler(event: Event) { const { target } = event; + const userTriggered = event.isTrusted; if ( !target || !(target as Element).tagName || @@ -320,7 +321,7 @@ function initInputObserver( text = '*'.repeat(text.length); } } - cbWithDedup(target, { text, isChecked }); + cbWithDedup(target, { text, isChecked, userTriggered }); // if a radio was checked // the other radios with the same name attribute will be unchecked. const name: string | undefined = (target as HTMLInputElement).name; @@ -332,6 +333,7 @@ function initInputObserver( cbWithDedup(el, { text: (el as HTMLInputElement).value, isChecked: !isChecked, + userTriggered: false, }); } }); diff --git a/src/types.ts b/src/types.ts index 907aea78d6..ef7715fb6c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -443,6 +443,12 @@ export type viewportResizeCallback = (d: viewportResizeDimension) => void; export type inputValue = { text: string; isChecked: boolean; + + // `userTriggered` indicates if this event was triggered directly by user (userTriggered: true) + // or was triggered indirectly (userTriggered: false) + // Example of `userTriggered` in action: + // User clicks on radio element (userTriggered: true) which triggers the other radio element to change (userTriggered: false) + userTriggered: boolean; }; export type inputCallback = (v: inputValue & { id: number }) => void; From 31862d84d9fd0db5789c939394ee739ef63c7eb3 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Thu, 18 Feb 2021 15:11:50 +0100 Subject: [PATCH 17/32] update snapshots to add userTriggered --- test/__snapshots__/integration.test.ts.snap | 383 +++----------------- 1 file changed, 60 insertions(+), 323 deletions(-) diff --git a/test/__snapshots__/integration.test.ts.snap b/test/__snapshots__/integration.test.ts.snap index f205fe9562..45ec4fea94 100644 --- a/test/__snapshots__/integration.test.ts.snap +++ b/test/__snapshots__/integration.test.ts.snap @@ -1287,6 +1287,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"t\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -1296,6 +1297,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"te\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -1305,6 +1307,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"tes\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -1314,6 +1317,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"test\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -1363,6 +1367,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"on\\", \\"isChecked\\": true, + \\"userTriggered\\": true, \\"id\\": 27 } }, @@ -1412,6 +1417,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"on\\", \\"isChecked\\": true, + \\"userTriggered\\": true, \\"id\\": 32 } }, @@ -1437,6 +1443,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"t\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1446,6 +1453,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"te\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1455,6 +1463,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"tex\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1464,6 +1473,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"text\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1473,6 +1483,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"texta\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1482,6 +1493,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"textar\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1491,6 +1503,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"textare\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1500,6 +1513,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1509,6 +1523,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea \\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1518,6 +1533,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea t\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1527,6 +1543,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea te\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1536,6 +1553,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea tes\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1545,6 +1563,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea test\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1554,6 +1573,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"1\\", \\"isChecked\\": false, + \\"userTriggered\\": false, \\"id\\": 42 } } @@ -2704,329 +2724,6 @@ exports[`ignore 1`] = ` ]" `; -exports[`log`] = ` -"[ - { - \\"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\\": \\"Log record\\", - \\"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\\": \\"script\\", - \\"attributes\\": {}, - \\"childNodes\\": [ - { - \\"type\\": 3, - \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 19 - } - ], - \\"id\\": 18 - }, - { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 20 - } - ], - \\"id\\": 16 - } - ], - \\"id\\": 3 - } - ], - \\"id\\": 1 - }, - \\"initialOffset\\": { - \\"left\\": 0, - \\"top\\": 0 - } - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"assert\\", - \\"payload\\": [ - \\"true\\", - \\"\\"assert\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"count\\", - \\"payload\\": [ - \\"\\"count\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"countReset\\", - \\"payload\\": [ - \\"\\"count\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"debug\\", - \\"payload\\": [ - \\"\\"debug\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"dir\\", - \\"payload\\": [ - \\"\\"dir\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"dirxml\\", - \\"payload\\": [ - \\"\\"dirxml\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"group\\", - \\"payload\\": [] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"groupCollapsed\\", - \\"payload\\": [] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"info\\", - \\"payload\\": [ - \\"\\"info\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"log\\", - \\"payload\\": [ - \\"\\"log\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"table\\", - \\"payload\\": [ - \\"\\"table\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"time\\", - \\"payload\\": [] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"timeEnd\\", - \\"payload\\": [] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"timeLog\\", - \\"payload\\": [] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"trace\\", - \\"payload\\": [ - \\"\\"trace\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"warn\\", - \\"payload\\": [ - \\"\\"warn\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"clear\\", - \\"payload\\": [] - } - } -]" -`; - exports[`log 1`] = ` "[ { @@ -3833,6 +3530,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"*\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -3842,6 +3540,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"**\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -3851,6 +3550,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"***\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -3860,6 +3560,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"****\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -3909,6 +3610,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"on\\", \\"isChecked\\": true, + \\"userTriggered\\": true, \\"id\\": 27 } }, @@ -3958,6 +3660,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"on\\", \\"isChecked\\": true, + \\"userTriggered\\": true, \\"id\\": 32 } }, @@ -3983,6 +3686,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"*\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3992,6 +3696,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"**\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4001,6 +3706,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"***\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4010,6 +3716,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"****\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4019,6 +3726,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"*****\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4028,6 +3736,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"******\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4037,6 +3746,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"*******\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4046,6 +3756,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"********\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4055,6 +3766,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"*********\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4064,6 +3776,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"**********\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4073,6 +3786,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"***********\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4082,6 +3796,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"************\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4091,6 +3806,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"*************\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4100,6 +3816,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"*\\", \\"isChecked\\": false, + \\"userTriggered\\": false, \\"id\\": 42 } } @@ -4521,6 +4238,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"t\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -4530,6 +4248,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"te\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -4539,6 +4258,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"tes\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -4548,6 +4268,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"test\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -4597,6 +4318,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"on\\", \\"isChecked\\": true, + \\"userTriggered\\": true, \\"id\\": 27 } }, @@ -4646,6 +4368,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"on\\", \\"isChecked\\": true, + \\"userTriggered\\": true, \\"id\\": 32 } }, @@ -4671,6 +4394,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"t\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4680,6 +4404,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"te\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4689,6 +4414,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"tex\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4698,6 +4424,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"text\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4707,6 +4434,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"texta\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4716,6 +4444,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"textar\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4725,6 +4454,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"textare\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4734,6 +4464,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4743,6 +4474,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea \\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4752,6 +4484,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea t\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4761,6 +4494,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea te\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4770,6 +4504,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea tes\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4779,6 +4514,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea test\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -4788,6 +4524,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"1\\", \\"isChecked\\": false, + \\"userTriggered\\": false, \\"id\\": 42 } } From 8db1a6b058ae4a8bea1b894bd506093f719ebe6f Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Thu, 18 Feb 2021 17:18:37 +0100 Subject: [PATCH 18/32] Revert "Do not ignore password fields, but allow them to be masked instead" This reverts commit 0cf62c08571b27513d46c114dd94eedc67bebcfe. --- guide.md | 40 ++++++++++++++++++++-------------------- scripts/repl.ts | 6 ++---- src/record/index.ts | 1 - src/record/observer.ts | 1 + 4 files changed, 23 insertions(+), 25 deletions(-) diff --git a/guide.md b/guide.md index 3cdc679602..65a54fafeb 100644 --- a/guide.md +++ b/guide.md @@ -135,25 +135,25 @@ setInterval(save, 10 * 1000); The parameter of `rrweb.record` accepts the following options. -| key | default | description | -| ---------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| emit | required | the callback function to get emitted events | -| checkoutEveryNth | - | take a full snapshot after every N events
refer to the [checkout](#checkout) chapter | -| checkoutEveryNms | - | take a full snapshot after every N ms
refer to the [checkout](#checkout) chapter | -| blockClass | 'rr-block' | Use a string or RegExp to configure which elements 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 | -| blockSelector | null | Use a string or RegExp to configure which selector should be blocked, refer to the [privacy](#privacy) chapter | -| maskAllInputs | false | mask all input content as \* | -| maskInputOptions | {} | mask some kinds of input \*
refer to the [list](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L72) | -| maskInputFn | - | customize mask input content recording logic | -| slimDOMOptions | {} | remove unnecessary parts of the DOM
refer to the [list](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L91) | -| inlineStylesheet | true | whether to inline the stylesheet in the events | -| hooks | {} | hooks for events
refer to the [list](https://github.com/rrweb-io/rrweb/blob/9488deb6d54a5f04350c063d942da5e96ab74075/src/types.ts#L207) | -| packFn | - | refer to the [storage optimization recipe](./docs/recipes/optimize-storage.md) | -| sampling | - | refer to the [storage optimization recipe](./docs/recipes/optimize-storage.md) | -| recordCanvas | false | whether to record the canvas element | -| collectFonts | false | whether to collect fonts in the website | -| recordLog | false | whether to record console output, refer to the [console recipe](./docs/recipes/console.md) | +| key | default | description | +| ---------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| emit | required | the callback function to get emitted events | +| checkoutEveryNth | - | take a full snapshot after every N events
refer to the [checkout](#checkout) chapter | +| checkoutEveryNms | - | take a full snapshot after every N ms
refer to the [checkout](#checkout) chapter | +| blockClass | 'rr-block' | Use a string or RegExp to configure which elements 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 | +| blockSelector | null | Use a string or RegExp to configure which selector should be blocked, refer to the [privacy](#privacy) chapter | +| maskAllInputs | false | mask all input content as \* | +| maskInputOptions | {} | mask some kinds of input \*
refer to the [list](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L72) | +| maskInputFn | - | customize mask input content recording logic | +| slimDOMOptions | {} | remove unnecessary parts of the DOM
refer to the [list](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L91) | +| inlineStylesheet | true | whether to inline the stylesheet in the events | +| hooks | {} | hooks for events
refer to the [list](https://github.com/rrweb-io/rrweb/blob/9488deb6d54a5f04350c063d942da5e96ab74075/src/types.ts#L207) | +| packFn | - | refer to the [storage optimization recipe](./docs/recipes/optimize-storage.md) | +| sampling | - | refer to the [storage optimization recipe](./docs/recipes/optimize-storage.md) | +| recordCanvas | false | whether to record the canvas element | +| collectFonts | false | whether to collect fonts in the website | +| recordLog | false | whether to record console output, refer to the [console recipe](./docs/recipes/console.md) | #### Privacy @@ -161,7 +161,7 @@ You may find some contents on the webpage which are not willing to be recorded, - An element with the class name `.rr-block` will not be recorded. Instead, it will replay as a placeholder with the same dimension. - An element with the class name `.rr-ignore` will not record its input events. -- You’ll probably want to mask `input[type="password"]` by adding `maskInputOptions: {password: true}` +- `input[type="password"]` will be ignored as default. - Mask options to mask the content in input elements. #### Checkout diff --git a/scripts/repl.ts b/scripts/repl.ts index ef97465a7e..1b933079a5 100644 --- a/scripts/repl.ts +++ b/scripts/repl.ts @@ -100,8 +100,7 @@ function getCode(): string { rrweb.record({ emit: event => window._replLog(event), recordCanvas: true, - collectFonts: true, - maskInputOptions: { password: true } + collectFonts: true }); `); page.on('framenavigated', async () => { @@ -112,8 +111,7 @@ function getCode(): string { rrweb.record({ emit: event => window._replLog(event), recordCanvas: true, - collectFonts: true, - maskInputOptions: { password: true } + collectFonts: true }); `); } diff --git a/src/record/index.ts b/src/record/index.ts index 61f3ca1fc1..70333c0747 100644 --- a/src/record/index.ts +++ b/src/record/index.ts @@ -69,7 +69,6 @@ function record( email: true, month: true, number: true, - password: true, range: true, search: true, tel: true, diff --git a/src/record/observer.ts b/src/record/observer.ts index 37977d1b58..069be64fbf 100644 --- a/src/record/observer.ts +++ b/src/record/observer.ts @@ -306,6 +306,7 @@ function initInputObserver( const type: string | undefined = (target as HTMLInputElement).type; if ( + type === 'password' || (target as HTMLElement).classList.contains(ignoreClass) ) { return; From 006ea41ae645528658a7c770ce136dd444009eed Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Thu, 18 Feb 2021 17:23:48 +0100 Subject: [PATCH 19/32] Revert "@Juice10: Add a flag for rrweb generated events" This reverts commit 425a04092d8cb036d83bd9e230be7ab8aebe6354. --- src/record/observer.ts | 7 ++----- src/types.ts | 1 - 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/record/observer.ts b/src/record/observer.ts index 90315e29e5..dd9d879dc1 100644 --- a/src/record/observer.ts +++ b/src/record/observer.ts @@ -289,8 +289,6 @@ function initInputObserver( ): listenerHandler { function eventHandler(event: KeyboardEvent) { // was Event const { target } = event; - const rrwebGenerated = !event.isTrusted; - if ( !target || !(target as Element).tagName || @@ -301,7 +299,7 @@ function initInputObserver( } if (event.type === 'keyup' && event.key === 'Enter') { - return cbWithDedup(target, { key: 'Enter', rrwebGenerated }); + return cbWithDedup(target, { key: 'Enter' }); } const type: string | undefined = (target as HTMLInputElement).type; @@ -324,7 +322,7 @@ function initInputObserver( text = '*'.repeat(text.length); } } - cbWithDedup(target, { text, isChecked, rrwebGenerated }); + cbWithDedup(target, { text, isChecked }); // if a radio was checked // the other radios with the same name attribute will be unchecked. const name: string | undefined = (target as HTMLInputElement).name; @@ -336,7 +334,6 @@ function initInputObserver( cbWithDedup(el, { text: (el as HTMLInputElement).value, isChecked: !isChecked, - rrwebGenerated: true, }); } }); diff --git a/src/types.ts b/src/types.ts index 916d4724b4..056bcdcfa0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -444,7 +444,6 @@ export type inputValue = { text?: string; isChecked?: boolean; key?: string; - rrwebGenerated: boolean; }; export type inputCallback = (v: inputValue & { id: number }) => void; From 52bb343ec69a1c0089d261a89a30cad272489e41 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Thu, 18 Feb 2021 17:25:54 +0100 Subject: [PATCH 20/32] =?UTF-8?q?Revert=20"Register=20Enter=20event=20@=20?= =?UTF-8?q?porting=20from=20@Juice10=E2=80=99s=20rrweb"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 0333f38b452302b0546e2fee2c7b3843639dabbb. --- src/record/observer.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/record/observer.ts b/src/record/observer.ts index eb22e3b478..e938d805e4 100644 --- a/src/record/observer.ts +++ b/src/record/observer.ts @@ -287,7 +287,7 @@ function initInputObserver( maskInputFn: MaskInputFn | undefined, sampling: SamplingStrategy, ): listenerHandler { - function eventHandler(event: KeyboardEvent) { // was Event + function eventHandler(event: Event) { const { target } = event; const userTriggered = event.isTrusted; if ( @@ -298,11 +298,6 @@ function initInputObserver( ) { return; } - - if (event.type === 'keyup' && event.key === 'Enter') { - return cbWithDedup(target, { key: 'Enter' }); - } - const type: string | undefined = (target as HTMLInputElement).type; if ((target as HTMLElement).classList.contains(ignoreClass)) { return; @@ -346,8 +341,7 @@ function initInputObserver( if ( !lastInputValue || lastInputValue.text !== v.text || - lastInputValue.isChecked !== v.isChecked || - lastInputValue.key !== v.key + lastInputValue.isChecked !== v.isChecked ) { lastInputValueMap.set(target, v); const id = mirror.getId(target as INode); @@ -379,7 +373,7 @@ function initInputObserver( hookSetter(p[0], p[1], { set() { // mock to a normal event - eventHandler({ target: this } as KeyboardEvent); // was Event + eventHandler({ target: this } as Event); }, }), ), From e058ae49c9a8c82dd0d751e80f26718088e99103 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Thu, 18 Feb 2021 17:32:28 +0100 Subject: [PATCH 21/32] align tests --- test/__snapshots__/integration.test.ts.snap | 407 ++++++++++++++++++++ 1 file changed, 407 insertions(+) diff --git a/test/__snapshots__/integration.test.ts.snap b/test/__snapshots__/integration.test.ts.snap index 33181e073e..ebd9dc2830 100644 --- a/test/__snapshots__/integration.test.ts.snap +++ b/test/__snapshots__/integration.test.ts.snap @@ -2709,6 +2709,397 @@ exports[`ignore 1`] = ` `; exports[`log 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\\": \\"Log record\\", + \\"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\\": \\"script\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", + \\"id\\": 19 + } + ], + \\"id\\": 18 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", + \\"id\\": 20 + } + ], + \\"id\\": 16 + } + ], + \\"id\\": 3 + } + ], + \\"id\\": 1 + }, + \\"initialOffset\\": { + \\"left\\": 0, + \\"top\\": 0 + } + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 11, + \\"level\\": \\"assert\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:2:37\\" + ], + \\"payload\\": [ + \\"true\\", + \\"\\\\\\"assert\\\\\\"\\" + ] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 11, + \\"level\\": \\"count\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:3:37\\" + ], + \\"payload\\": [ + \\"\\\\\\"count\\\\\\"\\" + ] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 11, + \\"level\\": \\"countReset\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:4:37\\" + ], + \\"payload\\": [ + \\"\\\\\\"count\\\\\\"\\" + ] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 11, + \\"level\\": \\"debug\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:5:37\\" + ], + \\"payload\\": [ + \\"\\\\\\"debug\\\\\\"\\" + ] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 11, + \\"level\\": \\"dir\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:6:37\\" + ], + \\"payload\\": [ + \\"\\\\\\"dir\\\\\\"\\" + ] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 11, + \\"level\\": \\"dirxml\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:7:37\\" + ], + \\"payload\\": [ + \\"\\\\\\"dirxml\\\\\\"\\" + ] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 11, + \\"level\\": \\"group\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:8:37\\" + ], + \\"payload\\": [] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 11, + \\"level\\": \\"groupCollapsed\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:9:37\\" + ], + \\"payload\\": [] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 11, + \\"level\\": \\"info\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:10:37\\" + ], + \\"payload\\": [ + \\"\\\\\\"info\\\\\\"\\" + ] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 11, + \\"level\\": \\"log\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:11:37\\" + ], + \\"payload\\": [ + \\"\\\\\\"log\\\\\\"\\" + ] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 11, + \\"level\\": \\"table\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:12:37\\" + ], + \\"payload\\": [ + \\"\\\\\\"table\\\\\\"\\" + ] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 11, + \\"level\\": \\"time\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:13:37\\" + ], + \\"payload\\": [] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 11, + \\"level\\": \\"timeEnd\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:14:37\\" + ], + \\"payload\\": [] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 11, + \\"level\\": \\"timeLog\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:15:37\\" + ], + \\"payload\\": [] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 11, + \\"level\\": \\"trace\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:16:37\\" + ], + \\"payload\\": [ + \\"\\\\\\"trace\\\\\\"\\" + ] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 11, + \\"level\\": \\"warn\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:17:37\\" + ], + \\"payload\\": [ + \\"\\\\\\"warn\\\\\\"\\" + ] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 11, + \\"level\\": \\"clear\\", + \\"trace\\": [ + \\"__puppeteer_evalu\\", + \\"ion_script__:18:37\\" + ], + \\"payload\\": [] + } + } +]" +`; + +exports[`mask 1`] = ` "[ { \\"type\\": 0, @@ -3313,6 +3704,7 @@ exports[`log 1`] = ` \\"source\\": 5, \\"text\\": \\"*\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 54 } }, @@ -3322,6 +3714,7 @@ exports[`log 1`] = ` \\"source\\": 5, \\"text\\": \\"**\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 54 } }, @@ -3331,6 +3724,7 @@ exports[`log 1`] = ` \\"source\\": 5, \\"text\\": \\"***\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 54 } }, @@ -3340,6 +3734,7 @@ exports[`log 1`] = ` \\"source\\": 5, \\"text\\": \\"****\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 54 } }, @@ -3349,6 +3744,7 @@ exports[`log 1`] = ` \\"source\\": 5, \\"text\\": \\"*****\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 54 } }, @@ -3358,6 +3754,7 @@ exports[`log 1`] = ` \\"source\\": 5, \\"text\\": \\"******\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 54 } }, @@ -3367,6 +3764,7 @@ exports[`log 1`] = ` \\"source\\": 5, \\"text\\": \\"*******\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 54 } }, @@ -3376,6 +3774,7 @@ exports[`log 1`] = ` \\"source\\": 5, \\"text\\": \\"********\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 54 } }, @@ -4289,6 +4688,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"*\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 54 } }, @@ -4298,6 +4698,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"**\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 54 } }, @@ -4307,6 +4708,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"***\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 54 } }, @@ -4316,6 +4718,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"****\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 54 } }, @@ -4325,6 +4728,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"*****\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 54 } }, @@ -4334,6 +4738,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"******\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 54 } }, @@ -4343,6 +4748,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"*******\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 54 } }, @@ -4352,6 +4758,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"********\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 54 } }, From ff84ac9fde102ef9a9534065162945c146c8a4eb Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Thu, 18 Feb 2021 17:39:24 +0100 Subject: [PATCH 22/32] UNDO ME: temporarily set rrweb-snapshot to juice10's repo --- package.json | 2 +- yarn.lock | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 710088beda..610aa6809c 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,6 @@ "@xstate/fsm": "^1.4.0", "fflate": "^0.4.4", "mitt": "^1.1.3", - "rrweb-snapshot": "^1.0.7" + "rrweb-snapshot": "Juice10/rrweb-snapshot#patch-1" } } diff --git a/yarn.lock b/yarn.lock index d7d1d0a179..9d46158b40 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2754,10 +2754,9 @@ rollup@^2.3.3: optionalDependencies: fsevents "~2.1.2" -rrweb-snapshot@^1.0.7: +rrweb-snapshot@Juice10/rrweb-snapshot#patch-1: version "1.0.7" - resolved "https://registry.yarnpkg.com/rrweb-snapshot/-/rrweb-snapshot-1.0.7.tgz#9d334590089af4a857970ef4e9e978d986a122d1" - integrity sha512-6fu9+KiQlFPkFk2SdahIDsV+yu1juiAR/o+kOiwKPbXur1TiFGMPAfaQNCkqLc8Nvyx3ItkJmrIldyxnAalEag== + resolved "https://codeload.github.com/Juice10/rrweb-snapshot/tar.gz/dd811bcb6e24ad7e2f64f8dc336a986cea4507dc" run-async@^2.2.0: version "2.4.1" From b5c0bef9ae530a5fe6543356c6f5b8cc54d36be0 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Thu, 18 Feb 2021 17:40:41 +0100 Subject: [PATCH 23/32] update types --- typings/types.d.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/typings/types.d.ts b/typings/types.d.ts index a8d9fa946c..b1ab861460 100644 --- a/typings/types.d.ts +++ b/typings/types.d.ts @@ -313,10 +313,9 @@ export declare type viewportResizeDimension = { }; export declare type viewportResizeCallback = (d: viewportResizeDimension) => void; export declare type inputValue = { - text?: string; - isChecked?: boolean; - key?: string; - rrwebGenerated: boolean; + text: string; + isChecked: boolean; + userTriggered: boolean; }; export declare type inputCallback = (v: inputValue & { id: number; From ea797791d086afcc5e04aff41f398f17c9580bcd Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Thu, 18 Feb 2021 20:10:21 +0100 Subject: [PATCH 24/32] use prepack instead of prepare --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8c0a541005..bbb49611fb 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.9.14", "description": "record and replay the web", "scripts": { - "prepare": "npm run bundle", + "prepack": "npm run bundle", "test": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true mocha -r ts-node/register test/**/*.test.ts", "test:watch": "PUPPETEER_HEADLESS=true npm run test -- --watch --watch-extensions js,ts", "repl": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true ts-node scripts/repl.ts", From 12e0455c2f119a0d6de20d974035ad6d5389bb1a Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Thu, 18 Feb 2021 20:23:56 +0100 Subject: [PATCH 25/32] after prepack don't remove the build directories --- .npmignore | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .npmignore diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000000..a60dbbe6db --- /dev/null +++ b/.npmignore @@ -0,0 +1,6 @@ +.vscode +.idea +node_modules +package-lock.json +temp +*.log \ No newline at end of file From 4741c66a51e8b59a7fb67954e3202a3a1d9f4c90 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Thu, 18 Feb 2021 20:26:06 +0100 Subject: [PATCH 26/32] maybe this works --- .npmignore | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.npmignore b/.npmignore index a60dbbe6db..e69de29bb2 100644 --- a/.npmignore +++ b/.npmignore @@ -1,6 +0,0 @@ -.vscode -.idea -node_modules -package-lock.json -temp -*.log \ No newline at end of file From b1da6f5186b9d2fe2a4ffd4a27e67f3acb50a65e Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Thu, 18 Feb 2021 20:40:28 +0100 Subject: [PATCH 27/32] for compatibility add both prepare and prepack --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index bbb49611fb..4362eb7690 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.9.14", "description": "record and replay the web", "scripts": { + "prepare": "npm run prepack", "prepack": "npm run bundle", "test": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true mocha -r ts-node/register test/**/*.test.ts", "test:watch": "PUPPETEER_HEADLESS=true npm run test -- --watch --watch-extensions js,ts", From 6889d2f2c53edb955ff147cd8b0beb5c76d8d9fb Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Thu, 18 Feb 2021 21:24:35 +0100 Subject: [PATCH 28/32] upgrade rrweb snapshot --- package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 4362eb7690..759c6b06fb 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,6 @@ "@xstate/fsm": "^1.4.0", "fflate": "^0.4.4", "mitt": "^1.1.3", - "rrweb-snapshot": "Juice10/rrweb-snapshot#patch-1" + "rrweb-snapshot": "Juice10/rrweb-snapshot#b682ca1c72b1ddee4abee4a5aad7b9d41d6d3574" } } diff --git a/yarn.lock b/yarn.lock index 9d46158b40..ef2d5a76c2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2754,9 +2754,9 @@ rollup@^2.3.3: optionalDependencies: fsevents "~2.1.2" -rrweb-snapshot@Juice10/rrweb-snapshot#patch-1: +rrweb-snapshot@Juice10/rrweb-snapshot#b682ca1c72b1ddee4abee4a5aad7b9d41d6d3574: version "1.0.7" - resolved "https://codeload.github.com/Juice10/rrweb-snapshot/tar.gz/dd811bcb6e24ad7e2f64f8dc336a986cea4507dc" + resolved "https://codeload.github.com/Juice10/rrweb-snapshot/tar.gz/b682ca1c72b1ddee4abee4a5aad7b9d41d6d3574" run-async@^2.2.0: version "2.4.1" From 35eba7286f7a7d5f6ad0aa76fd9061f0c3ebc3fc Mon Sep 17 00:00:00 2001 From: Yun Feng Date: Mon, 26 Apr 2021 16:28:55 +0800 Subject: [PATCH 29/32] fix: issue #548 1. Do not use virtual parent optimization if the mutation targets have iframe elements as children. This will cause some performance regression but will be easy to add and ship. 2. If an iframe element has already been a child of a virtual parent, add the virtual parent back to the dom. --- src/replay/index.ts | 72 ++++++++++++++++++++++++++++----------- typings/replay/index.d.ts | 1 + 2 files changed, 54 insertions(+), 19 deletions(-) diff --git a/src/replay/index.ts b/src/replay/index.ts index 61c7559c2e..07bd69a472 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -166,23 +166,9 @@ export class Replayer { this.emitter.on(ReplayerEvents.Flush, () => { const { scrollMap, inputMap } = this.treeIndex.flush(); - for (const [frag, parent] of this.fragmentParentMap.entries()) { - mirror.map[parent.__sn.id] = parent; - /** - * If we have already set value attribute on textarea, - * then we could not apply text content as default value any more. - */ - if ( - parent.__sn.type === NodeType.Element && - parent.__sn.tagName === 'textarea' && - frag.textContent - ) { - ((parent as unknown) as HTMLTextAreaElement).value = frag.textContent; - } - parent.appendChild(frag); - // restore state of elements after they are mounted - this.restoreState(parent); - } + this.fragmentParentMap.forEach((parent, frag) => + this.restoreRealParent(frag, parent), + ); this.fragmentParentMap.clear(); this.elementStateMap.clear(); @@ -627,6 +613,20 @@ export class Replayer { iframeEl: HTMLIFrameElement, ) { const collected: AppendedIframe[] = []; + // If iframeEl is detached from dom, iframeEl.contentDocument is null. + if (!iframeEl.contentDocument) { + let parent = iframeEl.parentNode; + while (parent) { + // The parent of iframeEl is virtual parent and we need to mount it on the dom. + if (this.fragmentParentMap.has((parent as unknown) as INode)) { + const frag = (parent as unknown) as INode; + const realParent = this.fragmentParentMap.get(frag)!; + this.restoreRealParent(frag, realParent); + break; + } + parent = parent.parentNode; + } + } buildNodeWithSN(mutation.node, { doc: iframeEl.contentDocument!, map: mirror.map, @@ -1139,8 +1139,19 @@ export class Replayer { parentInDocument = this.iframe.contentDocument.body.contains(parent); } - // if parent element is an iframe, iframe document can't be appended to virtual parent - if (useVirtualParent && parentInDocument && !isIframeINode(parent)) { + const hasIframeChild = + ((parent as unknown) as HTMLElement).getElementsByTagName?.('iframe') + .length > 0; + /** + * Why !isIframeINode(parent)? If parent element is an iframe, iframe document can't be appended to virtual parent. + * Why !hasIframeChild? If we move iframe elements from dom to fragment document, we will lose the contentDocument of iframe. So we need to disable the virtual dom optimization if a parent node contains iframe elements. + */ + if ( + useVirtualParent && + parentInDocument && + !isIframeINode(parent) && + !hasIframeChild + ) { const virtualParent = (document.createDocumentFragment() as unknown) as INode; mirror.map[mutation.parentId] = virtualParent; this.fragmentParentMap.set(virtualParent, parent); @@ -1529,6 +1540,29 @@ export class Replayer { }); } + /** + * Replace the virtual parent with the real parent. + * @param frag fragment document, the virtual parent + * @param parent real parent element + */ + private restoreRealParent(frag: INode, parent: INode) { + mirror.map[parent.__sn.id] = parent; + /** + * If we have already set value attribute on textarea, + * then we could not apply text content as default value any more. + */ + if ( + parent.__sn.type === NodeType.Element && + parent.__sn.tagName === 'textarea' && + frag.textContent + ) { + ((parent as unknown) as HTMLTextAreaElement).value = frag.textContent; + } + parent.appendChild(frag); + // restore state of elements after they are mounted + this.restoreState(parent); + } + /** * store state of elements before unmounted from dom recursively * the state should be restored in the handler of event ReplayerEvents.Flush diff --git a/typings/replay/index.d.ts b/typings/replay/index.d.ts index f1df3a2f72..441552ed37 100644 --- a/typings/replay/index.d.ts +++ b/typings/replay/index.d.ts @@ -55,6 +55,7 @@ export declare class Replayer { private hoverElements; private isUserInteraction; private backToNormal; + private restoreRealParent; private storeState; private restoreState; private warnNodeNotFound; From c2baa9a47264609b5b1655f037db226b81513d35 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Wed, 28 Apr 2021 19:28:50 +0200 Subject: [PATCH 30/32] Revert "UNDO ME: temporarily set rrweb-snapshot to juice10's repo" This reverts commit ff84ac9fde102ef9a9534065162945c146c8a4eb. --- package.json | 2 +- yarn.lock | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 759c6b06fb..bd03c47cce 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,6 @@ "@xstate/fsm": "^1.4.0", "fflate": "^0.4.4", "mitt": "^1.1.3", - "rrweb-snapshot": "Juice10/rrweb-snapshot#b682ca1c72b1ddee4abee4a5aad7b9d41d6d3574" + "rrweb-snapshot": "^1.0.7" } } diff --git a/yarn.lock b/yarn.lock index ef2d5a76c2..d7d1d0a179 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2754,9 +2754,10 @@ rollup@^2.3.3: optionalDependencies: fsevents "~2.1.2" -rrweb-snapshot@Juice10/rrweb-snapshot#b682ca1c72b1ddee4abee4a5aad7b9d41d6d3574: +rrweb-snapshot@^1.0.7: version "1.0.7" - resolved "https://codeload.github.com/Juice10/rrweb-snapshot/tar.gz/b682ca1c72b1ddee4abee4a5aad7b9d41d6d3574" + resolved "https://registry.yarnpkg.com/rrweb-snapshot/-/rrweb-snapshot-1.0.7.tgz#9d334590089af4a857970ef4e9e978d986a122d1" + integrity sha512-6fu9+KiQlFPkFk2SdahIDsV+yu1juiAR/o+kOiwKPbXur1TiFGMPAfaQNCkqLc8Nvyx3ItkJmrIldyxnAalEag== run-async@^2.2.0: version "2.4.1" From 5a61cbf253b788c91394da2d83109a8871f76369 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Sun, 25 Apr 2021 15:57:20 +0200 Subject: [PATCH 31/32] set scope of npm package to recordonce --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 4c3d86fe38..d7ae23a781 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "rrweb", + "name": "@recordonce/rrweb", "version": "0.9.14", "description": "record and replay the web", "scripts": { @@ -14,7 +14,7 @@ }, "repository": { "type": "git", - "url": "git+ssh://git@github.com/rrweb-io/rrweb.git" + "url": "git+ssh://git@github.com/recordonce/rrweb.git" }, "keywords": [ "rrweb" From 26d699288240569490c25bc39cd95e548e510b21 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Wed, 28 Apr 2021 22:10:23 +0200 Subject: [PATCH 32/32] Release 0.9.15-beta.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d7ae23a781..61b111c876 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@recordonce/rrweb", - "version": "0.9.14", + "version": "0.9.15-beta.0", "description": "record and replay the web", "scripts": { "prepare": "npm run prepack",