- Add export functionality to SessionList and Player pages
- Add new utility modules: dataOperations, format, path, settings
- Update manifest with export and download permissions
- Enhance storage utility with new data operations
- Add various test scripts and documentation files
- Add export button and exportRecording() function
- Fix button initialization timing with loop check
- Change events to global window.events for export access
- Update all references to use window.events
- Fix stopRecording to enable controls even if replay fails
- Enable all control buttons (play, speed, export) after recording
🎯 Key improvements:
- Users can now export recorded sessions as JSON files
- All buttons now work correctly after recording stops
- Proper error handling for replay initialization
- User-selectable save paths for exported files
📁 Modified: index.html
* Fix a security hole in #1787 found by Arun Murugesan:
"The workflow .github/workflows/eslint-check.yml contained a critical "pwn request" vulnerability that allows any GitHub user to execute arbitrary code with access to repository secrets by opening a pull request."
See https://github.com/preactjs/compressed-size-action/issues/54 for why that action shouldn't be used with pull_request_target
This change in this PR drops compressed-size-action in favour of executing the steps ourselves in two workflows, one which produces the size artifact, and the other which reads the artifact has the permissions to write the message back to the original PR (which is in a third party repo)
* The annotate action also needed pull-requests: write permission (fixes failing run 'ESLint Annotation')
* ci(bundle-size): extract bundle size scripts and simplify workflow
- Add `.github/scripts/measure-bundle-sizes.js` and
`render-bundle-size-comment.js` to replace inline node scripts
embedded in workflow YAML, improving readability and reusability
- Refactor `eslint-check.yml` to use the new script files and fix
checkout steps to handle both PR and non-PR triggers correctly
- Refactor `pr-checks-privileged.yml` to replace the large
`github-script` block with `render-bundle-size-comment.js` and
the `marocchino/sticky-pull-request-comment` action; remove the
now-unnecessary `pr_number.txt` artifact by reading the PR number
directly from the workflow_run event
- Pin `ataylorme/eslint-annotate-action` to a specific commit SHA
- Add `actions: read` permission where needed for artifact downloads
* ci: add fork PR support and harden workflow
- Look up PR number via API when workflow_run.pull_requests is empty
(GitHub leaves it empty for fork PRs), falling back gracefully
- Use head SHA instead of branch name for PR checkout to avoid TOCTOU
- Fix formatSignedSize to produce +0 instead of -0 for zero values
- Gate comment steps on successful PR number lookup
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Eoghan Murray <eoghan@getthere.ie>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: revamp installation docs for esm and umd
Document recommended install paths across the main guides and package
READMEs for rrweb, @rrweb/all, @rrweb/record, @rrweb/replay, and
rrweb-player.
Clarify three usage modes: bundler/npm, browser no-build with
import maps and +esm, and legacy UMD fallback.
* Apply suggestions from code review
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Apply formatting changes
* Apply suggestion from @eoghanmurray
Co-authored-by: Eoghan Murray <eoghan@getthere.ie>
* Apply formatting changes
* docs(all): streamline README usage section
Move the guide link next to the import example and remove the
duplicated Usage section to keep docs concise and easier to scan.
* docs(readme): update gzip size badges in zh-cn readme
* docs(plugins): update readme imports to scoped esm packages
Replace `rrweb` default imports and `rrweb.Replayer` usage with
`@rrweb/record` `record` and `@rrweb/replay` `Replayer` in plugin
usage examples.
Also update canvas WebRTC plugin imports to scoped `@rrweb/*`
package names to keep docs aligned with current package structure.
* docs: update docs to prefer scoped esm packages
replace `rrweb` default import examples with `@rrweb/record` and
`@rrweb/replay` across recipes and guides in en/zh-CN.
clarify package selection for new integrations, add `@rrweb/all`
convenience guidance, and refresh CDN/style import snippets for ESM and legacy UMD compatibility.
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Eoghan Murray <eoghan@getthere.ie>
* Don't allow video autoplay to automatically unfreeze page. If it's a 'real' playback, there should be a mount or a keyboard event which will serve to unfreeze the page. Also add other non-user events to the list (we really should have an `isUserEvent` function)
* Apply formatting changes
* Create a new `umd` folder alongside `dist` for output of UMD files with a plain `.js` instead of `.cjs` extension, as the latter won't be served with the correct mime type by jsdelivr
- #1687 (just rename `.cjs` to `.js`) was rejected due to the the 'dual package hazard' [1], and produces a warning when run through publint.dev (which was the original motivation for changing to \.cjs)
- jsdelivr won't be serving `.cjs` with the correct mime type: https://github.com/jsdelivr/jsdelivr/issues/18584
[1] https://nodejs.org/en/learn/modules/publishing-a-package#the-dual-package-hazard
* Update to point to alpha.19 as presumably that's when the umd folder will be available after the changes in this PR
* Apply formatting changes
* Don't try to create the same directory twice (was failing on packages/packer/umd)
* Create thirty-shirts-grow.md
* Revert something that shouldn't have gotten into the UMD branch folder
* Apply formatting changes
* Update vite.config.default.ts
* Apply formatting changes
* build: include umd builds in published packages
Add umd directory to the files array in package.json for all packages to include UMD builds in npm publications. Also update .gitignore to exclude
umd folders from version control.
* Docs: point to correct file
* Remove unused code
* docs: update rrweb cdn urls to umd bundles
Align README and guide examples with published UMD file locations for
rrweb, @rrweb/record, and @rrweb/replay.
Update versioned rrweb script examples from 2.0.0-alpha.19 to
2.0.0-alpha.21 in both English and Chinese guides.
* build(all): include umd folder in package files
---------
Co-authored-by: eoghanmurray <eoghanmurray@users.noreply.github.com>
Co-authored-by: Justin Halsall <Juice10@users.noreply.github.com>
* Update filesize badges (might need further evolution before 2.0.0)
* Don't run full CI/CD when only .md docs have changed in the PR
- move eslint checks into their own file so they can also ignore .md changes
- prettier checks don't need the same perms as eslint, so we can demote pull_request_target -> pull_request
* Add empty changeset
* Implement the bundle size change originally originally added in #1784 - adding here also to show how the conflicts would resolve
* Update .github/workflows/eslint-check.yml
---------
Co-authored-by: Justin Halsall <Juice10@users.noreply.github.com>
* chore: maintain CSS output file name in vite@6.0.1
Without this change, build would fail because the produced stylesheet assumes
the `package.json['name']` i.e., `styles/rrweb.css`. To maintain the existing
behavior, these changes are required.
See https://vite.dev/guide/migration.html#customize-css-output-file-name-in-library-mode
* build(rrvideo): upgrade playwright from 1.32.1 to 1.56.1
Update playwright dependency to latest version and refactor test execution options to use a shared configuration with increased timeout for stability.
* debug(rrvideo): add comprehensive logging to video transformation process
Add detailed console.log statements throughout the transformToVideo function to track execution flow and debug potential issues. Logging covers browser launch, context creation, page navigation, replay progress, and video file operations.
* ci(rrvideo): install playwright browsers and improve test output visibility
- Add Playwright Chromium installation step to CI workflow
- Change test execution stdio from 'pipe' to 'inherit' for better debugging
* fix(rrvideo): prevent autoplay and manually start playback after event listeners
Set autoPlay to false in replayer configuration and manually call play() after all event listeners are attached. This ensures event handlers are properly registered before playback begins, preventing potential race conditions.
Also refactor test execution options to separate stdio configuration from timeout settings for better control over test output visibility.
* fix(rrvideo): add timeout and error handling to replay process
Add comprehensive error handling to prevent hanging during video transformation:
- Add 2-minute timeout for replay finish event
- Add console and error listeners for better debugging
- Improve promise chain with proper error catching
- Clear timeout on successful completion or error
This prevents the process from hanging indefinitely when the replay finish event never fires.
* fix(rrvideo): add error handling and restructure replayer initialization
Wrap replayer initialization in try-catch block to handle potential errors gracefully. Restructure Player instantiation to use rrwebPlayer directly instead of rrwebPlayer.Player, and move width/height into props object for correct API usage. On error, log to console and trigger onReplayFinish callback to prevent hanging state.
* build(umd): rename record and replay globals
Update UMD build globals for recorder and replayer and
refresh documentation accordingly.
BREAKING CHANGE: UMD global names changed to rrwebRecord
and rrwebReplay.
* fix(rrvideo): adjust replay timeout to duration
* docs: update rrweb-player CDN script path
* Update vite.config.default.ts
Co-authored-by: Eoghan Murray <eoghan@getthere.ie>
---------
Co-authored-by: Rui <rui@conti.sh>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Eoghan Murray <eoghan@getthere.ie>
* fix: improve nested CSS rule handling and add related tests
* fix: enhance null safety for nested CSS rules and add related tests
* Improve nested CSS rule handling and replayer handling
Updated the fix message to include replayer handling of missing rules.
---------
Co-authored-by: Justin Halsall <Juice10@users.noreply.github.com>
* build(rrvideo): upgrade playwright from 1.32.1 to 1.56.1
Update playwright dependency to latest version and refactor test execution options to use a shared configuration with increased timeout for stability.
* Prefer `includes` formulation for brevity and as it composes better (easier to understand) in longer boolean expressions with &&
* Noticed two different interpretations of `headMetaAuthorship` under slimDOMOptions; take the opportunity to cleanup and merge code
* `link[rel="modulepreload"]` doesn't require `as="script"` which is tied to rel="preload" only
* extract file extension properly when examining `rel="prefetch"` to disregard URL parameters correctly
Co-authored-by: Eoghan Murray <eoghan@getthere.ie>
* Remove cache consumption in release workflow.
* Tighten style-check.yml permissions
* Tighten permissions in test workflow that consumes cache.
* Use stricter permissions where possible
---------
Co-authored-by: Justin Halsall <Juice10@users.noreply.github.com>
Fixes a browser 'lock up' at record time due to a presence of large amounts of css in <style> elements, which are split over multiple text nodes, which triggers the new code added in #1437 (see that PR for full explanation of why this all exists). #1437 was not written with performance in mind as it was believed to be an edge case, but things like Grammarly browser extension (#1603) among other scenarios were triggering pathological behavior, some of which was solved in #1615.
See also https://github.com/rrweb-io/rrweb/pull/1640#issuecomment-2633505804 for further discussion.
* Fix the case when there are multiple matches and we end up not finding a unique one - just go with the best guess when there are many splits by looking at the previous chunk's size
* Also add '0px' -> '0' stylesheet normalization, which also fixes the sample problem in a different way
* Add new test and modify it so that it can trigger a failure in the absence of the '0px' normalization; there may be other unknown ways of triggering a similar bug, so ensure that the primary 'best guess' method doesn't suffer a regression
* Leverage the 'best guess' method so that we can quit after 100 iterations trying to find a unique substring; hopefully this bit along with the `iterLimit` already added will prevent any future pathological cases.
Failing example extracted from large files identified by Paul D'Ambra (Posthog) ... see comment from MartinWorkfully: https://github.com/PostHog/posthog-js/issues/1668
* postcss was introduced in #1458 for use within adaptCssForReplay
* #1600 fixes the main case where invalid css could be introduced when if valid css from the output of `sheet.cssRules` was split according to how it was split across text nodes of the <style>
* the guard introduced here is still useful as we likely in future will switch to capturing the raw stylesheet contents (both <style> and <link>), at which point we will be much less confident of getting valid css
Fix for #1575 where postcss was raising an exception
* adapt the entire CSS as a whole in one pass with postcss, rather than adapting each split part separately
* break up the postcss output again and assign to individual text nodes (kind of inverse of splitCssText at record side)
* impose an upper bound of 30 iterations on the substring searches to preempt possible pathological behavior
* add tests to demonstrate the scenario and prevent regression
More technical details:
* Fix algorithm; checks against `ix_end` within loop were incorrect when `ix_start` was bigger than zero.
* Fix that length check against wrong array was causing 'should record style mutations with multiple child nodes and replay them correctly' test to fail.
Note on last point: I haven't looked into things more deeply than that the test was complaining about missing .length after `replayer.pause(1000);`
* [chore] Cache yarn packages for CI
* Cache yarn in release.yml
* [chore] Update deprecated download artifact on CI (#1647)
* I'm merging even though ESLint is stlll failing in Github Actions as I believe it's running actions _without_ this PR applied yet
- it was working for me when the test was run in isolation (`-t` option), but when the entire cross-origin-iframes test was run, the change of iframe contents didn't seem to happen in time
* Add eslint rule to flag up me forgetting to camelCase - I'd say I introduced all the snake_cases that are fixed here
* Allow some dubious snake cases for now; we could examine again whether they can be converted to `camelCase['snake_var']` if we need to maintain backwards compatibility of output
* add ESLINT_USE_FLAT_CONFIG against eslint v8.57.0 in order to continue using the deprecated .eslintrc.js method
* refactor: improved tab recording to improve stability
* feat: enable to import session
* improve stability
* feat: enable to edit session name
* prevent duplicate rrweb player in the dev mode
* fix: remote CSS does not get rebuilt properly
This fixes an issue where inlined CSS from a remotely loaded `<link>` does not get applied properly due to object reference mutation.
* add changeset
* ci-cd on ubuntu-22.04 instead of latest
* keep mirror meta synced
- Fix bug where the right split point was not being picked for the 3rd section onwards
- Fix that it wasn't able to find a split when both halves were identical
- Add test to put splitCssText through it's paces with a large file
- Introduce a limit on the iteration which causes the 'efficiently' test to fail
- Fix poor 'crawling' performance in the 'matching' algorithm for large css texts - e.g. for a (doubled) benchmark.css, we were running `normalizeCssText` 9480 times before `k` got to the right place
- Further algorithm efficiency: need to take larger jumps; use the scaling factor to make better guess at how big a jump to make