diff --git a/.craft.yml b/.craft.yml new file mode 100644 index 0000000000..6032f44ad7 --- /dev/null +++ b/.craft.yml @@ -0,0 +1,15 @@ +github: + owner: getsentry + repo: rrweb +changelogPolicy: simple +preReleaseCommand: bash scripts/craft-pre-release.sh +requireNames: + - /^sentry-internal-rrweb-snapshot-.*\.tgz$/ + - /^sentry-internal-rrweb-player-.*\.tgz$/ + - /^sentry-internal-rrweb-.*\.tgz$/ + - /^sentry-internal-rrdom-.*\.tgz$/ +targets: + - name: github + includeNames: /^sentry-.*.tgz$/ + - name: npm + includeNames: /^sentry-.*.tgz$/ diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 128b0da4eb..081895b70e 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -1,11 +1,16 @@ -name: Tests +name: Build & Tests -on: [pull_request] +on: + push: + branches: + - master + - release/** + pull_request: concurrency: ${{ github.workflow }}-${{ github.ref }} jobs: - release: + job_test: name: Tests runs-on: ubuntu-latest steps: @@ -26,5 +31,31 @@ jobs: - name: Run tests # Skip this for now, as it somehow always fails - if: 1 == 2 - run: xvfb-run --server-args="-screen 0 1920x1080x24" yarn test \ No newline at end of file + if: 1 == 2 + run: xvfb-run --server-args="-screen 0 1920x1080x24" yarn test + + job_artifacts: + needs: job_test + name: Upload Artifacts + runs-on: ubuntu-latest + # Build artifacts are only needed for releasing workflow. + if: startsWith(github.ref, 'refs/heads/release/') + steps: + - name: Checkout Repo + uses: actions/checkout@v3 + + - name: Set up Node + uses: volta-cli/action@v3 + + - name: Install Dependencies + run: yarn --frozen-lockfile + + - name: Build Tarballs + run: yarn build:tarball + + - name: Upload Artifacts + uses: actions/upload-artifact@v3 + with: + name: ${{ github.sha }} + path: | + ${{ github.workspace }}/packages/**/*.tgz diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..e6335c507e --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,30 @@ +name: Prepare Release +on: + workflow_dispatch: + inputs: + version: + description: Version to release + required: true + force: + description: Force a release even when there are release-blockers (optional) + required: false + merge_target: + description: Target branch to merge into. Uses the default branch, sentry-v1, as a fallback (optional) + required: false +jobs: + release: + runs-on: ubuntu-latest + name: 'Release a new version' + steps: + - uses: actions/checkout@v3 + with: + token: ${{ secrets.GH_RELEASE_PAT }} + fetch-depth: 0 + - name: Prepare release + uses: getsentry/action-prepare-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GH_RELEASE_PAT }} + with: + version: ${{ github.event.inputs.version }} + force: ${{ github.event.inputs.force }} + merge_target: ${{ github.event.inputs.merge_target }} diff --git a/LICENSE b/LICENSE index fce28eb837..d11896ba11 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,14 @@ -MIT License +Copyright (c) 2023 Sentry (https://sentry.io) and individual contributors. All rights reserved. -Copyright (c) 2018 Contributors (https://github.com/rrweb-io/rrweb/graphs/contributors) and SmartX Inc. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 3e6490f17b..fefcc0e451 100644 --- a/README.md +++ b/README.md @@ -1,160 +1,28 @@

- -

-

- Try rrweb + + Sentry +

-# rrweb - -**[The rrweb documentary (in Chinese, with English subtitles)](https://www.bilibili.com/video/BV1wL4y1B7wN?share_source=copy_web)** - -[![Join the chat at slack](https://img.shields.io/badge/slack-@rrweb-teal.svg?logo=slack)](https://join.slack.com/t/rrweb/shared_invite/zt-siwoc6hx-uWay3s2wyG8t5GpZVb8rWg) -[![Twitter Follow](https://img.shields.io/badge/twitter-@rrweb__io-teal.svg?logo=twitter)](https://twitter.com/rrweb_io) -![total gzip size](https://img.badgesize.io/https://cdn.jsdelivr.net/npm/rrweb@latest/dist/rrweb.min.js?compression=gzip&label=total%20gzip%20size) -![recorder gzip size](https://img.badgesize.io/https://cdn.jsdelivr.net/npm/rrweb@latest/dist/record/rrweb-record.min.js?compression=gzip&label=recorder%20gzip%20size) -[![](https://data.jsdelivr.com/v1/package/npm/rrweb/badge)](https://www.jsdelivr.com/package/npm/rrweb) - -[δΈ­ζ–‡ζ–‡ζ‘£](./README.zh_CN.md) - -> I have joined Github Sponsors and highly appreciate your sponsorship. - -rrweb refers to 'record and replay the web', which is a tool for recording and replaying users' interactions on the web. - -## Guide - -[**πŸ“š Read the rrweb guide here. πŸ“š**](./guide.md) - -[**🍳 Recipes 🍳**](./docs/recipes/index.md) - -## Project Structure - -rrweb is mainly composed of 3 parts: - -- **[rrweb-snapshot](https://github.com/rrweb-io/rrweb/tree/master/packages/rrweb-snapshot/)**, including both snapshot and rebuilding features. The snapshot is used to convert the DOM and its state into a serializable data structure with a unique identifier; the rebuilding feature is to rebuild the snapshot into corresponding DOM. -- **[rrweb](https://github.com/rrweb-io/rrweb)**, including two functions, record and replay. The record function is used to record all the mutations in the DOM; the replay is to replay the recorded mutations one by one according to the corresponding timestamp. -- **[rrweb-player](https://github.com/rrweb-io/rrweb/tree/master/packages/rrweb-player/)**, is a player UI for rrweb, providing GUI-based functions like pause, fast-forward, drag and drop to play at any time. - -## Roadmap - -- rrdom: an ad-hoc DOM for rrweb session data [#419](https://github.com/rrweb-io/rrweb/issues/419) -- storage engine: do deduplication on a large number of rrweb sessions -- more end-to-end tests -- compact mutation data in common patterns -- provide plugins via the new plugin API, including: - - XHR plugin - - fetch plugin - - GraphQL plugin - - ... +# Sentry rrweb Fork -## Internal Design +This repo is a fork of [rrweb](https://github.com/rrweb-io/rrweb). The purpose is to apply patches and bugfixes to rrweb and release Sentry-internal packages with our patches included. All credits and attribution for rrweb go to the original creators of the library and all its contributors. -- [serialization](./docs/serialization.md) -- [incremental snapshot](./docs/observer.md) -- [replay](./docs/replay.md) -- [sandbox](./docs/sandbox.md) +From this monorepo, Sentry maintains and publishes the following NPM packages: -## Contribute Guide +- `@sentry-internal/rrweb` (corresponds to the [original `rrweb` package](https://www.npmjs.com/package/rrweb)) +- `@sentry-internal/rrdom` (corresponds to the [original `rrdom` package](https://www.npmjs.com/package/rrdom)) +- `@sentry-internal/rrweb-player` (corresponds to the [original `rrweb-player` package](https://www.npmjs.com/package/rrweb-player)) +- `@sentry-internal/rrweb-snapshot` (corresponds to the [original `rrweb-snapshot` package](https://www.npmjs.com/package/rrweb-snapshot)) -Since we want the record and replay sides to share a strongly typed data structure, rrweb is developed with typescript which provides stronger type support. - -[Typescript handbook](https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html) - -1. Fork this repository. -2. Run `yarn install` in the root to install required dependencies for all sub-packages (note: `npm install` is _not_ recommended). -3. Run `yarn dev` in the root to get auto-building for all the sub-packages whenever you modify anything. -4. Navigate to one of the sub-packages (in the `packages` folder) where you'd like to make a change. -5. Patch the code and run `yarn test` to run the tests, make sure they pass before you commit anything. -6. Push the code and create a pull request. - -Protip: You can run `yarn test` in the root folder to run all the tests. - -In addition to adding integration tests and unit tests, rrweb also provides a REPL testing tool. - -[Using the REPL tool](./guide.md#REPL-tool) - -## Core Team Members - - - - - - - - -
- - -
Yuyz0112 -
-
- - -
Mark-Fenng -
-
- - -
eoghanmurray -
-
- - -
Juice10 -
-
- -## Who's using rrweb +# rrweb - - - - - - - - - - - -
- - - - - - - - - - - - - - The first ever UX automation tool - -
- - - - - - Remote Access & Co-Browsing - -
+

+ +

+

+ Check out the original rrweb Repo +

+

+ rrweb.io +

diff --git a/package.json b/package.json index 42e45ff27c..dffd879233 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ "test:watch": "yarn lerna run test:watch --parallel", "dev": "yarn lerna run dev --parallel", "repl": "cd packages/rrweb && npm run repl", - "postinstall": "node node_modules/puppeteer/install.js" + "postinstall": "node node_modules/puppeteer/install.js", + "build:tarball": "yarn lerna run build:tarball" }, "volta": { "node": "12.22.12", diff --git a/packages/rrdom/LICENSE b/packages/rrdom/LICENSE new file mode 100644 index 0000000000..d11896ba11 --- /dev/null +++ b/packages/rrdom/LICENSE @@ -0,0 +1,14 @@ +Copyright (c) 2023 Sentry (https://sentry.io) and individual contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/rrdom/package.json b/packages/rrdom/package.json index a1ed991ca5..9df6631c12 100644 --- a/packages/rrdom/package.json +++ b/packages/rrdom/package.json @@ -1,12 +1,13 @@ { - "name": "rrdom", + "name": "@sentry-internal/rrdom", "version": "0.1.2", "scripts": { "dev": "rollup -c -w", "bundle": "rollup --config", "bundle:es-only": "cross-env ES_ONLY=true rollup --config", "test": "jest", - "prepublish": "npm run bundle" + "prepublish": "npm run bundle", + "build:tarball": "npm pack" }, "keywords": [ "rrweb", @@ -33,7 +34,7 @@ "rollup": "^2.56.3", "rollup-plugin-terser": "^7.0.2", "rollup-plugin-typescript2": "^0.30.0", - "rrweb-snapshot": "^1.1.14", + "@sentry-internal/rrweb-snapshot": "^1.1.14", "ts-jest": "^27.0.5", "tslib": "^2.3.1", "typescript": "^3.9.5" diff --git a/packages/rrdom/rollup.config.js b/packages/rrdom/rollup.config.js index 80baed3473..d0117e98e9 100644 --- a/packages/rrdom/rollup.config.js +++ b/packages/rrdom/rollup.config.js @@ -55,6 +55,7 @@ for (let config of baseConfigs) { name: config.name, format: 'iife', file: pkg.unpkg.replace(pkg.name, config.path), + extend: true, }, ], }, @@ -67,6 +68,7 @@ for (let config of baseConfigs) { format: 'iife', file: toMinPath(pkg.unpkg).replace(pkg.name, config.path), sourcemap: true, + extend: true, }, ], }, diff --git a/packages/rrdom/src/document-nodejs.ts b/packages/rrdom/src/document-nodejs.ts index aff8d90512..2125b44bdc 100644 --- a/packages/rrdom/src/document-nodejs.ts +++ b/packages/rrdom/src/document-nodejs.ts @@ -1,4 +1,8 @@ -import { INode, NodeType, serializedNodeWithId } from 'rrweb-snapshot'; +import { + INode, + NodeType, + serializedNodeWithId, +} from '@sentry-internal/rrweb-snapshot'; import { NWSAPI } from 'nwsapi'; import { parseCSSText, camelize, toCSSText } from './style'; const nwsapi = require('nwsapi'); diff --git a/packages/rrdom/src/style.ts b/packages/rrdom/src/style.ts index 1e49b83619..fd57dee1a1 100644 --- a/packages/rrdom/src/style.ts +++ b/packages/rrdom/src/style.ts @@ -1,40 +1,39 @@ export function parseCSSText(cssText: string): Record { - const res: Record = {}; - const listDelimiter = /;(?![^(]*\))/g; - const propertyDelimiter = /:(.+)/; - cssText.split(listDelimiter).forEach(function (item) { - if (item) { - const tmp = item.split(propertyDelimiter); - tmp.length > 1 && (res[camelize(tmp[0].trim())] = tmp[1].trim()); - } - }); - return res; + const res: Record = {}; + const listDelimiter = /;(?![^(]*\))/g; + const propertyDelimiter = /:(.+)/; + cssText.split(listDelimiter).forEach(function (item) { + if (item) { + const tmp = item.split(propertyDelimiter); + tmp.length > 1 && (res[camelize(tmp[0].trim())] = tmp[1].trim()); + } + }); + return res; +} + +export function toCSSText(style: Record): string { + const properties = []; + for (let name in style) { + const value = style[name]; + if (typeof value !== 'string') continue; + const normalizedName = hyphenate(name); + properties.push(`${normalizedName}:${value};`); } - - export function toCSSText(style: Record): string { - const properties = []; - for (let name in style) { - const value = style[name]; - if (typeof value !== 'string') continue; - const normalizedName = hyphenate(name); - properties.push(`${normalizedName}:${value};`); - } - return properties.join(' '); - } - - /** - * Camelize a hyphen-delimited string. - */ - const camelizeRE = /-(\w)/g; - export const camelize = (str: string): string => { - return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : '')); - }; - - /** - * Hyphenate a camelCase string. - */ - const hyphenateRE = /\B([A-Z])/g; - export const hyphenate = (str: string): string => { - return str.replace(hyphenateRE, '-$1').toLowerCase(); - }; - \ No newline at end of file + return properties.join(' '); +} + +/** + * Camelize a hyphen-delimited string. + */ +const camelizeRE = /-(\w)/g; +export const camelize = (str: string): string => { + return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : '')); +}; + +/** + * Hyphenate a camelCase string. + */ +const hyphenateRE = /\B([A-Z])/g; +export const hyphenate = (str: string): string => { + return str.replace(hyphenateRE, '-$1').toLowerCase(); +}; diff --git a/packages/rrweb-player/LICENSE b/packages/rrweb-player/LICENSE new file mode 100644 index 0000000000..d11896ba11 --- /dev/null +++ b/packages/rrweb-player/LICENSE @@ -0,0 +1,14 @@ +Copyright (c) 2023 Sentry (https://sentry.io) and individual contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/rrweb-player/package.json b/packages/rrweb-player/package.json index ec09c21361..1db1cf2223 100644 --- a/packages/rrweb-player/package.json +++ b/packages/rrweb-player/package.json @@ -1,5 +1,5 @@ { - "name": "rrweb-player", + "name": "@sentry-internal/rrweb-player", "version": "0.7.14", "devDependencies": { "@rollup/plugin-commonjs": "^11.0.0", @@ -25,7 +25,7 @@ }, "dependencies": { "@tsconfig/svelte": "^1.0.0", - "rrweb": "^1.1.3" + "@sentry-internal/rrweb": "^1.1.3" }, "scripts": { "build": "rollup -c", @@ -33,7 +33,8 @@ "prepublishOnly": "yarn build", "start": "sirv public", "validate": "svelte-check", - "prepublish": "yarn build" + "prepublish": "yarn build", + "build:tarball": "npm pack" }, "description": "rrweb's replayer UI", "main": "lib/index.js", diff --git a/packages/rrweb-player/src/Controller.svelte b/packages/rrweb-player/src/Controller.svelte index 33cfac775a..d3303ac688 100644 --- a/packages/rrweb-player/src/Controller.svelte +++ b/packages/rrweb-player/src/Controller.svelte @@ -1,11 +1,11 @@ - - {#if showController}
@@ -338,17 +245,20 @@ class="rr-progress" class:disabled={speedState === 'skipping'} bind:this={progress} - on:click={(event) => handleProgressClick(event)}> + on:click={(event) => handleProgressClick(event)} + >
+ style="width: {percentage}" + /> {#each customEvents as event}
+ {event.position};" + /> {/each}
@@ -365,7 +275,8 @@ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" - height="16"> + height="16" + > + 12.4928-30.16704l0-512q0-17.67424-12.4928-30.16704t-30.16704-12.4928z" + /> {:else} + height="16" + > + 512l-388.66944-233.32864 0 466.65728z" + /> {/if} @@ -401,7 +315,8 @@ {/each} @@ -409,7 +324,8 @@ id="skip" bind:checked={skipInactive} disabled={speedState === 'skipping'} - label="skip inactive" /> + label="skip inactive" + />
{/if} + + diff --git a/packages/rrweb-player/src/Player.svelte b/packages/rrweb-player/src/Player.svelte index 9e826ab199..5e5875b813 100644 --- a/packages/rrweb-player/src/Player.svelte +++ b/packages/rrweb-player/src/Player.svelte @@ -1,7 +1,7 @@ +
+
+ {#if replayer} + toggleFullscreen()} + /> + {/if} +
+ - -
-
- {#if replayer} - toggleFullscreen()} /> - {/if} -
diff --git a/packages/rrweb-player/src/components/Switch.svelte b/packages/rrweb-player/src/components/Switch.svelte index 9aa6862401..14d9ae9f75 100644 --- a/packages/rrweb-player/src/components/Switch.svelte +++ b/packages/rrweb-player/src/components/Switch.svelte @@ -5,6 +5,12 @@ export let label: string; +
+ +
+ - -
- -
diff --git a/packages/rrweb-player/src/main.ts b/packages/rrweb-player/src/main.ts index 341e39aacc..40bc4d82e9 100644 --- a/packages/rrweb-player/src/main.ts +++ b/packages/rrweb-player/src/main.ts @@ -1,4 +1,4 @@ -import type { eventWithTime } from 'rrweb/typings/types'; +import type { eventWithTime } from '@sentry-internal/rrweb/typings/types'; import _Player from './Player.svelte'; type PlayerProps = { diff --git a/packages/rrweb-player/tsconfig.json b/packages/rrweb-player/tsconfig.json index 77db65da2f..418c3aa556 100644 --- a/packages/rrweb-player/tsconfig.json +++ b/packages/rrweb-player/tsconfig.json @@ -1,5 +1,5 @@ { "extends": "@tsconfig/svelte/tsconfig.json", "include": ["src/**/*"], - "exclude": ["node_modules/*", "__sapper__/*", "public/*"], -} \ No newline at end of file + "exclude": ["node_modules/*", "__sapper__/*", "public/*"] +} diff --git a/packages/rrweb-player/typings/index.d.ts b/packages/rrweb-player/typings/index.d.ts index 7412448170..33b46aa60a 100644 --- a/packages/rrweb-player/typings/index.d.ts +++ b/packages/rrweb-player/typings/index.d.ts @@ -1,5 +1,8 @@ -import { eventWithTime, playerConfig } from 'rrweb/typings/types'; -import { Replayer, mirror } from 'rrweb'; +import { + eventWithTime, + playerConfig, +} from '@sentry-internal/rrweb/typings/types'; +import { Replayer, mirror } from '@sentry-internal/rrweb'; import { SvelteComponent } from 'svelte'; export type RRwebPlayerOptions = { diff --git a/packages/rrweb-snapshot/LICENSE b/packages/rrweb-snapshot/LICENSE new file mode 100644 index 0000000000..d11896ba11 --- /dev/null +++ b/packages/rrweb-snapshot/LICENSE @@ -0,0 +1,14 @@ +Copyright (c) 2023 Sentry (https://sentry.io) and individual contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/rrweb-snapshot/package.json b/packages/rrweb-snapshot/package.json index d66d3519ce..581047c23e 100644 --- a/packages/rrweb-snapshot/package.json +++ b/packages/rrweb-snapshot/package.json @@ -1,5 +1,5 @@ { - "name": "rrweb-snapshot", + "name": "@sentry-internal/rrweb-snapshot", "version": "1.1.14", "description": "rrweb's component to take a snapshot of DOM, aka DOM serializer", "scripts": { @@ -11,7 +11,8 @@ "bundle:es-only": "cross-env ES_ONLY=true rollup --config", "dev": "yarn bundle:es-only --watch", "typings": "tsc -d --declarationDir typings", - "prepublish": "npm run typings && npm run bundle" + "prepublish": "npm run typings && npm run bundle", + "build:tarball": "npm pack" }, "repository": { "type": "git", diff --git a/packages/rrweb-snapshot/src/rebuild.ts b/packages/rrweb-snapshot/src/rebuild.ts index 847cdd0698..d4ec23f55b 100644 --- a/packages/rrweb-snapshot/src/rebuild.ts +++ b/packages/rrweb-snapshot/src/rebuild.ts @@ -215,7 +215,10 @@ function buildNode( n.attributes.rr_dataURL ) { // backup original img srcset - node.setAttribute('rrweb-original-srcset', n.attributes.srcset as string); + node.setAttribute( + 'rrweb-original-srcset', + n.attributes.srcset as string, + ); } else { node.setAttribute(name, value); } diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index 10948ed4f3..a110517105 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -300,7 +300,10 @@ export function needMaskingText( } if (node.nodeType === node.ELEMENT_NODE) { if (unmaskTextSelector) { - if ((node as HTMLElement).matches(unmaskTextSelector) || (node as HTMLElement).closest(unmaskTextSelector)) { + if ( + (node as HTMLElement).matches(unmaskTextSelector) || + (node as HTMLElement).closest(unmaskTextSelector) + ) { return false; } } @@ -327,14 +330,29 @@ export function needMaskingText( return true; } } - return needMaskingText(node.parentNode, maskTextClass, maskTextSelector, unmaskTextSelector); + return needMaskingText( + node.parentNode, + maskTextClass, + maskTextSelector, + unmaskTextSelector, + ); } if (node.nodeType === node.TEXT_NODE) { // check parent node since text node do not have class name - return needMaskingText(node.parentNode, maskTextClass, maskTextSelector, unmaskTextSelector); + return needMaskingText( + node.parentNode, + maskTextClass, + maskTextSelector, + unmaskTextSelector, + ); } - return needMaskingText(node.parentNode, maskTextClass, maskTextSelector, unmaskTextSelector); + return needMaskingText( + node.parentNode, + maskTextClass, + maskTextSelector, + unmaskTextSelector, + ); } // https://stackoverflow.com/a/36155560 @@ -462,7 +480,7 @@ function serializeNode( n as HTMLElement, blockClass, blockSelector, - unblockSelector + unblockSelector, ); const tagName = getValidTagName(n as HTMLElement); let attributes: attributes = {}; @@ -681,7 +699,12 @@ function serializeNode( if ( !isStyle && !isScript && - needMaskingText(n, maskTextClass, maskTextSelector, unmaskTextSelector) && + needMaskingText( + n, + maskTextClass, + maskTextSelector, + unmaskTextSelector, + ) && textContent ) { textContent = maskTextFn diff --git a/packages/rrweb-snapshot/src/utils.ts b/packages/rrweb-snapshot/src/utils.ts index 505516dbee..15adc27590 100644 --- a/packages/rrweb-snapshot/src/utils.ts +++ b/packages/rrweb-snapshot/src/utils.ts @@ -20,8 +20,8 @@ export function maskInputValue({ maskInputFn, }: { input: HTMLElement; - maskInputSelector: string|null; - unmaskInputSelector: string|null; + maskInputSelector: string | null; + unmaskInputSelector: string | null; maskInputOptions: MaskInputOptions; tagName: string; type: string | number | boolean | null; diff --git a/packages/rrweb/LICENSE b/packages/rrweb/LICENSE new file mode 100644 index 0000000000..d11896ba11 --- /dev/null +++ b/packages/rrweb/LICENSE @@ -0,0 +1,14 @@ +Copyright (c) 2023 Sentry (https://sentry.io) and individual contributors. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/rrweb/package.json b/packages/rrweb/package.json index 145dd1b6f9..d4ef31c5ed 100644 --- a/packages/rrweb/package.json +++ b/packages/rrweb/package.json @@ -1,5 +1,5 @@ { - "name": "rrweb", + "name": "@sentry-internal/rrweb", "version": "1.1.3", "description": "record and replay the web", "scripts": { @@ -14,7 +14,8 @@ "bundle": "rollup --config", "typings": "tsc -d --declarationDir typings", "check-types": "tsc -noEmit", - "prepublish": "npm run typings && npm run bundle" + "prepublish": "npm run typings && npm run bundle", + "build:tarball": "npm pack" }, "repository": { "type": "git", @@ -79,6 +80,6 @@ "base64-arraybuffer": "^1.0.1", "fflate": "^0.4.4", "mitt": "^1.1.3", - "rrweb-snapshot": "^1.1.14" + "@sentry-internal/rrweb-snapshot": "^1.1.14" } } diff --git a/packages/rrweb/src/packer/unpack.ts b/packages/rrweb/src/packer/unpack.ts index 9211d7b593..8433bc68d1 100644 --- a/packages/rrweb/src/packer/unpack.ts +++ b/packages/rrweb/src/packer/unpack.ts @@ -16,7 +16,7 @@ export const unpack: UnpackFn = (raw: string) => { } try { const e: eventWithTimeAndPacker = JSON.parse( - strFromU8(unzlibSync(strToU8(raw, true))) + strFromU8(unzlibSync(strToU8(raw, true))), ); if (e.v === MARK) { return e; diff --git a/packages/rrweb/src/record/iframe-manager.ts b/packages/rrweb/src/record/iframe-manager.ts index 1825c1786f..21bbe97617 100644 --- a/packages/rrweb/src/record/iframe-manager.ts +++ b/packages/rrweb/src/record/iframe-manager.ts @@ -1,4 +1,4 @@ -import { serializedNodeWithId, INode } from 'rrweb-snapshot'; +import { serializedNodeWithId, INode } from '@sentry-internal/rrweb-snapshot'; import { mutationCallBack } from '../types'; export class IframeManager { diff --git a/packages/rrweb/src/record/index.ts b/packages/rrweb/src/record/index.ts index 210b0c89cd..0073f91dcb 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -1,4 +1,8 @@ -import { snapshot, MaskInputOptions, SlimDOMOptions } from 'rrweb-snapshot'; +import { + snapshot, + MaskInputOptions, + SlimDOMOptions, +} from '@sentry-internal/rrweb-snapshot'; import { initObservers, mutationBuffers } from './observer'; import { on, @@ -47,7 +51,7 @@ function record( blockSelector = null, unblockSelector = null, ignoreClass = 'rr-ignore', - ignoreSelector =null, + ignoreSelector = null, maskTextClass = 'rr-mask', maskTextSelector = null, maskInputSelector = null, diff --git a/packages/rrweb/src/record/mutation.ts b/packages/rrweb/src/record/mutation.ts index bcfea6ca6e..7d3b16edf4 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -6,7 +6,7 @@ import { isShadowRoot, needMaskingText, maskInputValue, -} from 'rrweb-snapshot'; +} from '@sentry-internal/rrweb-snapshot'; import { mutationRecord, textCursor, @@ -459,7 +459,7 @@ export default class MutationBuffer { m.target, this.maskTextClass, this.maskTextSelector, - this.unmaskTextSelector + this.unmaskTextSelector, ) && value ? this.maskTextFn ? this.maskTextFn(value) diff --git a/packages/rrweb/src/record/observer.ts b/packages/rrweb/src/record/observer.ts index f740ebebf3..4045e6e811 100644 --- a/packages/rrweb/src/record/observer.ts +++ b/packages/rrweb/src/record/observer.ts @@ -1,4 +1,8 @@ -import { INode, MaskInputOptions, maskInputValue } from 'rrweb-snapshot'; +import { + INode, + MaskInputOptions, + maskInputValue, +} from '@sentry-internal/rrweb-snapshot'; import { FontFaceSet } from 'css-font-loading-module'; import { throttle, @@ -352,7 +356,10 @@ function initInputObserver({ return; } const type: string | undefined = (target as HTMLInputElement).type; - if ((target as HTMLElement).classList.contains(ignoreClass) || (ignoreSelector && (target as HTMLElement).matches(ignoreSelector))) { + if ( + (target as HTMLElement).classList.contains(ignoreClass) || + (ignoreSelector && (target as HTMLElement).matches(ignoreSelector)) + ) { return; } let text = (target as HTMLInputElement).value; @@ -366,7 +373,7 @@ function initInputObserver({ maskInputOptions[type as keyof MaskInputOptions] ) { text = maskInputValue({ - input: (target as HTMLElement), + input: target as HTMLElement, maskInputOptions, maskInputSelector, unmaskInputSelector, diff --git a/packages/rrweb/src/record/observers/canvas/2d.ts b/packages/rrweb/src/record/observers/canvas/2d.ts index dd63469b1e..f9a51b0481 100644 --- a/packages/rrweb/src/record/observers/canvas/2d.ts +++ b/packages/rrweb/src/record/observers/canvas/2d.ts @@ -1,4 +1,4 @@ -import { INode } from 'rrweb-snapshot'; +import { INode } from '@sentry-internal/rrweb-snapshot'; import { blockClass, CanvasContext, diff --git a/packages/rrweb/src/record/observers/canvas/canvas-manager.ts b/packages/rrweb/src/record/observers/canvas/canvas-manager.ts index a266e5fb73..0c89f56585 100644 --- a/packages/rrweb/src/record/observers/canvas/canvas-manager.ts +++ b/packages/rrweb/src/record/observers/canvas/canvas-manager.ts @@ -1,4 +1,4 @@ -import { INode } from 'rrweb-snapshot'; +import { INode } from '@sentry-internal/rrweb-snapshot'; import { blockClass, canvasManagerMutationCallback, diff --git a/packages/rrweb/src/record/observers/canvas/canvas.ts b/packages/rrweb/src/record/observers/canvas/canvas.ts index 437af7d5f3..452bed9032 100644 --- a/packages/rrweb/src/record/observers/canvas/canvas.ts +++ b/packages/rrweb/src/record/observers/canvas/canvas.ts @@ -1,4 +1,4 @@ -import { INode, ICanvas } from 'rrweb-snapshot'; +import { INode, ICanvas } from '@sentry-internal/rrweb-snapshot'; import { blockClass, IWindow, listenerHandler } from '../../../types'; import { isBlocked, patch } from '../../../utils'; diff --git a/packages/rrweb/src/record/observers/canvas/webgl.ts b/packages/rrweb/src/record/observers/canvas/webgl.ts index 45b03928f3..bb04acd909 100644 --- a/packages/rrweb/src/record/observers/canvas/webgl.ts +++ b/packages/rrweb/src/record/observers/canvas/webgl.ts @@ -1,4 +1,4 @@ -import { INode } from 'rrweb-snapshot'; +import { INode } from '@sentry-internal/rrweb-snapshot'; import { blockClass, CanvasContext, diff --git a/packages/rrweb/src/replay/index.ts b/packages/rrweb/src/replay/index.ts index df567b3ae1..0573a11c02 100644 --- a/packages/rrweb/src/replay/index.ts +++ b/packages/rrweb/src/replay/index.ts @@ -5,7 +5,7 @@ import { NodeType, BuildCache, createCache, -} from 'rrweb-snapshot'; +} from '@sentry-internal/rrweb-snapshot'; import * as mittProxy from 'mitt'; import { polyfill as smoothscrollPolyfill } from './smoothscroll'; import { Timer } from './timer'; diff --git a/packages/rrweb/src/replay/virtual-styles.ts b/packages/rrweb/src/replay/virtual-styles.ts index f850df27c9..51a0772879 100644 --- a/packages/rrweb/src/replay/virtual-styles.ts +++ b/packages/rrweb/src/replay/virtual-styles.ts @@ -1,4 +1,4 @@ -import { INode } from 'rrweb-snapshot'; +import { INode } from '@sentry-internal/rrweb-snapshot'; export enum StyleRuleType { Insert, diff --git a/packages/rrweb/src/types.ts b/packages/rrweb/src/types.ts index 43cec3acff..2c08c103c9 100644 --- a/packages/rrweb/src/types.ts +++ b/packages/rrweb/src/types.ts @@ -6,7 +6,7 @@ import { SlimDOMOptions, MaskInputFn, MaskTextFn, -} from 'rrweb-snapshot'; +} from '@sentry-internal/rrweb-snapshot'; import { PackFn, UnpackFn } from './packer/base'; import { IframeManager } from './record/iframe-manager'; import { ShadowDomManager } from './record/shadow-dom-manager'; diff --git a/packages/rrweb/src/utils.ts b/packages/rrweb/src/utils.ts index 91376444ef..f21a091a7f 100644 --- a/packages/rrweb/src/utils.ts +++ b/packages/rrweb/src/utils.ts @@ -21,7 +21,7 @@ import { serializedNodeWithId, NodeType, isShadowRoot, -} from 'rrweb-snapshot'; +} from '@sentry-internal/rrweb-snapshot'; export function on( type: string, diff --git a/packages/rrweb/test/events/ordering.ts b/packages/rrweb/test/events/ordering.ts index 083c687011..76d916b1ca 100644 --- a/packages/rrweb/test/events/ordering.ts +++ b/packages/rrweb/test/events/ordering.ts @@ -80,7 +80,7 @@ const events: eventWithTime[] = [ { id: 102, value: 'Intermediate - incorrect', - } + }, ], source: IncrementalSource.Mutation, removes: [], @@ -97,7 +97,7 @@ const events: eventWithTime[] = [ { id: 102, value: 'Final - correct', - } + }, ], source: IncrementalSource.Mutation, removes: [], diff --git a/packages/rrweb/test/integration.test.ts b/packages/rrweb/test/integration.test.ts index 6999e3caee..89ef1993d1 100644 --- a/packages/rrweb/test/integration.test.ts +++ b/packages/rrweb/test/integration.test.ts @@ -11,7 +11,7 @@ import { replaceLast, } from './utils'; import { recordOptions, eventWithTime, EventType } from '../src/types'; -import { visitSnapshot, NodeType } from 'rrweb-snapshot'; +import { visitSnapshot, NodeType } from '@sentry-internal/rrweb-snapshot'; interface ISuite { server: http.Server; diff --git a/packages/rrweb/test/record/webgl.test.ts b/packages/rrweb/test/record/webgl.test.ts index 17442669d4..b0436b93eb 100644 --- a/packages/rrweb/test/record/webgl.test.ts +++ b/packages/rrweb/test/record/webgl.test.ts @@ -12,7 +12,7 @@ import { CanvasContext, } from '../../src/types'; import { assertSnapshot, launchPuppeteer, waitForRAF } from '../utils'; -import { ICanvas } from 'rrweb-snapshot'; +import { ICanvas } from '@sentry-internal/rrweb-snapshot'; interface ISuite { code: string; diff --git a/packages/rrweb/test/utils.ts b/packages/rrweb/test/utils.ts index 69e72cd998..e7a9aa5619 100644 --- a/packages/rrweb/test/utils.ts +++ b/packages/rrweb/test/utils.ts @@ -1,4 +1,4 @@ -import { NodeType } from 'rrweb-snapshot'; +import { NodeType } from '@sentry-internal/rrweb-snapshot'; import { EventType, IncrementalSource, diff --git a/packages/rrweb/typings/record/iframe-manager.d.ts b/packages/rrweb/typings/record/iframe-manager.d.ts index 4300a7abce..a9d76ad9cc 100644 --- a/packages/rrweb/typings/record/iframe-manager.d.ts +++ b/packages/rrweb/typings/record/iframe-manager.d.ts @@ -1,4 +1,4 @@ -import { serializedNodeWithId, INode } from 'rrweb-snapshot'; +import { serializedNodeWithId, INode } from '@sentry-internal/rrweb-snapshot'; import { mutationCallBack } from '../types'; export declare class IframeManager { private iframes; diff --git a/packages/rrweb/typings/replay/virtual-styles.d.ts b/packages/rrweb/typings/replay/virtual-styles.d.ts index 11ebf52d1b..d97cf711e6 100644 --- a/packages/rrweb/typings/replay/virtual-styles.d.ts +++ b/packages/rrweb/typings/replay/virtual-styles.d.ts @@ -1,4 +1,4 @@ -import { INode } from 'rrweb-snapshot'; +import { INode } from '@sentry-internal/rrweb-snapshot'; export declare enum StyleRuleType { Insert = 0, Remove = 1, diff --git a/packages/rrweb/typings/types.d.ts b/packages/rrweb/typings/types.d.ts index bf529fa294..56d05e4ef2 100644 --- a/packages/rrweb/typings/types.d.ts +++ b/packages/rrweb/typings/types.d.ts @@ -1,4 +1,4 @@ -import { serializedNodeWithId, idNodeMap, INode, MaskInputOptions, SlimDOMOptions, MaskInputFn, MaskTextFn } from 'rrweb-snapshot'; +import { serializedNodeWithId, idNodeMap, INode, MaskInputOptions, SlimDOMOptions, MaskInputFn, MaskTextFn } from '@sentry-internal/rrweb-snapshot'; import { PackFn, UnpackFn } from './packer/base'; import { IframeManager } from './record/iframe-manager'; import { ShadowDomManager } from './record/shadow-dom-manager'; diff --git a/packages/rrweb/typings/utils.d.ts b/packages/rrweb/typings/utils.d.ts index bdd5d741d2..1b7275be55 100644 --- a/packages/rrweb/typings/utils.d.ts +++ b/packages/rrweb/typings/utils.d.ts @@ -1,5 +1,5 @@ import { Mirror, throttleOptions, listenerHandler, hookResetter, blockClass, addedNodeMutation, removedNodeMutation, textMutation, attributeMutation, mutationData, scrollData, inputData, DocumentDimension, IWindow } from './types'; -import { INode, serializedNodeWithId } from 'rrweb-snapshot'; +import { INode, serializedNodeWithId } from '@sentry-internal/rrweb-snapshot'; export declare function on(type: string, fn: EventListenerOrEventListenerObject, target?: Document | IWindow): listenerHandler; export declare function createMirror(): Mirror; export declare let _mirror: Mirror; diff --git a/scripts/craft-pre-release.sh b/scripts/craft-pre-release.sh new file mode 100755 index 0000000000..75df3de94e --- /dev/null +++ b/scripts/craft-pre-release.sh @@ -0,0 +1,20 @@ +#!/bin/bash +set -eux + +# Move to the project root +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd $SCRIPT_DIR/.. +OLD_VERSION="${1}" +NEW_VERSION="${2}" + +# Do not tag and commit changes made by "npm version" +export npm_config_git_tag_version=false + +yarn install --frozen-lockfile +# --force-publish - force publish all packages, this will skip the lerna changed check for changed packages and forces a package that didn't have a git diff change to be updated. +# --exact - specify updated dependencies in updated packages exactly (with no punctuation), instead of as semver compatible (with a ^). +# --no-git-tag-version - don't commit changes to package.json files and don't tag the release. +# --no-push - don't push committed and tagged changes. +# --include-merged-tags - include tags from merged branches when detecting changed packages. +# --yes - skip all confirmation prompts +yarn lerna version --force-publish --exact --no-git-tag-version --no-push --include-merged-tags --yes "${NEW_VERSION}"