* feat: add rrweb web-extension package * refactor: make the extension suitable for manifest v3 * update tsconfig.json * use version_name rather than recorder_version in manifest.json * update manifest.json * enable to keep recording after changing tabs * enable to record between tabs and urls * fix CI error * try to fix CI error * feat: add pause and resume buttons * feat: add a link to new session after recording * improve session list * refactor: migrate session storage from chrome local storage to indexedDB * feat: add pagination to session list * fix: multiple recorders are started after pausing and resuming process * fix: can't stop recording on firefox browser * update type import of 'eventWithTime' * fix CI error * doc: add readme * Apply suggestions from Justin's code review Co-authored-by: Justin Halsall <Juice10@users.noreply.github.com> * refactor: make use of webNavigation API to implement recording consistent during page navigation * fix firefox compatibility issue and add title to pages * add mouseleave listener to enhance the recording liability * fix firefox compatibility issue and improve the experience of recording resume after closing tabs * update tsconfig * upgrade vite-plugin-web-extension config to fix some bugs on facebook web page * update import links * refactor: cross tab recording mechanism apply Justin's suggestion * refactor: slipt util/index.ts into multiple files * implement cross-origin iframe recording * fix: regression of issue: ShadowHost can't be a string (issue 941) * refactor shadow dom recording to make tests cover key code * Apply formatting changes * increase the node memory limitation to avoid CI failure * Create lovely-pears-cross.md * Apply formatting changes * Update packages/web-extension/package.json * Update .changeset/lovely-pears-cross.md * update change logs * delete duplicated property --------- Co-authored-by: Justin Halsall <Juice10@users.noreply.github.com>
73 lines
1.8 KiB
TypeScript
73 lines
1.8 KiB
TypeScript
import { record } from 'rrweb';
|
|
import type { recordOptions } from 'rrweb/typings/types';
|
|
import type { eventWithTime } from '@rrweb/types';
|
|
import { MessageName, RecordStartedMessage } from '~/types';
|
|
import { isInCrossOriginIFrame } from '~/utils';
|
|
|
|
/**
|
|
* This script is injected into both main page and cross-origin IFrames through <script> tags.
|
|
*/
|
|
|
|
const events: eventWithTime[] = [];
|
|
let stopFn: (() => void) | null = null;
|
|
|
|
function startRecord(config: recordOptions<eventWithTime>) {
|
|
events.length = 0;
|
|
stopFn =
|
|
record({
|
|
emit: (event) => {
|
|
events.push(event);
|
|
postMessage({
|
|
message: MessageName.EmitEvent,
|
|
event,
|
|
});
|
|
},
|
|
...config,
|
|
}) || null;
|
|
postMessage({
|
|
message: MessageName.RecordStarted,
|
|
startTimestamp: Date.now(),
|
|
} as RecordStartedMessage);
|
|
}
|
|
|
|
const messageHandler = (
|
|
event: MessageEvent<{
|
|
message: MessageName;
|
|
config?: recordOptions<eventWithTime>;
|
|
}>,
|
|
) => {
|
|
if (event.source !== window) return;
|
|
const data = event.data;
|
|
const eventHandler = {
|
|
[MessageName.StartRecord]: () => {
|
|
startRecord(data.config || {});
|
|
},
|
|
[MessageName.StopRecord]: () => {
|
|
if (stopFn) stopFn();
|
|
postMessage({
|
|
message: MessageName.RecordStopped,
|
|
events,
|
|
endTimestamp: Date.now(),
|
|
});
|
|
window.removeEventListener('message', messageHandler);
|
|
},
|
|
} as Record<MessageName, () => void>;
|
|
if (eventHandler[data.message]) eventHandler[data.message]();
|
|
};
|
|
|
|
/**
|
|
* Only post message in the main page.
|
|
*/
|
|
function postMessage(message: unknown) {
|
|
if (!isInCrossOriginIFrame()) window.postMessage(message, location.origin);
|
|
}
|
|
|
|
window.addEventListener('message', messageHandler);
|
|
|
|
window.postMessage(
|
|
{
|
|
message: MessageName.RecordScriptReady,
|
|
},
|
|
location.origin,
|
|
);
|