├── .cache └── .gitkeep ├── .changeset ├── README.md ├── angry-turtles-provide.md ├── attribute-text-reductions.md ├── beige-olives-roll.md ├── blank-cherries-laugh.md ├── blank-dev-changset.md ├── brave-numbers-joke.md ├── breezy-cats-heal.md ├── breezy-mice-breathe.md ├── bright-socks-clap.md ├── calm-bulldogs-speak.md ├── calm-oranges-sin.md ├── chatty-cherries-train.md ├── chilled-penguins-sin.md ├── clean-plants-play.md ├── clean-shrimps-lay.md ├── cold-eyes-hunt.md ├── cold-hounds-teach.md ├── config.json ├── controller-finish-flag.md ├── cool-grapes-hug.md ├── cool-horses-bow.md ├── cuddly-bikes-fail.md ├── cuddly-readers-warn.md ├── curvy-apples-lay.md ├── curvy-balloons-brake.md ├── date-now-guard.md ├── dirty-pets-fly.md ├── dirty-rules-dress.md ├── efficiently-splitCssText-1603.md ├── efficiently-splitCssText-1640.md ├── eight-terms-hunt.md ├── eighty-teachers-smash.md ├── eleven-bobcats-peel.md ├── eleven-toys-vanish.md ├── empty-bikes-cheer.md ├── eslint-camelcase-devonly.md ├── event-single-wrap.md ├── fair-dragons-greet.md ├── fair-ducks-clean.md ├── famous-bobcats-push.md ├── fast-chefs-smell.md ├── fast-pets-exist.md ├── few-rockets-travel.md ├── few-turkeys-reflect.md ├── five-peas-lay.md ├── fix-adapt-css.md ├── fluffy-planes-retire.md ├── format-head-prettier.md ├── forty-elephants-attack.md ├── four-panthers-fly.md ├── fresh-cars-impress.md ├── fresh-spoons-drive.md ├── friendly-numbers-leave.md ├── fuzzy-mugs-march.md ├── giant-rats-chew.md ├── gold-apples-joke.md ├── gold-experts-type.md ├── gold-terms-look.md ├── great-cows-camp.md ├── grumpy-ways-own.md ├── happy-carrots-hide.md ├── hip-worms-relax.md ├── hungry-dodos-taste.md ├── inlineImage-maybeNot-crossOrigin.md ├── itchy-dryers-double.md ├── itchy-tables-compete.md ├── khaki-dots-bathe.md ├── kind-kids-design.md ├── large-ants-prove.md ├── last-jest-to-vitest.md ├── lazy-squids-draw.md ├── lazy-toes-confess.md ├── lemon-lamps-switch.md ├── light-fireants-exercise.md ├── little-radios-thank.md ├── little-suits-leave.md ├── loud-seals-raise.md ├── lovely-files-sparkle.md ├── lovely-pears-cross.md ├── lovely-students-boil.md ├── lucky-donuts-hammer.md ├── mean-tips-impress.md ├── metal-mugs-mate.md ├── mighty-ads-worry.md ├── mighty-bulldogs-begin.md ├── mighty-frogs-sparkle.md ├── modern-doors-watch.md ├── moody-dots-refuse.md ├── moody-experts-build.md ├── nasty-scissors-reply.md ├── nervous-buses-pump.md ├── nervous-kiwis-nail.md ├── nervous-mirrors-perform.md ├── nervous-poets-grin.md ├── nervous-tables-travel.md ├── new-snakes-call.md ├── nice-pugs-reply.md ├── no-neg-lookbehind.md ├── odd-onions-brush.md ├── old-dryers-hide.md ├── perfect-bulldogs-punch.md ├── perfect-dolls-grab.md ├── polite-olives-wave.md ├── pre.json ├── pretty-meals-flash.md ├── pretty-plums-rescue.md ├── pretty-schools-remember.md ├── proud-clocks-hope.md ├── proud-experts-jam.md ├── purple-carrots-film.md ├── rare-adults-sneeze.md ├── real-masks-explode.md ├── real-trains-switch.md ├── red-peaches-explode.md ├── rich-crews-protect.md ├── rich-dots-lay.md ├── rich-jars-remember.md ├── rotten-spies-enjoy.md ├── serious-ants-juggle.md ├── serious-eggs-greet.md ├── shadow-dom-unbusify.md ├── short-hounds-confess.md ├── shy-countries-rhyme.md ├── silent-plants-perform.md ├── silly-knives-chew.md ├── silver-pots-sit.md ├── silver-windows-float.md ├── simplifify-hover-replacement.md ├── single-style-capture.md ├── six-llamas-brush.md ├── sixty-impalas-laugh.md ├── skip-mask-check-on-leaf-elements.md ├── slimy-eagles-grow.md ├── small-hats-kneel.md ├── small-olives-arrive.md ├── smart-ears-refuse.md ├── smart-geckos-cover.md ├── smooth-papayas-boil.md ├── smooth-poems-bake.md ├── soft-worms-tan.md ├── spotty-bees-destroy.md ├── stupid-ghosts-help.md ├── swift-dancers-rest.md ├── swift-peas-film.md ├── swift-pots-search.md ├── textarea-inner-html.md ├── thin-vans-applaud.md ├── thirty-baboons-punch.md ├── three-baboons-bow.md ├── tidy-swans-repair.md ├── tidy-yaks-joke.md ├── tiny-buckets-love.md ├── tiny-candles-whisper.md ├── tiny-chairs-build.md ├── title-deanimate-option.md ├── tricky-panthers-guess.md ├── twenty-goats-kneel.md ├── twenty-lies-switch.md ├── twenty-planets-repeat.md ├── two-boats-boil.md ├── unlucky-mirrors-invite.md ├── violet-melons-itch.md ├── violet-zebras-cry.md ├── wicked-dolphins-tie.md ├── wicked-lions-return.md ├── wise-spiders-jog.md ├── witty-kids-talk.md ├── yellow-mails-cheat.md └── young-timers-grow.md ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── feature_request.yml ├── config.yml └── workflows │ ├── ci-cd.yml │ ├── release.yml │ └── style-check.yml ├── .gitignore ├── .markdownlint.yml ├── .npmignore ├── .prettierignore ├── .prettierrc ├── .puppeteerrc.cjs ├── .release-it.json ├── .vscode └── rrweb-monorepo.code-workspace ├── .yarn └── releases │ └── yarn-1.23.0-20220130.1630.cjs ├── .yarnrc.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── README.zh_CN.md ├── docs ├── development │ └── coding-style.md ├── observer.md ├── observer.zh_CN.md ├── recipes │ ├── canvas.md │ ├── canvas.zh_CN.md │ ├── console.md │ ├── console.zh_CN.md │ ├── cross-origin-iframes.md │ ├── cross-origin-iframes.zh_CN.md │ ├── custom-event.md │ ├── custom-event.zh_CN.md │ ├── customize-replayer.md │ ├── customize-replayer.zh_CN.md │ ├── dive-into-event.md │ ├── dive-into-event.zh_CN.md │ ├── export-to-video.md │ ├── export-to-video.zh_CN.md │ ├── index.md │ ├── index.zh_CN.md │ ├── interaction.md │ ├── interaction.zh_CN.md │ ├── live-mode.md │ ├── live-mode.zh_CN.md │ ├── optimize-storage.md │ ├── optimize-storage.zh_CN.md │ ├── pagination.md │ ├── pagination.zh_CN.md │ ├── plugin.md │ ├── plugin.zh_CN.md │ ├── record-and-replay.md │ └── record-and-replay.zh_CN.md ├── replay.md ├── replay.zh_CN.md ├── sandbox.md ├── sandbox.zh_CN.md ├── serialization.md ├── serialization.zh_CN.md └── styleguide.md ├── guide.md ├── guide.zh_CN.md ├── package.json ├── packages ├── all │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.ts │ ├── test │ │ ├── __snapshots__ │ │ │ └── cross-origin-iframe-packer.test.ts.snap │ │ ├── cross-origin-iframe-packer.test.ts │ │ ├── html │ │ │ └── blank.html │ │ └── utils.ts │ ├── tsconfig.json │ ├── vite.config.ts │ └── vitest.config.ts ├── packer │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── pack │ │ └── package.json │ ├── package.json │ ├── src │ │ ├── base.ts │ │ ├── index.ts │ │ ├── pack.ts │ │ └── unpack.ts │ ├── test │ │ ├── __snapshots__ │ │ │ └── packer.test.ts.snap │ │ └── packer.test.ts │ ├── tsconfig.json │ ├── unpack │ │ └── package.json │ └── vite.config.ts ├── plugins │ ├── rrweb-plugin-canvas-webrtc-record │ │ ├── CHANGELOG.md │ │ ├── Readme.md │ │ ├── package.json │ │ ├── src │ │ │ ├── index.ts │ │ │ ├── simple-peer-light.d.ts │ │ │ └── types.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── rrweb-plugin-canvas-webrtc-replay │ │ ├── CHANGELOG.md │ │ ├── Readme.md │ │ ├── package.json │ │ ├── src │ │ │ ├── index.ts │ │ │ ├── simple-peer-light.d.ts │ │ │ └── types.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── rrweb-plugin-console-record │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ ├── error-stack-parser.ts │ │ │ ├── index.ts │ │ │ └── stringify.ts │ │ ├── test │ │ │ ├── __snapshots__ │ │ │ │ └── index.test.ts.snap │ │ │ ├── html │ │ │ │ ├── index.ts │ │ │ │ └── log.html │ │ │ ├── index.test.ts │ │ │ └── stringify.test.ts │ │ ├── tsconfig.json │ │ ├── vite.config.ts │ │ └── vitest.config.ts │ ├── rrweb-plugin-console-replay │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ └── index.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── rrweb-plugin-sequential-id-record │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ └── index.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts │ └── rrweb-plugin-sequential-id-replay │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ └── index.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts ├── record │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.ts │ ├── test │ │ └── record.test.ts │ ├── tsconfig.json │ ├── vite.config.ts │ └── vitest.config.ts ├── replay │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.ts │ ├── test │ │ └── replay.test.ts │ ├── tsconfig.json │ ├── vite.config.ts │ └── vitest.config.ts ├── rrdom-nodejs │ ├── .gitignore │ ├── .vscode │ │ ├── extensions.json │ │ └── launch.json │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── document-nodejs.ts │ │ ├── index.ts │ │ └── polyfill.ts │ ├── test │ │ ├── document-nodejs.test.ts │ │ └── polyfill.test.ts │ ├── tsconfig.json │ ├── vite.config.js │ └── vitest.config.ts ├── rrdom │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── diff.ts │ │ ├── document.ts │ │ ├── index.ts │ │ └── style.ts │ ├── test │ │ ├── __snapshots__ │ │ │ └── virtual-dom.test.ts.snap │ │ ├── diff.test.ts │ │ ├── diff │ │ │ └── dialog.test.ts │ │ ├── document.test.ts │ │ ├── html │ │ │ ├── iframe.html │ │ │ ├── main.html │ │ │ └── shadow-dom.html │ │ └── virtual-dom.test.ts │ ├── tsconfig.json │ ├── vite.config.js │ └── vitest.config.ts ├── rrvideo │ ├── CHANGELOG.md │ ├── README.md │ ├── README.zh_CN.md │ ├── demo │ │ └── demo.gif │ ├── jest.config.js │ ├── package.json │ ├── rrvideo.config.example.json │ ├── src │ │ ├── cli.ts │ │ └── index.ts │ ├── test │ │ ├── cli.test.ts │ │ ├── events │ │ │ └── example.ts │ │ └── tsconfig.json │ └── tsconfig.json ├── rrweb-player │ ├── .eslintignore │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── .prettierignore │ ├── .release-it.json │ ├── .svelte-kit │ │ ├── ambient.d.ts │ │ ├── generated │ │ │ └── client │ │ │ │ ├── app.js │ │ │ │ ├── matchers.js │ │ │ │ └── nodes │ │ │ │ ├── 0.js │ │ │ │ └── 1.js │ │ ├── non-ambient.d.ts │ │ └── tsconfig.json │ ├── CHANGELOG.md │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ │ ├── events.js │ │ └── global.css │ ├── src │ │ ├── Controller.svelte │ │ ├── Player.svelte │ │ ├── components │ │ │ └── Switch.svelte │ │ ├── main.ts │ │ ├── types.ts │ │ └── utils.ts │ ├── svelte.config.js │ ├── tsconfig.json │ ├── tsconfig.node.json │ ├── vite-env.d.ts │ └── vite.config.ts ├── rrweb-snapshot │ ├── .gitignore │ ├── .release-it.json │ ├── CHANGELOG.md │ ├── README.md │ ├── jsr.json │ ├── package.json │ ├── src │ │ ├── css.ts │ │ ├── index.ts │ │ ├── rebuild.ts │ │ ├── snapshot.ts │ │ ├── types.ts │ │ └── utils.ts │ ├── test │ │ ├── __snapshots__ │ │ │ └── integration.test.ts.snap │ │ ├── alt-css │ │ │ └── alt-style.css │ │ ├── css.test.ts │ │ ├── css │ │ │ ├── benchmark.css │ │ │ ├── style-with-import.css │ │ │ └── style.css │ │ ├── html │ │ │ ├── about-mozilla.html │ │ │ ├── background-clip-text.html │ │ │ ├── basic.html │ │ │ ├── block-element.html │ │ │ ├── compat-mode.html │ │ │ ├── cors-style-sheet.html │ │ │ ├── dialog.html │ │ │ ├── dynamic-stylesheet.html │ │ │ ├── form-fields.html │ │ │ ├── hover.html │ │ │ ├── iframe-inner.html │ │ │ ├── iframe.html │ │ │ ├── invalid-attribute.html │ │ │ ├── invalid-doctype.html │ │ │ ├── invalid-tagname.html │ │ │ ├── mask-text.html │ │ │ ├── monkey-patched-elements.html │ │ │ ├── picture-blob-in-frame.html │ │ │ ├── picture-blob.html │ │ │ ├── picture-in-frame.html │ │ │ ├── picture-with-inline-onload.html │ │ │ ├── picture.html │ │ │ ├── preload.html │ │ │ ├── shadow-dom.html │ │ │ ├── svg.html │ │ │ ├── video.html │ │ │ ├── with-relative-res.html │ │ │ ├── with-script.html │ │ │ ├── with-style-sheet-with-import.html │ │ │ └── with-style-sheet.html │ │ ├── iframe-html │ │ │ ├── frame1.html │ │ │ ├── frame2.html │ │ │ └── main.html │ │ ├── images │ │ │ ├── compat-bottom.png │ │ │ ├── compat-top-left.png │ │ │ ├── compat-top-right.png │ │ │ ├── robot.png │ │ │ ├── rrweb-favicon-20x20.png │ │ │ └── symbol-defs.svg │ │ ├── integration.test.ts │ │ ├── js │ │ │ └── a.js │ │ ├── rebuild.test.ts │ │ ├── snapshot.test.ts │ │ ├── stringify-stylesheet.bench.ts │ │ ├── utils.test.ts │ │ └── utils.ts │ ├── tsconfig.json │ ├── vite.config.js │ └── vitest.config.ts ├── rrweb │ ├── .gitignore │ ├── .release-it.json │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── rrweb-record │ │ └── package.json │ ├── rrweb-replay │ │ └── package.json │ ├── scripts │ │ ├── repl.js │ │ ├── stream.js │ │ └── utils.js │ ├── src │ │ ├── entries │ │ │ ├── record.ts │ │ │ └── replay.ts │ │ ├── index.ts │ │ ├── record │ │ │ ├── cross-origin-iframe-mirror.ts │ │ │ ├── error-handler.ts │ │ │ ├── iframe-manager.ts │ │ │ ├── index.ts │ │ │ ├── mutation.ts │ │ │ ├── observer.ts │ │ │ ├── observers │ │ │ │ └── canvas │ │ │ │ │ ├── 2d.ts │ │ │ │ │ ├── canvas-manager.ts │ │ │ │ │ ├── canvas.ts │ │ │ │ │ ├── serialize-args.ts │ │ │ │ │ └── webgl.ts │ │ │ ├── processed-node-manager.ts │ │ │ ├── shadow-dom-manager.ts │ │ │ ├── stylesheet-manager.ts │ │ │ └── workers │ │ │ │ ├── image-bitmap-data-url-worker.ts │ │ │ │ └── tsconfig.json │ │ ├── replay │ │ │ ├── canvas │ │ │ │ ├── 2d.ts │ │ │ │ ├── deserialize-args.ts │ │ │ │ ├── index.ts │ │ │ │ └── webgl.ts │ │ │ ├── dialog │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── machine.ts │ │ │ ├── media │ │ │ │ └── index.ts │ │ │ ├── smoothscroll.ts │ │ │ ├── styles │ │ │ │ ├── inject-style.ts │ │ │ │ └── style.css │ │ │ └── timer.ts │ │ ├── types.ts │ │ └── utils.ts │ ├── test │ │ ├── __snapshots__ │ │ │ ├── integration.test.ts.snap │ │ │ ├── record.test.ts.snap │ │ │ └── replayer.test.ts.snap │ │ ├── benchmark │ │ │ ├── dom-mutation.test.ts │ │ │ └── replay-fast-forward.test.ts │ │ ├── e2e │ │ │ ├── __image_snapshots__ │ │ │ │ ├── webgl-test-ts-test-e-2-e-webgl-test-ts-e-2-e-webgl-will-record-and-replay-a-webgl-image-1-snap.png │ │ │ │ └── webgl-test-ts-test-e-2-e-webgl-test-ts-e-2-e-webgl-will-record-and-replay-a-webgl-square-1-snap.png │ │ │ └── webgl.test.ts │ │ ├── events │ │ │ ├── adopted-style-sheet-modification.ts │ │ │ ├── adopted-style-sheet.ts │ │ │ ├── bad-style.ts │ │ │ ├── bad-textarea.ts │ │ │ ├── canvas-in-iframe.ts │ │ │ ├── custom-element-define-class.ts │ │ │ ├── dialog-playback.ts │ │ │ ├── document-replacement.ts │ │ │ ├── hover.ts │ │ │ ├── iframe-shadowdom-hover.ts │ │ │ ├── iframe.ts │ │ │ ├── input.ts │ │ │ ├── ordering.ts │ │ │ ├── scroll-with-parent-styles.ts │ │ │ ├── scroll.ts │ │ │ ├── selection.ts │ │ │ ├── shadow-dom.ts │ │ │ ├── style-sheet-rule-events.ts │ │ │ ├── style-sheet-text-mutation.ts │ │ │ ├── video-playback-on-full-snapshot.ts │ │ │ ├── video-playback.ts │ │ │ └── webgl.ts │ │ ├── html │ │ │ ├── assets │ │ │ │ ├── 1-minute-of-silence.mp3 │ │ │ │ ├── bunny-video.webm │ │ │ │ ├── robot.png │ │ │ │ ├── style.css │ │ │ │ └── webgl-utils.js │ │ │ ├── audio.html │ │ │ ├── benchmark-dom-mutation-add-and-move.html │ │ │ ├── benchmark-dom-mutation-add-and-remove.html │ │ │ ├── benchmark-dom-mutation-attributes.html │ │ │ ├── benchmark-dom-mutation-deep-nested.html │ │ │ ├── benchmark-dom-mutation-multiple-descendant-add.html │ │ │ ├── benchmark-dom-mutation.html │ │ │ ├── blank.html │ │ │ ├── block.html │ │ │ ├── blocked-unblocked.html │ │ │ ├── canvas-webgl-image.html │ │ │ ├── canvas-webgl-shader.html │ │ │ ├── canvas-webgl-square.html │ │ │ ├── canvas-webgl.html │ │ │ ├── canvas.html │ │ │ ├── dialog.html │ │ │ ├── empty.html │ │ │ ├── form.html │ │ │ ├── frame-image-blob-url.html │ │ │ ├── frame1.html │ │ │ ├── frame2.html │ │ │ ├── hello-world.html │ │ │ ├── ignore.html │ │ │ ├── image-blob-url.html │ │ │ ├── link.html │ │ │ ├── main.html │ │ │ ├── mask-text.html │ │ │ ├── move-node.html │ │ │ ├── mutation-observer.html │ │ │ ├── password.html │ │ │ ├── polyfilled-shadowdom-mutation.html │ │ │ ├── react-styled-components.html │ │ │ ├── select2.html │ │ │ ├── shadow-dom.html │ │ │ ├── shuffle.html │ │ │ ├── style.html │ │ │ └── video.html │ │ ├── integration.test.ts │ │ ├── machine.test.ts │ │ ├── record.test.ts │ │ ├── record │ │ │ ├── __snapshots__ │ │ │ │ ├── cross-origin-iframes.test.ts.snap │ │ │ │ ├── cross-origin-iframes.test.ts.snap.extra │ │ │ │ ├── dialog.test.ts.snap │ │ │ │ └── webgl.test.ts.snap │ │ │ ├── cross-origin-iframes.test.ts │ │ │ ├── dialog.test.ts │ │ │ ├── error-handler.test.ts │ │ │ ├── serialize-args.test.ts │ │ │ └── webgl.test.ts │ │ ├── replay │ │ │ ├── 2d-mutation.test.ts │ │ │ ├── __image_snapshots__ │ │ │ │ ├── dialog-test-ts-test-replay-dialog-test-ts-dialog-closed-dialogs-show-nothing-1-snap.png │ │ │ │ ├── dialog-test-ts-test-replay-dialog-test-ts-dialog-should-add-an-opened-dialog-with-show-modal-in-incremental-snapshot-alternative.png │ │ │ │ ├── dialog-test-ts-test-replay-dialog-test-ts-dialog-should-add-an-opened-dialog-with-show-modal-in-incremental-snapshot.png │ │ │ │ ├── dialog-test-ts-test-replay-dialog-test-ts-dialog-should-close-dialog-again-when-open-attribute-gets-removed.png │ │ │ │ ├── dialog-test-ts-test-replay-dialog-test-ts-dialog-should-open-dialog-with-show-in-full-snapshot.png │ │ │ │ ├── dialog-test-ts-test-replay-dialog-test-ts-dialog-should-open-dialog-with-show-modal-in-full-snapshot.png │ │ │ │ ├── dialog-test-ts-test-replay-dialog-test-ts-dialog-should-open-dialog-with-show-modal.png │ │ │ │ ├── dialog-test-ts-test-replay-dialog-test-ts-dialog-should-switch-between-show-and-show-modal.png │ │ │ │ ├── dialog-test-ts-test-replay-dialog-test-ts-dialog-should-switch-between-show-modal-and-show.png │ │ │ │ ├── dialog-test-ts-test-replay-dialog-test-ts-dialog-show-the-dialog-when-open-attribute-gets-added.png │ │ │ │ ├── hover-test-ts-test-replay-hover-test-ts-replayer-hover-should-trigger-hover-on-mouse-down-1-snap.png │ │ │ │ ├── video-test-ts-test-replay-video-test-ts-video-will-be-paused-when-the-player-wasnt-started-yet-1-snap.png │ │ │ │ ├── video-test-ts-test-replay-video-test-ts-video-will-play-from-the-correct-moment-1-snap.png │ │ │ │ ├── video-test-ts-test-replay-video-test-ts-video-will-seek-to-the-correct-moment-1-snap.png │ │ │ │ ├── video-test-ts-test-replay-video-test-ts-video-will-seek-to-the-correct-moment-without-media-interaction-events-1-snap.png │ │ │ │ └── webgl-test-ts-test-replay-webgl-test-ts-replayer-webgl-should-output-simple-webgl-object-1-snap.png │ │ │ ├── deserialize-args.test.ts │ │ │ ├── dialog.test.ts │ │ │ ├── hover.test.ts │ │ │ ├── preload-all-images.test.ts │ │ │ ├── video.test.ts │ │ │ ├── webgl-mutation.test.ts │ │ │ └── webgl.test.ts │ │ ├── replayer.test.ts │ │ ├── rrdom.test.ts │ │ ├── util.test.ts │ │ └── utils.ts │ ├── tsconfig.json │ ├── vite.config.entries.js │ ├── vite.config.js │ └── vitest.config.ts ├── types │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.ts │ ├── tsconfig.json │ └── vite.config.js ├── utils │ ├── CHANGELOG.md │ ├── Readme.md │ ├── package.json │ ├── src │ │ └── index.ts │ ├── tsconfig.json │ └── vite.config.js └── web-extension │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ ├── background │ │ └── index.ts │ ├── components │ │ ├── CircleButton.tsx │ │ └── SidebarWithHeader.tsx │ ├── content │ │ ├── index.ts │ │ └── inject.ts │ ├── manifest.json │ ├── options │ │ ├── App.tsx │ │ ├── index.html │ │ └── index.tsx │ ├── pages │ │ ├── App.tsx │ │ ├── Player.tsx │ │ ├── SessionList.tsx │ │ ├── index.html │ │ └── index.tsx │ ├── popup │ │ ├── App.tsx │ │ ├── Timer.tsx │ │ ├── index.tsx │ │ └── popup.html │ ├── public │ │ ├── icon128.png │ │ ├── icon16.png │ │ └── icon48.png │ ├── types.ts │ └── utils │ │ ├── channel.ts │ │ ├── index.ts │ │ └── storage.ts │ ├── tsconfig.json │ └── vite.config.ts ├── scripts └── lint-packages.sh ├── tsconfig.base.json ├── tsconfig.eslint.json ├── tsconfig.json ├── turbo.json ├── vite.config.default.ts ├── vitest.config.ts ├── vitest.workspace.ts └── yarn.lock /.cache/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/.cache/.gitkeep -------------------------------------------------------------------------------- /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/angry-turtles-provide.md: -------------------------------------------------------------------------------- 1 | --- 2 | "rrweb-snapshot": patch 3 | --- 4 | 5 | Handle exceptions thrown from postcss when calling adaptCssForReplay 6 | -------------------------------------------------------------------------------- /.changeset/attribute-text-reductions.md: -------------------------------------------------------------------------------- 1 | --- 2 | 'rrweb': patch 3 | --- 4 | 5 | Don't include redundant data from text/attribute mutations on just-added nodes 6 | -------------------------------------------------------------------------------- /.changeset/beige-olives-roll.md: -------------------------------------------------------------------------------- 1 | --- 2 | "rrweb-snapshot": patch 3 | "rrweb": patch 4 | --- 5 | 6 | Fix that the optional `maskInputFn` was being accidentally ignored during the creation of the full snapshot 7 | -------------------------------------------------------------------------------- /.changeset/blank-cherries-laugh.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | -------------------------------------------------------------------------------- /.changeset/blank-dev-changset.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | -------------------------------------------------------------------------------- /.changeset/brave-numbers-joke.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | -------------------------------------------------------------------------------- /.changeset/breezy-cats-heal.md: -------------------------------------------------------------------------------- 1 | --- 2 | 'rrweb': patch 3 | --- 4 | 5 | fix: createImageBitmap throws DOMException if source is 0 width or height 6 | -------------------------------------------------------------------------------- /.changeset/breezy-mice-breathe.md: -------------------------------------------------------------------------------- 1 | --- 2 | 'rrweb': patch 3 | --- 4 | 5 | safely capture BigInt values with the console log plugin" 6 | -------------------------------------------------------------------------------- /.changeset/bright-socks-clap.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | -------------------------------------------------------------------------------- /.changeset/calm-bulldogs-speak.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | -------------------------------------------------------------------------------- /.changeset/calm-oranges-sin.md: -------------------------------------------------------------------------------- 1 | --- 2 | 'rrweb': patch 3 | --- 4 | 5 | fix: Fix checking for `patchTarget` in `initAdoptedStyleSheetObserver` 6 | -------------------------------------------------------------------------------- /.changeset/chatty-cherries-train.md: -------------------------------------------------------------------------------- 1 | --- 2 | 'rrweb': patch 3 | --- 4 | 5 | Fix the statement which is getting changed by Microbundle 6 | -------------------------------------------------------------------------------- /.changeset/chilled-penguins-sin.md: -------------------------------------------------------------------------------- 1 | --- 2 | "rrdom": patch 3 | --- 4 | 5 | Ignore invalid DOM attributes when diffing 6 | -------------------------------------------------------------------------------- /.changeset/clean-plants-play.md: -------------------------------------------------------------------------------- 1 | --- 2 | 'rrweb': patch 3 | '@rrweb/types': patch 4 | --- 5 | 6 | Compact style mutation fixes and improvements 7 | 8 | - fixes when style updates contain a 'var()' on a shorthand property #1246 9 | - further ensures that style mutations are compact by reverting to string method if it is shorter 10 | -------------------------------------------------------------------------------- /.changeset/clean-shrimps-lay.md: -------------------------------------------------------------------------------- 1 | --- 2 | 'rrweb': patch 3 | --- 4 | 5 | feat: Add `ignoreSelector` option 6 | 7 | Similar to ignoreClass, but accepts a CSS selector so that you can use any CSS selector. 8 | -------------------------------------------------------------------------------- /.changeset/cold-eyes-hunt.md: -------------------------------------------------------------------------------- 1 | --- 2 | 'rrdom': patch 3 | --- 4 | 5 | Fix: rrdom bugs 6 | 7 | 1. Fix a bug in the diff algorithm. 8 | 2. Omit the 'srcdoc' attribute of iframes to avoid overwriting content. 9 | -------------------------------------------------------------------------------- /.changeset/cold-hounds-teach.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json", 3 | "changelog": ["@changesets/changelog-github", { "repo": "rrweb-io/rrweb" }], 4 | "commit": false, 5 | "fixed": [ 6 | [ 7 | "rrweb", 8 | "rrweb-snapshot", 9 | "rrdom", 10 | "rrdom-nodejs", 11 | "rrweb-player", 12 | "@rrweb/all", 13 | "@rrweb/replay", 14 | "@rrweb/record", 15 | "@rrweb/types", 16 | "@rrweb/packer", 17 | "@rrweb/utils", 18 | "@rrweb/web-extension", 19 | "rrvideo", 20 | "@rrweb/rrweb-plugin-console-record", 21 | "@rrweb/rrweb-plugin-console-replay", 22 | "@rrweb/rrweb-plugin-sequential-id-record", 23 | "@rrweb/rrweb-plugin-sequential-id-replay", 24 | "@rrweb/rrweb-plugin-canvas-webrtc-record", 25 | "@rrweb/rrweb-plugin-canvas-webrtc-replay" 26 | ] 27 | ], 28 | "linked": [], 29 | "access": "public", 30 | "baseBranch": "master", 31 | "updateInternalDependencies": "patch", 32 | "ignore": [] 33 | } 34 | -------------------------------------------------------------------------------- /.changeset/controller-finish-flag.md: -------------------------------------------------------------------------------- 1 | --- 2 | 'rrweb-player': patch 3 | 'rrweb': patch 4 | --- 5 | 6 | Reset the finished flag in Controller `goto` instead of `handleProgressClick` so that it is properly handled if `goto` is called directly. 7 | -------------------------------------------------------------------------------- /.changeset/cool-grapes-hug.md: -------------------------------------------------------------------------------- 1 | --- 2 | 'rrdom': patch 3 | --- 4 | 5 | Support `loop` in `RRMediaElement` 6 | -------------------------------------------------------------------------------- /.changeset/cool-horses-bow.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@rrweb/rrweb-plugin-canvas-webrtc-record": patch 3 | "@rrweb/rrweb-plugin-canvas-webrtc-replay": patch 4 | "@rrweb/rrweb-plugin-sequential-id-record": patch 5 | "@rrweb/rrweb-plugin-sequential-id-replay": patch 6 | "@rrweb/rrweb-plugin-console-record": patch 7 | "@rrweb/rrweb-plugin-console-replay": patch 8 | "@rrweb/packer": patch 9 | "@rrweb/record": patch 10 | "@rrweb/replay": patch 11 | "@rrweb/all": patch 12 | --- 13 | 14 | Keep package version in sync with other packages 15 | -------------------------------------------------------------------------------- /.changeset/cuddly-bikes-fail.md: -------------------------------------------------------------------------------- 1 | --- 2 | "rrweb-snapshot": patch 3 | "rrweb": patch 4 | --- 5 | 6 | fix: duplicate textContent for style elements cause incremental style mutations to be invalid 7 | -------------------------------------------------------------------------------- /.changeset/cuddly-readers-warn.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | -------------------------------------------------------------------------------- /.changeset/curvy-apples-lay.md: -------------------------------------------------------------------------------- 1 | --- 2 | 'rrweb-snapshot': patch 3 | 'rrweb': patch 4 | --- 5 | 6 | Extend to run fixBrowserCompatibilityIssuesInCSS over inline stylesheets 7 | -------------------------------------------------------------------------------- /.changeset/curvy-balloons-brake.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | -------------------------------------------------------------------------------- /.changeset/date-now-guard.md: -------------------------------------------------------------------------------- 1 | --- 2 | 'rrweb': patch 3 | --- 4 | 5 | Guard against presence of older 3rd party javascript libraries which redefine Date.now() 6 | -------------------------------------------------------------------------------- /.changeset/dirty-pets-fly.md: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | -------------------------------------------------------------------------------- /.changeset/dirty-rules-dress.md: -------------------------------------------------------------------------------- 1 | --- 2 | 'rrweb-snapshot': minor 3 | --- 4 | 5 | Video and Audio elements now also capture `playbackRate`, `muted`, `loop`, `volume`. 6 | -------------------------------------------------------------------------------- /.changeset/efficiently-splitCssText-1603.md: -------------------------------------------------------------------------------- 1 | --- 2 | "rrweb-snapshot": patch 3 | "rrweb": patch 4 | --- 5 | 6 | Improve performance of splitCssText for 24 | 25 | 26 |

This is a h1 heading

27 |

This is a h1 heading with styles

28 |
29 |
30 | Text 1 31 |
32 |

This is a paragraph

33 | 34 |
35 | Text 2 36 |
37 | This is an image 38 | 39 |
40 | 41 |
42 |
43 | 44 | 45 | -------------------------------------------------------------------------------- /packages/rrdom/test/html/shadow-dom.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | shadow dom 7 | 8 | 9 |
10 | 18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /packages/rrdom/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "include": ["src"], 4 | "compilerOptions": { 5 | "rootDir": "src", 6 | "tsBuildInfoFile": "./tsconfig.tsbuildinfo" 7 | }, 8 | "references": [ 9 | { 10 | "path": "../rrweb-snapshot" 11 | }, 12 | { 13 | "path": "../types" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /packages/rrdom/vite.config.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import config from '../../vite.config.default'; 3 | 4 | export default config(path.resolve(__dirname, 'src/index.ts'), 'rrdom'); 5 | -------------------------------------------------------------------------------- /packages/rrdom/vitest.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineProject, mergeConfig } from 'vitest/config'; 3 | import configShared from '../../vitest.config'; 4 | 5 | export default mergeConfig( 6 | configShared, 7 | defineProject({ 8 | test: { 9 | globals: true, 10 | }, 11 | }), 12 | ); 13 | -------------------------------------------------------------------------------- /packages/rrvideo/demo/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrvideo/demo/demo.gif -------------------------------------------------------------------------------- /packages/rrvideo/jest.config.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line tsdoc/syntax 2 | /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ 3 | module.exports = { 4 | preset: 'ts-jest', 5 | testEnvironment: 'node', 6 | }; 7 | -------------------------------------------------------------------------------- /packages/rrvideo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rrvideo", 3 | "version": "2.0.0-alpha.18", 4 | "description": "transform rrweb session into video", 5 | "main": "build/index.js", 6 | "bin": { 7 | "rrvideo": "build/cli.js" 8 | }, 9 | "files": [ 10 | "build", 11 | "package.json" 12 | ], 13 | "types": "build/index.d.ts", 14 | "scripts": { 15 | "install": "playwright install", 16 | "build": "tsc", 17 | "test": "jest", 18 | "check-types": "tsc -noEmit", 19 | "prepublish": "yarn build" 20 | }, 21 | "author": "yanzhen@smartx.com", 22 | "license": "MIT", 23 | "devDependencies": { 24 | "@types/fs-extra": "11.0.1", 25 | "@types/jest": "^27.4.1", 26 | "@types/minimist": "^1.2.1", 27 | "@types/node": "^18.15.11", 28 | "jest": "^27.5.1", 29 | "ts-jest": "^27.1.3", 30 | "@rrweb/types": "^2.0.0-alpha.18" 31 | }, 32 | "dependencies": { 33 | "@open-tech-world/cli-progress-bar": "^2.0.2", 34 | "fs-extra": "^11.1.1", 35 | "minimist": "^1.2.5", 36 | "playwright": "^1.32.1", 37 | "rrweb-player": "^2.0.0-alpha.18" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/rrvideo/rrvideo.config.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "width": 1400, 3 | "height": 900, 4 | "speed": 4, 5 | "skipInactive": true, 6 | "mouseTail": { 7 | "strokeStyle": "green", 8 | "lineWidth": 2 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/rrvideo/src/cli.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import * as fs from 'fs'; 3 | import * as path from 'path'; 4 | import minimist from 'minimist'; 5 | import { ProgressBar } from '@open-tech-world/cli-progress-bar'; 6 | import type Player from 'rrweb-player'; 7 | import { transformToVideo } from './index'; 8 | 9 | const argv = minimist(process.argv.slice(2)); 10 | 11 | if (!argv.input) { 12 | throw new Error('please pass --input to your rrweb events file'); 13 | } 14 | 15 | let config = {}; 16 | 17 | if (argv.config) { 18 | const configPathStr = argv.config as string; 19 | const configPath = path.isAbsolute(configPathStr) 20 | ? configPathStr 21 | : path.resolve(process.cwd(), configPathStr); 22 | config = JSON.parse(fs.readFileSync(configPath, 'utf-8')) as Omit< 23 | ConstructorParameters[0]['props'], 24 | 'events' 25 | >; 26 | } 27 | 28 | const pBar = new ProgressBar({ prefix: 'Transforming' }); 29 | const onProgressUpdate = (percent: number) => { 30 | if (percent < 1) pBar.run({ value: percent * 100, total: 100 }); 31 | else 32 | pBar.run({ value: 100, total: 100, prefix: 'Transformation Completed!' }); 33 | }; 34 | 35 | transformToVideo({ 36 | input: argv.input as string, 37 | output: argv.output as string, 38 | rrwebPlayer: config, 39 | onProgressUpdate, 40 | }) 41 | .then((file) => { 42 | console.log(`Successfully transformed into "${file}".`); 43 | }) 44 | .catch((error) => { 45 | console.log('Failed to transform this session.'); 46 | console.error(error); 47 | process.exit(1); 48 | }); 49 | -------------------------------------------------------------------------------- /packages/rrvideo/test/cli.test.ts: -------------------------------------------------------------------------------- 1 | import { execSync } from 'child_process'; 2 | import * as fs from 'fs-extra'; 3 | import * as path from 'path'; 4 | import exampleEvents from './events/example'; 5 | 6 | describe('should be able to run cli', () => { 7 | beforeAll(() => { 8 | fs.mkdirSync(path.resolve(__dirname, './generated')); 9 | fs.writeJsonSync( 10 | path.resolve(__dirname, './generated/example.json'), 11 | exampleEvents, 12 | { 13 | spaces: 2, 14 | }, 15 | ); 16 | }); 17 | afterAll(async () => { 18 | await fs.remove(path.resolve(__dirname, './generated')); 19 | }); 20 | 21 | it('should throw error without input path', () => { 22 | expect(() => { 23 | execSync('node ./build/cli.js', { stdio: 'pipe' }); 24 | }).toThrowError(/.*please pass --input to your rrweb events file.*/); 25 | }); 26 | 27 | it('should generate a video without output path', () => { 28 | execSync('node ./build/cli.js --input ./test/generated/example.json', { 29 | stdio: 'pipe', 30 | }); 31 | const outputFile = path.resolve(__dirname, '../rrvideo-output.webm'); 32 | expect(fs.existsSync(outputFile)).toBe(true); 33 | fs.removeSync(outputFile); 34 | }); 35 | 36 | it('should generate a video with specific output path', () => { 37 | const outputFile = path.resolve(__dirname, './generated/output.webm'); 38 | execSync( 39 | `node ./build/cli.js --input ./test/generated/example.json --output ${outputFile}`, 40 | { stdio: 'pipe' }, 41 | ); 42 | expect(fs.existsSync(outputFile)).toBe(true); 43 | fs.removeSync(outputFile); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /packages/rrvideo/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": {} 3 | } 4 | -------------------------------------------------------------------------------- /packages/rrvideo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "target": "ES6", 5 | "module": "commonjs", 6 | "declaration": true, 7 | "sourceMap": true, 8 | "outDir": "./build", 9 | "rootDir": "./src", 10 | "strictNullChecks": true, 11 | "noImplicitAny": true, 12 | "strictBindCallApply": true, 13 | "noUnusedLocals": true, 14 | "noUnusedParameters": true, 15 | "esModuleInterop": true, 16 | "skipLibCheck": true, 17 | "forceConsistentCasingInFileNames": true 18 | }, 19 | "exclude": ["build", "node_modules", "test"], 20 | "references": [ 21 | { 22 | "path": "../rrweb-player" 23 | }, 24 | { 25 | "path": "../types" 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /packages/rrweb-player/.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | types 3 | vite.config.ts 4 | vite-env.d.ts 5 | svelte.config.js 6 | public/events.js 7 | src/**/*.d.ts -------------------------------------------------------------------------------- /packages/rrweb-player/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | /** @type { import("eslint").Linter.Config } */ 2 | module.exports = { 3 | root: true, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:@typescript-eslint/recommended', 7 | 'plugin:svelte/recommended', 8 | '../../.eslintrc.js', 9 | ], 10 | parser: '@typescript-eslint/parser', 11 | plugins: ['@typescript-eslint'], 12 | parserOptions: { 13 | sourceType: 'module', 14 | ecmaVersion: 2020, 15 | extraFileExtensions: ['.svelte'], 16 | }, 17 | env: { 18 | browser: true, 19 | es2017: true, 20 | node: true, 21 | }, 22 | overrides: [ 23 | { 24 | files: ['*.svelte'], 25 | parser: 'svelte-eslint-parser', 26 | parserOptions: { 27 | parser: '@typescript-eslint/parser', 28 | }, 29 | }, 30 | ], 31 | }; 32 | -------------------------------------------------------------------------------- /packages/rrweb-player/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | package-lock.json 4 | yarn.lock 5 | 6 | .vscode 7 | temp 8 | 9 | dist 10 | 11 | *.log 12 | 13 | # Svelte definitions are generated by vite 14 | src/**/*.svelte.d.ts 15 | types -------------------------------------------------------------------------------- /packages/rrweb-player/.prettierignore: -------------------------------------------------------------------------------- 1 | # files generated by svelte-kit 2 | .svelte-kit/generated/* 3 | .svelte-kit/ambient.d.ts 4 | .svelte-kit/non-ambient.d.ts 5 | -------------------------------------------------------------------------------- /packages/rrweb-player/.release-it.json: -------------------------------------------------------------------------------- 1 | { 2 | "non-interactive": false, 3 | "buildCommand": "npm run build", 4 | "requireCleanWorkingDir": false 5 | } 6 | -------------------------------------------------------------------------------- /packages/rrweb-player/.svelte-kit/generated/client/app.js: -------------------------------------------------------------------------------- 1 | export { matchers } from './matchers.js'; 2 | 3 | export const nodes = [ 4 | () => import('./nodes/0'), 5 | () => import('./nodes/1') 6 | ]; 7 | 8 | export const server_loads = []; 9 | 10 | export const dictionary = { 11 | 12 | }; 13 | 14 | export const hooks = { 15 | handleError: (({ error }) => { console.error(error) }), 16 | 17 | reroute: (() => {}) 18 | }; 19 | 20 | export { default as root } from '../root.svelte'; -------------------------------------------------------------------------------- /packages/rrweb-player/.svelte-kit/generated/client/matchers.js: -------------------------------------------------------------------------------- 1 | export const matchers = {}; -------------------------------------------------------------------------------- /packages/rrweb-player/.svelte-kit/generated/client/nodes/0.js: -------------------------------------------------------------------------------- 1 | export { default as component } from "../../../../../../node_modules/@sveltejs/kit/src/runtime/components/layout.svelte"; -------------------------------------------------------------------------------- /packages/rrweb-player/.svelte-kit/generated/client/nodes/1.js: -------------------------------------------------------------------------------- 1 | export { default as component } from "../../../../../../node_modules/@sveltejs/kit/src/runtime/components/error.svelte"; -------------------------------------------------------------------------------- /packages/rrweb-player/.svelte-kit/non-ambient.d.ts: -------------------------------------------------------------------------------- 1 | 2 | // this file is generated — do not edit it 3 | 4 | 5 | declare module "svelte/elements" { 6 | export interface HTMLAttributes { 7 | 'data-sveltekit-keepfocus'?: true | '' | 'off' | undefined | null; 8 | 'data-sveltekit-noscroll'?: true | '' | 'off' | undefined | null; 9 | 'data-sveltekit-preload-code'?: 10 | | true 11 | | '' 12 | | 'eager' 13 | | 'viewport' 14 | | 'hover' 15 | | 'tap' 16 | | 'off' 17 | | undefined 18 | | null; 19 | 'data-sveltekit-preload-data'?: true | '' | 'hover' | 'tap' | 'off' | undefined | null; 20 | 'data-sveltekit-reload'?: true | '' | 'off' | undefined | null; 21 | 'data-sveltekit-replacestate'?: true | '' | 'off' | undefined | null; 22 | } 23 | } 24 | 25 | export {}; 26 | -------------------------------------------------------------------------------- /packages/rrweb-player/.svelte-kit/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": {}, 4 | "rootDirs": [ 5 | "..", 6 | "./types" 7 | ], 8 | "verbatimModuleSyntax": true, 9 | "isolatedModules": true, 10 | "lib": [ 11 | "esnext", 12 | "DOM", 13 | "DOM.Iterable" 14 | ], 15 | "moduleResolution": "bundler", 16 | "module": "esnext", 17 | "noEmit": true, 18 | "target": "esnext" 19 | }, 20 | "include": [ 21 | "ambient.d.ts", 22 | "non-ambient.d.ts", 23 | "./types/**/$types.d.ts", 24 | "../vite.config.js", 25 | "../vite.config.ts", 26 | "../src/**/*.js", 27 | "../src/**/*.ts", 28 | "../src/**/*.svelte", 29 | "../tests/**/*.js", 30 | "../tests/**/*.ts", 31 | "../tests/**/*.svelte" 32 | ], 33 | "exclude": [ 34 | "../node_modules/**", 35 | "../src/service-worker.js", 36 | "../src/service-worker.ts", 37 | "../src/service-worker.d.ts" 38 | ] 39 | } -------------------------------------------------------------------------------- /packages/rrweb-player/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Svelte app 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 36 | 37 | -------------------------------------------------------------------------------- /packages/rrweb-player/public/global.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | position: relative; 4 | width: 100%; 5 | height: 100%; 6 | } 7 | 8 | body { 9 | box-sizing: border-box; 10 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 11 | Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif; 12 | } 13 | -------------------------------------------------------------------------------- /packages/rrweb-player/src/main.ts: -------------------------------------------------------------------------------- 1 | import _Player from './Player.svelte'; 2 | import type { RRwebPlayerOptions } from './types'; 3 | export class Player extends _Player { 4 | constructor( 5 | options: { 6 | // for compatibility 7 | data?: RRwebPlayerOptions['props']; 8 | } & RRwebPlayerOptions, 9 | ) { 10 | super({ 11 | target: options.target, 12 | props: options.data || options.props, 13 | }); 14 | } 15 | } 16 | 17 | export default Player; 18 | -------------------------------------------------------------------------------- /packages/rrweb-player/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-auto'; 2 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors 7 | // for more information about preprocessors 8 | preprocess: vitePreprocess(), 9 | 10 | kit: { 11 | // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. 12 | // If your environment is not supported or you settled on a specific environment, switch out the adapter. 13 | // See https://kit.svelte.dev/docs/adapters for more information about adapters. 14 | adapter: adapter(), 15 | }, 16 | }; 17 | 18 | export default config; 19 | -------------------------------------------------------------------------------- /packages/rrweb-player/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "exclude": ["package.json", "vite.config.ts"], 4 | "include": ["src/**/*", "vite-env.d.ts"], 5 | "compilerOptions": { 6 | "composite": true, 7 | "rootDir": "./src", 8 | // defaults for svelte 9 | "useDefineForClassFields": true, 10 | "resolveJsonModule": true, 11 | /** 12 | * Typecheck JS in `.svelte` and `.js` files by default. 13 | * Disable checkJs if you'd like to use dynamic types in JS. 14 | * Note that setting allowJs false does not prevent the use 15 | * of JS in `.svelte` files. 16 | */ 17 | "allowJs": true, 18 | "checkJs": true 19 | }, 20 | "references": [ 21 | { 22 | "path": "../replay" 23 | }, 24 | { 25 | "path": "../packer" 26 | }, 27 | { 28 | "path": "../types" 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /packages/rrweb-player/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "strict": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/rrweb-player/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | node_modules 3 | package-lock.json 4 | build 5 | dist 6 | es 7 | lib 8 | temp 9 | typings 10 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/.release-it.json: -------------------------------------------------------------------------------- 1 | { 2 | "non-interactive": true, 3 | "hooks": { 4 | "before:init": ["npm run bundle", "npm run typings"] 5 | }, 6 | "git": { 7 | "requireCleanWorkingDir": false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rrweb/snapshot", 3 | "version": "2.0.0-alpha.14", 4 | "exports": "./src/index.ts" 5 | } 6 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/src/css.ts: -------------------------------------------------------------------------------- 1 | import type { AcceptedPlugin, Rule } from 'postcss'; 2 | 3 | const MEDIA_SELECTOR = /(max|min)-device-(width|height)/; 4 | const MEDIA_SELECTOR_GLOBAL = new RegExp(MEDIA_SELECTOR.source, 'g'); 5 | 6 | const mediaSelectorPlugin: AcceptedPlugin = { 7 | postcssPlugin: 'postcss-custom-selectors', 8 | prepare() { 9 | return { 10 | postcssPlugin: 'postcss-custom-selectors', 11 | AtRule: function (atrule) { 12 | if (atrule.params.match(MEDIA_SELECTOR_GLOBAL)) { 13 | atrule.params = atrule.params.replace(MEDIA_SELECTOR_GLOBAL, '$1-$2'); 14 | } 15 | }, 16 | }; 17 | }, 18 | }; 19 | 20 | // Simplified from https://github.com/giuseppeg/postcss-pseudo-classes/blob/master/index.js 21 | const pseudoClassPlugin: AcceptedPlugin = { 22 | postcssPlugin: 'postcss-hover-classes', 23 | prepare: function () { 24 | const fixed: Rule[] = []; 25 | return { 26 | Rule: function (rule) { 27 | if (fixed.indexOf(rule) !== -1) { 28 | return; 29 | } 30 | fixed.push(rule); 31 | rule.selectors.forEach(function (selector) { 32 | if (selector.includes(':hover')) { 33 | rule.selector += ',\n' + selector.replace(/:hover/g, '.\\:hover'); 34 | } 35 | }); 36 | }, 37 | }; 38 | }, 39 | }; 40 | 41 | export { mediaSelectorPlugin, pseudoClassPlugin }; 42 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/src/index.ts: -------------------------------------------------------------------------------- 1 | import snapshot, { 2 | serializeNodeWithId, 3 | transformAttribute, 4 | ignoreAttribute, 5 | visitSnapshot, 6 | cleanupSnapshot, 7 | needMaskingText, 8 | classMatchesRegex, 9 | IGNORED_NODE, 10 | genId, 11 | } from './snapshot'; 12 | import rebuild, { 13 | buildNodeWithSN, 14 | adaptCssForReplay, 15 | createCache, 16 | } from './rebuild'; 17 | export * from './types'; 18 | export * from './utils'; 19 | 20 | export { 21 | snapshot, 22 | serializeNodeWithId, 23 | rebuild, 24 | buildNodeWithSN, 25 | adaptCssForReplay, 26 | createCache, 27 | transformAttribute, 28 | ignoreAttribute, 29 | visitSnapshot, 30 | cleanupSnapshot, 31 | needMaskingText, 32 | classMatchesRegex, 33 | IGNORED_NODE, 34 | genId, 35 | }; 36 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/alt-css/alt-style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | background: url('../should-be-in-root-folder.jpg'); 4 | border-image: url('data:image/svg+xml;utf8,'); 5 | } 6 | p { 7 | color: red; 8 | background: url('./should-be-in-alt-css-folder.jpg'); 9 | } 10 | body > p { 11 | color: yellow; 12 | } 13 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/css/style-with-import.css: -------------------------------------------------------------------------------- 1 | @import '//fonts.googleapis.com/css2?family=Open+Sans:wght@400;600;700&family=Roboto:wght@100;300;400;500;700&display=swap"'; 2 | @import './style.css'; 3 | @import '../alt-css/alt-style.css'; 4 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | background: url('../should-be-in-root-folder.jpg'); 4 | border-image: url('data:image/svg+xml;utf8,'); 5 | } 6 | p { 7 | color: red; 8 | background: url('./should-be-in-css-folder.jpg'); 9 | } 10 | body > p { 11 | color: yellow; 12 | } 13 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/about-mozilla.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | The Book of Mozilla, 11:9 6 | 37 | 38 | 39 | 40 | 41 |

42 | Mammon slept. And the beast reborn spread over the earth and its numbers 43 | grew legion. And they proclaimed the times and sacrificed crops unto the 44 | fire, with the cunning of foxes. And they built a new world in their own 45 | image as promised by the 46 | sacred words, and spoke 47 | of the beast with their children. Mammon awoke, and lo! it was 48 | naught but a follower. 49 |

50 | 51 |

52 | from The Book of Mozilla, 11:9
(10th Edition) 53 |

54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/background-clip-text.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 |

The background is clipped to the foreground text.

12 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/basic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Document 9 | 10 | 11 | 12 |

Title

13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/block-element.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 19 | 20 | 21 | 22 |
block 1
23 |
record 2
24 |
block 3
25 |
block 3
26 | 27 | 28 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/compat-mode.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Compat Mode; image resizing 5 | 6 | 7 |
8 | 9 | 10 | 11 |
12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/cors-style-sheet.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | with style sheet 8 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/dialog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | I'm a dialog 4 | 5 | 6 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/dynamic-stylesheet.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | dynamic stylesheet 8 | 9 | 16 | 17 | 18 |

p tag

19 | 20 | 21 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/form-fields.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | form fields 8 | 9 | 10 | 11 |
12 | 15 | 18 | 21 | 25 | 31 | 34 |
35 | 36 | 44 | 45 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/hover.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | hover selector 9 | 25 | 26 | 27 | 28 |
hover me
29 | 30 | 31 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/iframe-inner.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/iframe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | iframe 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/invalid-attribute.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/invalid-doctype.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Invalid Doctype 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/invalid-tagname.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | Hello 11 | Hello 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/mask-text.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 |

mask 1

12 |
13 | mask 2 14 |
15 |
mask 3
16 | 17 | 18 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/monkey-patched-elements.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 36 | 37 | 38 |
    39 |
  • a
  • 40 |
  • b
  • 41 |
  • c
  • 42 |
  • d
  • 43 |
44 | 45 | 46 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/picture-blob-in-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/picture-blob.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | This is a robot 4 | 5 | 16 | 17 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/picture-in-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/picture-with-inline-onload.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | This is a robot 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/picture.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | This is a robot 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/preload.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/video.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | video 8 | 9 | 10 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/with-relative-res.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | Hello 12 | Hello 13 | Hello 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/with-script.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | with script 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/with-style-sheet-with-import.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | with style sheet with import 9 | 10 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/html/with-style-sheet.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | with style sheet 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/iframe-html/frame1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Frame 1 7 | 8 | 9 | frame 1 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/iframe-html/frame2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Frame 2 7 | 8 | 9 | frame 2 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/iframe-html/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Main 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/images/compat-bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb-snapshot/test/images/compat-bottom.png -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/images/compat-top-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb-snapshot/test/images/compat-top-left.png -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/images/compat-top-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb-snapshot/test/images/compat-top-right.png -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/images/robot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb-snapshot/test/images/robot.png -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/images/rrweb-favicon-20x20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb-snapshot/test/images/rrweb-favicon-20x20.png -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/js/a.js: -------------------------------------------------------------------------------- 1 | var a = 1 + 1; 2 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/stringify-stylesheet.bench.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @vitest-environment jsdom 3 | */ 4 | import { bench } from 'vitest'; 5 | import * as fs from 'fs'; 6 | import * as path from 'path'; 7 | import { stringifyStylesheet } from '../src/utils'; 8 | import * as CSSOM from 'cssom'; 9 | 10 | describe('stringifyStylesheet', () => { 11 | let benchmarkStylesheet: CSSStyleSheet; 12 | 13 | const cssText = fs.readFileSync( 14 | path.resolve(__dirname, './css/benchmark.css'), 15 | 'utf8', 16 | ); 17 | benchmarkStylesheet = CSSOM.parse(cssText); 18 | benchmarkStylesheet.href = 'https://example.com/style.css'; 19 | 20 | it.skip('stringify', () => { 21 | // written just to ensure it's working 22 | const cssText = '.x { background: url(./relative.jpg) }'; 23 | const styleSheet = CSSOM.parse(cssText); 24 | styleSheet.href = 'https://example.com/style.css'; 25 | expect(stringifyStylesheet(styleSheet)).toEqual( 26 | 'x {background: url(https://example.com/relative.jpg);}', 27 | ); 28 | }); 29 | 30 | bench( 31 | 'stringify', 32 | () => { 33 | stringifyStylesheet(benchmarkStylesheet); 34 | }, 35 | { time: 1000 }, 36 | ); 37 | }); 38 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/test/utils.ts: -------------------------------------------------------------------------------- 1 | import * as puppeteer from 'puppeteer'; 2 | import * as http from 'http'; 3 | 4 | export async function waitForRAF(page: puppeteer.Page) { 5 | return await page.evaluate(() => { 6 | return new Promise((resolve) => { 7 | requestAnimationFrame(() => { 8 | requestAnimationFrame(resolve); 9 | }); 10 | }); 11 | }); 12 | } 13 | 14 | export function getServerURL(server: http.Server): string { 15 | const address = server.address(); 16 | if (address && typeof address !== 'string') { 17 | return `http://localhost:${address.port}`; 18 | } else { 19 | return `${address}`; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "include": ["src"], 4 | "exclude": ["vite.config.ts", "vitest.config.ts", "test"], 5 | "compilerOptions": { 6 | "rootDir": "src", 7 | "tsBuildInfoFile": "./tsconfig.tsbuildinfo" 8 | }, 9 | "references": [ 10 | { 11 | "path": "../types" 12 | }, 13 | { 14 | "path": "../utils" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/vite.config.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import config from '../../vite.config.default'; 3 | 4 | export default config(path.resolve(__dirname, 'src/index.ts'), 'rrwebSnapshot'); 5 | -------------------------------------------------------------------------------- /packages/rrweb-snapshot/vitest.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineProject, mergeConfig } from 'vitest/config'; 3 | import configShared from '../../vitest.config.ts'; 4 | 5 | export default mergeConfig( 6 | configShared, 7 | defineProject({ 8 | test: { 9 | globals: true, 10 | }, 11 | }), 12 | ); 13 | -------------------------------------------------------------------------------- /packages/rrweb/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .idea 3 | node_modules 4 | package-lock.json 5 | # yarn.lock 6 | tsconfig.tsbuildinfo 7 | build 8 | dist 9 | es 10 | lib 11 | typings 12 | 13 | temp 14 | 15 | *.log 16 | 17 | .env 18 | __diff_output__ -------------------------------------------------------------------------------- /packages/rrweb/.release-it.json: -------------------------------------------------------------------------------- 1 | { 2 | "non-interactive": true, 3 | "hooks": { 4 | "before:init": ["npm run bundle", "npm run typings"] 5 | }, 6 | "git": { 7 | "requireCleanWorkingDir": false 8 | }, 9 | "github": { 10 | "release": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/rrweb/rrweb-record/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "../dist/rrweb-record.cjs", 3 | "types": "../dist/rrweb-record.d.ts" 4 | } 5 | -------------------------------------------------------------------------------- /packages/rrweb/rrweb-replay/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "../dist/rrweb-replay.cjs", 3 | "types": "../dist/rrweb-replay.d.ts" 4 | } 5 | -------------------------------------------------------------------------------- /packages/rrweb/src/entries/record.ts: -------------------------------------------------------------------------------- 1 | import record from '../record'; 2 | 3 | export { record }; 4 | -------------------------------------------------------------------------------- /packages/rrweb/src/entries/replay.ts: -------------------------------------------------------------------------------- 1 | export * from '../replay'; 2 | -------------------------------------------------------------------------------- /packages/rrweb/src/index.ts: -------------------------------------------------------------------------------- 1 | import record from './record'; 2 | import { 3 | Replayer, 4 | type playerConfig, 5 | type PlayerMachineState, 6 | type SpeedMachineState, 7 | } from './replay'; 8 | import canvasMutation from './replay/canvas'; 9 | import { _mirror } from './utils'; 10 | import * as utils from './utils'; 11 | 12 | export { 13 | EventType, 14 | IncrementalSource, 15 | MouseInteractions, 16 | ReplayerEvents, 17 | type eventWithTime, 18 | } from '@rrweb/types'; 19 | 20 | // exports style.css from replay 21 | import './replay/styles/style.css'; 22 | 23 | export type { recordOptions, ReplayPlugin } from './types'; 24 | 25 | const { addCustomEvent } = record; 26 | const { freezePage } = record; 27 | const { takeFullSnapshot } = record; 28 | 29 | export { 30 | record, 31 | addCustomEvent, 32 | freezePage, 33 | takeFullSnapshot, 34 | Replayer, 35 | type playerConfig, 36 | type PlayerMachineState, 37 | type SpeedMachineState, 38 | canvasMutation, 39 | _mirror as mirror, 40 | utils, 41 | }; 42 | -------------------------------------------------------------------------------- /packages/rrweb/src/record/error-handler.ts: -------------------------------------------------------------------------------- 1 | import type { ErrorHandler } from '../types'; 2 | 3 | type Callback = (...args: unknown[]) => unknown; 4 | 5 | let errorHandler: ErrorHandler | undefined; 6 | 7 | export function registerErrorHandler(handler: ErrorHandler | undefined) { 8 | errorHandler = handler; 9 | } 10 | 11 | export function unregisterErrorHandler() { 12 | errorHandler = undefined; 13 | } 14 | 15 | /** 16 | * Wrap callbacks in a wrapper that allows to pass errors to a configured `errorHandler` method. 17 | */ 18 | export const callbackWrapper = (cb: T): T => { 19 | if (!errorHandler) { 20 | return cb; 21 | } 22 | 23 | const rrwebWrapped = ((...rest: unknown[]) => { 24 | try { 25 | return cb(...rest); 26 | } catch (error) { 27 | if (errorHandler && errorHandler(error) === true) { 28 | return; 29 | } 30 | 31 | throw error; 32 | } 33 | }) as unknown as T; 34 | 35 | return rrwebWrapped; 36 | }; 37 | -------------------------------------------------------------------------------- /packages/rrweb/src/record/processed-node-manager.ts: -------------------------------------------------------------------------------- 1 | import type MutationBuffer from './mutation'; 2 | 3 | /** 4 | * Keeps a log of nodes that could show up in multiple mutation buffer but shouldn't be handled twice. 5 | */ 6 | export default class ProcessedNodeManager { 7 | private nodeMap: WeakMap> = new WeakMap(); 8 | 9 | private active = false; 10 | 11 | public inOtherBuffer(node: Node, thisBuffer: MutationBuffer) { 12 | const buffers = this.nodeMap.get(node); 13 | return ( 14 | buffers && Array.from(buffers).some((buffer) => buffer !== thisBuffer) 15 | ); 16 | } 17 | 18 | public add(node: Node, buffer: MutationBuffer) { 19 | if (!this.active) { 20 | this.active = true; 21 | requestAnimationFrame(() => { 22 | this.nodeMap = new WeakMap(); 23 | this.active = false; 24 | }); 25 | } 26 | this.nodeMap.set(node, (this.nodeMap.get(node) || new Set()).add(buffer)); 27 | } 28 | 29 | public destroy() { 30 | // cleanup no longer needed 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/rrweb/src/record/workers/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.json", 3 | "compilerOptions": { 4 | "lib": ["webworker"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/rrweb/src/replay/styles/inject-style.ts: -------------------------------------------------------------------------------- 1 | const rules: (blockClass: string) => string[] = (blockClass: string) => [ 2 | `.${blockClass} { background: currentColor }`, 3 | 'noscript { display: none !important; }', 4 | ]; 5 | 6 | export default rules; 7 | -------------------------------------------------------------------------------- /packages/rrweb/test/e2e/__image_snapshots__/webgl-test-ts-test-e-2-e-webgl-test-ts-e-2-e-webgl-will-record-and-replay-a-webgl-image-1-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/e2e/__image_snapshots__/webgl-test-ts-test-e-2-e-webgl-test-ts-e-2-e-webgl-will-record-and-replay-a-webgl-image-1-snap.png -------------------------------------------------------------------------------- /packages/rrweb/test/e2e/__image_snapshots__/webgl-test-ts-test-e-2-e-webgl-test-ts-e-2-e-webgl-will-record-and-replay-a-webgl-square-1-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/e2e/__image_snapshots__/webgl-test-ts-test-e-2-e-webgl-test-ts-e-2-e-webgl-will-record-and-replay-a-webgl-square-1-snap.png -------------------------------------------------------------------------------- /packages/rrweb/test/html/assets/1-minute-of-silence.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/html/assets/1-minute-of-silence.mp3 -------------------------------------------------------------------------------- /packages/rrweb/test/html/assets/bunny-video.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/html/assets/bunny-video.webm -------------------------------------------------------------------------------- /packages/rrweb/test/html/assets/robot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/html/assets/robot.png -------------------------------------------------------------------------------- /packages/rrweb/test/html/assets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: pink; 3 | } 4 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/audio.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Audio 8 | 9 | 10 |

1 minute of silence

11 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/benchmark-dom-mutation-add-and-move.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 37 | 38 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/benchmark-dom-mutation-add-and-remove.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 46 | 47 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/benchmark-dom-mutation-attributes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/benchmark-dom-mutation-deep-nested.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 31 | 32 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/benchmark-dom-mutation-multiple-descendant-add.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/benchmark-dom-mutation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 27 | 28 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/blank.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/block.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Block record 8 | 9 | 10 |
11 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/canvas-webgl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | canvas 7 | 8 | 9 | 15 | 16 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/canvas.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | canvas 7 | 8 | 9 | 15 | 16 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/dialog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | I'm a dialog 4 | 5 | 6 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/empty.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Empty 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | form fields 8 | 9 | 10 | 11 |
12 | 15 | 18 | 21 | 24 | 27 | 33 | 36 | 37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/frame-image-blob-url.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Frame with image 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/frame1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Frame 1 7 | 8 | 9 | frame 1 10 | 11 | 12 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/frame2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Frame 2 7 | 8 | 9 | frame 2 10 | 11 | 18 | 19 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/hello-world.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Hello World! 8 | 9 | 10 | Hello world! 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/ignore.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ignore fields 8 | 9 | 10 | 11 |
12 | 15 | 18 | 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/image-blob-url.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Image with blob:url 8 | 9 | 10 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/link.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Link click 8 | 9 | 10 | 11 | not link 12 | link 13 | 14 | 15 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Main 7 | 13 | 14 | 15 | 16 | 17 | 25 | 26 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/mask-text.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Mask text 8 | 9 | 10 |

mask1

11 |
12 | mask2 13 |
14 |
15 |
16 |
mask3
17 |
18 |
19 | 20 |

21 | unmask1 22 |

23 | 24 | 25 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/move-node.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |

6 |
7 | 8 | 9 | 1 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/mutation-observer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

mutation observer

4 |
    5 |
  • 6 |
7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/password.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/polyfilled-shadowdom-mutation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |
10 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/select2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Select2 3.5 8 | 9 | 10 | 11 |
12 | Select2 is a jQuery replacement for select boxes. 13 |
14 | In the 3.5 version it use a quite complicated DOM generation strategy which is a good battle-test for rrweb's recorder. 15 |
16 | 20 | 21 | 22 | 25 | 26 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/shuffle.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | shuffle 7 | 8 | 9 | 10 |
  • 1
  • 2
  • 3
  • 4
  • 5
11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/style.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | style 7 | 10 | 16 | 19 | 20 | 25 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /packages/rrweb/test/html/video.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Video 8 | 9 | 10 |

Big Buck Bunny

11 | 15 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /packages/rrweb/test/replay/__image_snapshots__/dialog-test-ts-test-replay-dialog-test-ts-dialog-closed-dialogs-show-nothing-1-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/replay/__image_snapshots__/dialog-test-ts-test-replay-dialog-test-ts-dialog-closed-dialogs-show-nothing-1-snap.png -------------------------------------------------------------------------------- /packages/rrweb/test/replay/__image_snapshots__/dialog-test-ts-test-replay-dialog-test-ts-dialog-should-add-an-opened-dialog-with-show-modal-in-incremental-snapshot-alternative.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/replay/__image_snapshots__/dialog-test-ts-test-replay-dialog-test-ts-dialog-should-add-an-opened-dialog-with-show-modal-in-incremental-snapshot-alternative.png -------------------------------------------------------------------------------- /packages/rrweb/test/replay/__image_snapshots__/dialog-test-ts-test-replay-dialog-test-ts-dialog-should-add-an-opened-dialog-with-show-modal-in-incremental-snapshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/replay/__image_snapshots__/dialog-test-ts-test-replay-dialog-test-ts-dialog-should-add-an-opened-dialog-with-show-modal-in-incremental-snapshot.png -------------------------------------------------------------------------------- /packages/rrweb/test/replay/__image_snapshots__/dialog-test-ts-test-replay-dialog-test-ts-dialog-should-close-dialog-again-when-open-attribute-gets-removed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/replay/__image_snapshots__/dialog-test-ts-test-replay-dialog-test-ts-dialog-should-close-dialog-again-when-open-attribute-gets-removed.png -------------------------------------------------------------------------------- /packages/rrweb/test/replay/__image_snapshots__/dialog-test-ts-test-replay-dialog-test-ts-dialog-should-open-dialog-with-show-in-full-snapshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/replay/__image_snapshots__/dialog-test-ts-test-replay-dialog-test-ts-dialog-should-open-dialog-with-show-in-full-snapshot.png -------------------------------------------------------------------------------- /packages/rrweb/test/replay/__image_snapshots__/dialog-test-ts-test-replay-dialog-test-ts-dialog-should-open-dialog-with-show-modal-in-full-snapshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/replay/__image_snapshots__/dialog-test-ts-test-replay-dialog-test-ts-dialog-should-open-dialog-with-show-modal-in-full-snapshot.png -------------------------------------------------------------------------------- /packages/rrweb/test/replay/__image_snapshots__/dialog-test-ts-test-replay-dialog-test-ts-dialog-should-open-dialog-with-show-modal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/replay/__image_snapshots__/dialog-test-ts-test-replay-dialog-test-ts-dialog-should-open-dialog-with-show-modal.png -------------------------------------------------------------------------------- /packages/rrweb/test/replay/__image_snapshots__/dialog-test-ts-test-replay-dialog-test-ts-dialog-should-switch-between-show-and-show-modal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/replay/__image_snapshots__/dialog-test-ts-test-replay-dialog-test-ts-dialog-should-switch-between-show-and-show-modal.png -------------------------------------------------------------------------------- /packages/rrweb/test/replay/__image_snapshots__/dialog-test-ts-test-replay-dialog-test-ts-dialog-should-switch-between-show-modal-and-show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/replay/__image_snapshots__/dialog-test-ts-test-replay-dialog-test-ts-dialog-should-switch-between-show-modal-and-show.png -------------------------------------------------------------------------------- /packages/rrweb/test/replay/__image_snapshots__/dialog-test-ts-test-replay-dialog-test-ts-dialog-show-the-dialog-when-open-attribute-gets-added.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/replay/__image_snapshots__/dialog-test-ts-test-replay-dialog-test-ts-dialog-show-the-dialog-when-open-attribute-gets-added.png -------------------------------------------------------------------------------- /packages/rrweb/test/replay/__image_snapshots__/hover-test-ts-test-replay-hover-test-ts-replayer-hover-should-trigger-hover-on-mouse-down-1-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/replay/__image_snapshots__/hover-test-ts-test-replay-hover-test-ts-replayer-hover-should-trigger-hover-on-mouse-down-1-snap.png -------------------------------------------------------------------------------- /packages/rrweb/test/replay/__image_snapshots__/video-test-ts-test-replay-video-test-ts-video-will-be-paused-when-the-player-wasnt-started-yet-1-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/replay/__image_snapshots__/video-test-ts-test-replay-video-test-ts-video-will-be-paused-when-the-player-wasnt-started-yet-1-snap.png -------------------------------------------------------------------------------- /packages/rrweb/test/replay/__image_snapshots__/video-test-ts-test-replay-video-test-ts-video-will-play-from-the-correct-moment-1-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/replay/__image_snapshots__/video-test-ts-test-replay-video-test-ts-video-will-play-from-the-correct-moment-1-snap.png -------------------------------------------------------------------------------- /packages/rrweb/test/replay/__image_snapshots__/video-test-ts-test-replay-video-test-ts-video-will-seek-to-the-correct-moment-1-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/replay/__image_snapshots__/video-test-ts-test-replay-video-test-ts-video-will-seek-to-the-correct-moment-1-snap.png -------------------------------------------------------------------------------- /packages/rrweb/test/replay/__image_snapshots__/video-test-ts-test-replay-video-test-ts-video-will-seek-to-the-correct-moment-without-media-interaction-events-1-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/replay/__image_snapshots__/video-test-ts-test-replay-video-test-ts-video-will-seek-to-the-correct-moment-without-media-interaction-events-1-snap.png -------------------------------------------------------------------------------- /packages/rrweb/test/replay/__image_snapshots__/webgl-test-ts-test-replay-webgl-test-ts-replayer-webgl-should-output-simple-webgl-object-1-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/rrweb/test/replay/__image_snapshots__/webgl-test-ts-test-replay-webgl-test-ts-replayer-webgl-should-output-simple-webgl-object-1-snap.png -------------------------------------------------------------------------------- /packages/rrweb/test/replay/webgl-mutation.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @vitest-environment jsdom 3 | */ 4 | import { vi } from 'vitest'; 5 | import { polyfillWebGLGlobals } from '../utils'; 6 | polyfillWebGLGlobals(); 7 | 8 | import webglMutation from '../../src/replay/canvas/webgl'; 9 | import { CanvasContext } from '@rrweb/types'; 10 | import { variableListFor } from '../../src/replay/canvas/deserialize-args'; 11 | 12 | let canvas: HTMLCanvasElement; 13 | describe('webglMutation', () => { 14 | beforeEach(() => { 15 | canvas = document.createElement('canvas'); 16 | }); 17 | afterEach(() => { 18 | vi.clearAllMocks(); 19 | }); 20 | 21 | it('should create webgl variables', async () => { 22 | const createShaderMock = vi.fn().mockImplementation(() => { 23 | return new WebGLShader(); 24 | }); 25 | const context = { 26 | createShader: createShaderMock, 27 | } as unknown as WebGLRenderingContext; 28 | vi.spyOn(canvas, 'getContext').mockImplementation(() => { 29 | return context; 30 | }); 31 | 32 | expect(variableListFor(context, 'WebGLShader')).toHaveLength(0); 33 | 34 | await webglMutation({ 35 | mutation: { 36 | property: 'createShader', 37 | args: [35633], 38 | }, 39 | type: CanvasContext.WebGL, 40 | target: canvas, 41 | imageMap: new Map(), 42 | errorHandler: () => {}, 43 | }); 44 | 45 | expect(createShaderMock).toHaveBeenCalledWith(35633); 46 | expect(variableListFor(context, 'WebGLShader')).toHaveLength(1); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /packages/rrweb/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "include": ["src"], 4 | "compilerOptions": { 5 | "rootDir": "src", 6 | "tsBuildInfoFile": "./tsconfig.tsbuildinfo", 7 | "types": [ 8 | // from tsconfig.base.json 9 | "vite/client", 10 | "@types/dom-mediacapture-transform", 11 | "@types/offscreencanvas", 12 | // rrweb specific: 13 | /* 14 | * @see https://vitest.dev/config/#globals 15 | * if we remove the --globals flag from the vite test command, we can remove this 16 | * to remove the flag, we need to add vitest imports in the test files 17 | */ 18 | "vitest/globals" 19 | ], 20 | // TODO: enable me in the future, this is quite a large project 21 | // at time of writing (April 2024) there are over 100 errors in rrweb 22 | "strict": false 23 | }, 24 | "references": [ 25 | { 26 | "path": "../types" 27 | }, 28 | { 29 | "path": "../utils" 30 | }, 31 | { 32 | "path": "../rrdom" 33 | }, 34 | { 35 | "path": "../rrweb-snapshot" 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /packages/rrweb/vite.config.entries.js: -------------------------------------------------------------------------------- 1 | import config from '../../vite.config.default'; 2 | 3 | export default config( 4 | { 5 | // rrweb: 'src/index.ts', 6 | 'rrweb-record': 'src/entries/record.ts', 7 | 'rrweb-replay': 'src/entries/replay.ts', 8 | }, 9 | 'rrweb', 10 | // { outputDir: 'dist/alt' }, 11 | { outputDir: 'dist' }, 12 | ); 13 | -------------------------------------------------------------------------------- /packages/rrweb/vite.config.js: -------------------------------------------------------------------------------- 1 | import config from '../../vite.config.default'; 2 | 3 | // export default config('src/index.ts', 'rrweb', { outputDir: 'dist/main' }); 4 | export default config('src/index.ts', 'rrweb'); 5 | -------------------------------------------------------------------------------- /packages/rrweb/vitest.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineProject, mergeConfig } from 'vitest/config'; 3 | import configShared from '../../vitest.config'; 4 | 5 | export default mergeConfig( 6 | configShared, 7 | defineProject({ 8 | test: { 9 | globals: true, 10 | }, 11 | }), 12 | ); 13 | -------------------------------------------------------------------------------- /packages/types/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | es 3 | lib 4 | typings 5 | -------------------------------------------------------------------------------- /packages/types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rrweb/types", 3 | "version": "2.0.0-alpha.18", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "keywords": [ 8 | "rrweb", 9 | "@rrweb/types" 10 | ], 11 | "scripts": { 12 | "dev": "vite build --watch", 13 | "build": "yarn turbo run prepublish", 14 | "check-types": "tsc -noEmit", 15 | "prepublish": "tsc -noEmit && vite build", 16 | "lint": "yarn eslint src/**/*.ts" 17 | }, 18 | "homepage": "https://github.com/rrweb-io/rrweb/tree/main/packages/@rrweb/types#readme", 19 | "bugs": { 20 | "url": "https://github.com/rrweb-io/rrweb/issues" 21 | }, 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/rrweb-io/rrweb.git" 25 | }, 26 | "license": "MIT", 27 | "type": "module", 28 | "main": "./dist/types.umd.cjs", 29 | "module": "./dist/types.js", 30 | "unpkg": "./dist/types.umd.cjs", 31 | "typings": "dist/index.d.ts", 32 | "exports": { 33 | ".": { 34 | "import": { 35 | "types": "./dist/index.d.ts", 36 | "default": "./dist/types.js" 37 | }, 38 | "require": { 39 | "types": "./dist/index.d.cts", 40 | "default": "./dist/types.umd.cjs" 41 | } 42 | } 43 | }, 44 | "files": [ 45 | "dist", 46 | "package.json" 47 | ], 48 | "devDependencies": { 49 | "vite": "^5.3.1", 50 | "vite-plugin-dts": "^3.9.1" 51 | }, 52 | "browserslist": [ 53 | "supports es6-class" 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /packages/types/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "include": ["src"], 4 | "exclude": ["vite.config.ts"], 5 | "compilerOptions": { 6 | "rootDir": "src", 7 | "tsBuildInfoFile": "./tsconfig.tsbuildinfo" 8 | }, 9 | "references": [] 10 | } 11 | -------------------------------------------------------------------------------- /packages/types/vite.config.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import config from '../../vite.config.default'; 3 | 4 | export default config(path.resolve(__dirname, 'src/index.ts'), 'rrwebTypes'); 5 | -------------------------------------------------------------------------------- /packages/utils/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @rrweb/utils 2 | 3 | ## 2.0.0-alpha.18 4 | 5 | ## 2.0.0-alpha.17 6 | 7 | ### Patch Changes 8 | 9 | - [#1509](https://github.com/rrweb-io/rrweb/pull/1509) [`be6bf52`](https://github.com/rrweb-io/rrweb/commit/be6bf52c248c35de1b3491e3a3440ff61f876414) Thanks [@Juice10](https://github.com/Juice10)! - Reverse monkey patch built in methods to support LWC (and other frameworks like angular which monkey patch built in methods). 10 | -------------------------------------------------------------------------------- /packages/utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rrweb/utils", 3 | "version": "2.0.0-alpha.18", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "keywords": [ 8 | "rrweb", 9 | "@rrweb/utils" 10 | ], 11 | "scripts": { 12 | "dev": "vite build --watch", 13 | "build": "tsc -noEmit && vite build", 14 | "check-types": "tsc -noEmit", 15 | "prepublish": "npm run build", 16 | "lint": "yarn eslint src/**/*.ts" 17 | }, 18 | "homepage": "https://github.com/rrweb-io/rrweb/tree/main/packages/@rrweb/utils#readme", 19 | "bugs": { 20 | "url": "https://github.com/rrweb-io/rrweb/issues" 21 | }, 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/rrweb-io/rrweb.git" 25 | }, 26 | "license": "MIT", 27 | "type": "module", 28 | "main": "./dist/utils.umd.cjs", 29 | "module": "./dist/utils.js", 30 | "unpkg": "./dist/utils.umd.cjs", 31 | "typings": "dist/index.d.ts", 32 | "exports": { 33 | ".": { 34 | "import": { 35 | "types": "./dist/index.d.ts", 36 | "default": "./dist/utils.js" 37 | }, 38 | "require": { 39 | "types": "./dist/index.d.cts", 40 | "default": "./dist/utils.umd.cjs" 41 | } 42 | } 43 | }, 44 | "files": [ 45 | "dist", 46 | "package.json" 47 | ], 48 | "devDependencies": { 49 | "vite": "^5.2.8", 50 | "vite-plugin-dts": "^3.8.1" 51 | }, 52 | "dependencies": {} 53 | } 54 | -------------------------------------------------------------------------------- /packages/utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "include": ["src"], 4 | "exclude": ["vite.config.ts"], 5 | "compilerOptions": { 6 | "rootDir": "src", 7 | "tsBuildInfoFile": "./tsconfig.tsbuildinfo" 8 | }, 9 | "references": [] 10 | } 11 | -------------------------------------------------------------------------------- /packages/utils/vite.config.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import config from '../../vite.config.default'; 3 | 4 | export default config(path.resolve(__dirname, 'src/index.ts'), 'rrwebUtils'); 5 | -------------------------------------------------------------------------------- /packages/web-extension/src/components/CircleButton.tsx: -------------------------------------------------------------------------------- 1 | import { Button, type ButtonProps } from '@chakra-ui/react'; 2 | 3 | interface CircleButtonProps extends ButtonProps { 4 | diameter: number; 5 | onClick?: () => void; 6 | children?: React.ReactNode; 7 | title?: string; 8 | } 9 | 10 | export function CircleButton({ 11 | diameter, 12 | onClick, 13 | children, 14 | title, 15 | ...rest 16 | }: CircleButtonProps) { 17 | return ( 18 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /packages/web-extension/src/options/App.tsx: -------------------------------------------------------------------------------- 1 | import { Route, Routes } from 'react-router-dom'; 2 | import SidebarWithHeader from '~/components/SidebarWithHeader'; 3 | import { FiList, FiSettings } from 'react-icons/fi'; 4 | import { Box } from '@chakra-ui/react'; 5 | 6 | export default function App() { 7 | return ( 8 | 24 | 25 | 26 | } /> 27 | 28 | 29 | 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /packages/web-extension/src/options/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | rrweb settings 4 | 5 | 6 |
7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/web-extension/src/options/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ChakraProvider } from '@chakra-ui/react'; 3 | import * as ReactDOM from 'react-dom/client'; 4 | import { createHashRouter, RouterProvider } from 'react-router-dom'; 5 | import App from './App'; 6 | 7 | const rootElement = document.getElementById('root'); 8 | const router = createHashRouter([ 9 | { 10 | path: '/*', 11 | element: , 12 | }, 13 | ]); 14 | 15 | rootElement && 16 | ReactDOM.createRoot(rootElement).render( 17 | 18 | 19 | 20 | 21 | , 22 | ); 23 | -------------------------------------------------------------------------------- /packages/web-extension/src/pages/App.tsx: -------------------------------------------------------------------------------- 1 | import { Route, Routes } from 'react-router-dom'; 2 | import SidebarWithHeader from '~/components/SidebarWithHeader'; 3 | import { SessionList } from './SessionList'; 4 | import { FiList, FiSettings } from 'react-icons/fi'; 5 | import Player from './Player'; 6 | 7 | export default function App() { 8 | return ( 9 | 31 | 32 | } /> 33 | } /> 34 | 35 | 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /packages/web-extension/src/pages/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | rrweb 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/web-extension/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ChakraProvider } from '@chakra-ui/react'; 3 | import * as ReactDOM from 'react-dom/client'; 4 | import { createHashRouter, RouterProvider } from 'react-router-dom'; 5 | import App from './App'; 6 | 7 | const rootElement = document.getElementById('root'); 8 | const router = createHashRouter([ 9 | { 10 | path: '/*', 11 | element: , 12 | }, 13 | ]); 14 | 15 | rootElement && 16 | ReactDOM.createRoot(rootElement).render( 17 | 18 | 19 | 20 | 21 | , 22 | ); 23 | -------------------------------------------------------------------------------- /packages/web-extension/src/popup/Timer.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | import { Stat, StatNumber } from '@chakra-ui/react'; 3 | import { formatTime } from '~/utils'; 4 | 5 | export function Timer({ 6 | startTime, 7 | ticking, 8 | }: { 9 | startTime: number; 10 | ticking: boolean; 11 | }) { 12 | const [time, setTime] = useState(Date.now() - startTime); 13 | useEffect(() => { 14 | if (!ticking) return; 15 | const interval = setInterval(() => { 16 | setTime(Date.now() - startTime); 17 | }, 100); 18 | return () => clearInterval(interval); 19 | }, [startTime, ticking]); 20 | return ( 21 | 22 | {formatTime(time)} 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /packages/web-extension/src/popup/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ChakraProvider } from '@chakra-ui/react'; 3 | import * as ReactDOM from 'react-dom/client'; 4 | import { App } from './App'; 5 | 6 | const rootElement = document.getElementById('root'); 7 | 8 | rootElement && 9 | ReactDOM.createRoot(rootElement).render( 10 | 11 | 12 | 13 | 14 | , 15 | ); 16 | -------------------------------------------------------------------------------- /packages/web-extension/src/popup/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/web-extension/src/public/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/web-extension/src/public/icon128.png -------------------------------------------------------------------------------- /packages/web-extension/src/public/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/web-extension/src/public/icon16.png -------------------------------------------------------------------------------- /packages/web-extension/src/public/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rrweb-io/rrweb/fd9d2747c6a236975055a69165ccce640b029015/packages/web-extension/src/public/icon48.png -------------------------------------------------------------------------------- /packages/web-extension/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export function isFirefox(): boolean { 2 | return ( 3 | (typeof window !== 'undefined' && 4 | window.navigator?.userAgent.toLowerCase().includes('firefox')) || 5 | false 6 | ); 7 | } 8 | 9 | export function isInCrossOriginIFrame(): boolean { 10 | if (window.parent !== window) { 11 | try { 12 | void window.parent.location.origin; 13 | } catch (error) { 14 | return true; 15 | } 16 | } 17 | return false; 18 | } 19 | 20 | const SECOND = 1000; 21 | const MINUTE = 60 * SECOND; 22 | const HOUR = 60 * MINUTE; 23 | 24 | export function formatTime(ms: number): string { 25 | if (ms <= 0) { 26 | return '00:00'; 27 | } 28 | const hour = Math.floor(ms / HOUR); 29 | ms = ms % HOUR; 30 | const minute = Math.floor(ms / MINUTE); 31 | ms = ms % MINUTE; 32 | const second = Math.floor(ms / SECOND); 33 | if (hour) { 34 | return `${padZero(hour)}:${padZero(minute)}:${padZero(second)}`; 35 | } 36 | return `${padZero(minute)}:${padZero(second)}`; 37 | } 38 | 39 | function padZero(num: number, len = 2): string { 40 | let str = String(num); 41 | const threshold = Math.pow(10, len - 1); 42 | if (num < threshold) { 43 | while (String(threshold).length > str.length) { 44 | str = `0${num}`; 45 | } 46 | } 47 | return str; 48 | } 49 | -------------------------------------------------------------------------------- /packages/web-extension/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "baseUrl": ".", 6 | "tsBuildInfoFile": "./tsconfig.tsbuildinfo", 7 | "esModuleInterop": true, 8 | "incremental": true, 9 | "resolveJsonModule": true, 10 | "paths": { 11 | "~/*": ["src/*"] 12 | }, 13 | "jsx": "react-jsx" 14 | }, 15 | "exclude": ["dist", "node_modules", "vite.config.ts"], 16 | "references": [ 17 | { 18 | "path": "../rrweb" 19 | }, 20 | { 21 | "path": "../rrweb-player" 22 | }, 23 | { 24 | "path": "../types" 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /scripts/lint-packages.sh: -------------------------------------------------------------------------------- 1 | script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 2 | packages_dir="$script_dir/../packages" 3 | 4 | for dir in "$packages_dir"/*/ "$packages_dir/plugins"/*/ ; do 5 | if [ -d "$dir" ] && [ -f "$dir/package.json" ]; then 6 | ( 7 | cd "$dir" || exit 8 | npx publint --strict 9 | attw --pack . --exclude-entrypoints dist/style.css 10 | ) 11 | fi 12 | done -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | /** 5 | * @see https://vitejs.dev/guide/features.html#target 6 | */ 7 | "esModuleInterop": true, 8 | "target": "ESNext", 9 | "module": "ESNext", 10 | "moduleResolution": "Node", 11 | "rootDir": "src", 12 | "outDir": "dist", 13 | "lib": ["es6", "dom"], 14 | "sourceMap": true, 15 | "skipLibCheck": true, 16 | "declaration": true, 17 | "verbatimModuleSyntax": true, 18 | "strict": true, 19 | "removeComments": true, 20 | "noImplicitAny": true, 21 | "strictNullChecks": true, 22 | "preserveConstEnums": true, 23 | "strictBindCallApply": true, 24 | "noUnusedLocals": true, 25 | "noUnusedParameters": true, 26 | "forceConsistentCasingInFileNames": true, 27 | "downlevelIteration": true, 28 | 29 | // needed for vite 30 | /** 31 | * @see https://vitejs.dev/guide/features.html#isolatedmodules 32 | */ 33 | "isolatedModules": true, 34 | 35 | "types": [ 36 | "node", 37 | /** 38 | * needed as long as we have jest tests 39 | * they add globals like `test` and `expect` 40 | */ 41 | "jest", 42 | /** 43 | * @see https://vitejs.dev/guide/features.html#client-types 44 | */ 45 | "vite/client", 46 | "@types/dom-mediacapture-transform", 47 | "@types/offscreencanvas" 48 | ] 49 | }, 50 | "exclude": ["**/vite.config.ts", "**/vitest.config.ts", "**/test"], 51 | "compileOnSave": true 52 | } 53 | -------------------------------------------------------------------------------- /tsconfig.eslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": [".eslintrc.js"] 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "references": [ 3 | { 4 | "path": "packages/rrdom" 5 | }, 6 | { 7 | "path": "packages/rrdom-nodejs" 8 | }, 9 | { 10 | "path": "packages/rrweb" 11 | }, 12 | { 13 | "path": "packages/rrweb-player" 14 | }, 15 | { 16 | "path": "packages/rrweb-snapshot" 17 | }, 18 | { 19 | "path": "packages/types" 20 | }, 21 | { 22 | "path": "packages/plugins/rrweb-plugin-console-replay" 23 | }, 24 | { 25 | "path": "packages/plugins/rrweb-plugin-console-record" 26 | }, 27 | { 28 | "path": "packages/rrvideo" 29 | }, 30 | { 31 | "path": "packages/web-extension" 32 | } 33 | ], 34 | "files": [], 35 | "include": [], 36 | "exclude": [], 37 | "compilerOptions": { 38 | "rootDir": "." 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turborepo.org/schema.json", 3 | // These root workspace files are reused in workspaces and may affect their build output 4 | "globalDependencies": [ 5 | ".eslintrc.js", 6 | ".prettierrc", 7 | "vite.config.defaults.ts", 8 | "tsconfig.json" 9 | ], 10 | "globalPassThroughEnv": ["PUPPETEER_HEADLESS", "DISABLE_WORKER_INLINING"], 11 | "tasks": { 12 | "prepublish": { 13 | "dependsOn": ["^prepublish", "//#references:update"], 14 | "outputs": [ 15 | "lib/**", 16 | "es/**", 17 | "dist/**", 18 | "typings/**", 19 | ".svelte-kit/**", 20 | "types/**" 21 | ] 22 | }, 23 | "test": { 24 | "dependsOn": ["^prepublish"] 25 | }, 26 | "test:watch": { 27 | "persistent": true, 28 | "cache": false 29 | }, 30 | "test:update": { 31 | "dependsOn": ["^prepublish"] 32 | }, 33 | "dev": { 34 | "dependsOn": ["prepublish", "^prepublish"], 35 | "persistent": true, 36 | "cache": false 37 | }, 38 | "lint": {}, 39 | "check-types": { 40 | "dependsOn": ["^prepublish"] 41 | }, 42 | "//#references:update": { 43 | "inputs": ["packages/*/package.json", "packages/plugins/*/package.json"], 44 | "outputs": [ 45 | "packages/*/tsconfig.json", 46 | "packages/plugins/*/tsconfig.json" 47 | ] 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | test: { 3 | /** 4 | * Keeps old (pre-jest 29) snapshot format 5 | * its a bit ugly and harder to read than the new format, 6 | * so we might want to remove this in its own PR 7 | */ 8 | snapshotFormat: { 9 | escapeString: true, 10 | printBasicPrototype: true, 11 | }, 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /vitest.workspace.ts: -------------------------------------------------------------------------------- 1 | import { defineWorkspace } from 'vitest/config'; 2 | 3 | export default defineWorkspace(['packages/**/vitest.config.ts']); 4 | --------------------------------------------------------------------------------