impl #81 custom event

This is the record side impl of custom event, according to the
issue, we may also add first-class support for the custom event
tag like display color labels in the replayer-ui.
This commit is contained in:
Yanzhen Yu
2026-04-01 12:00:00 +08:00
parent 469dbd5dee
commit d92a946926
5 changed files with 139 additions and 5 deletions

View File

@@ -1,6 +1,11 @@
import record from './record';
import record, { addCustomEvent } from './record';
import { Replayer } from './replay';
import { mirror } from './utils';
export { EventType, IncrementalSource, MouseInteractions, ReplayerEvents } from './types'
export { record, Replayer, mirror };
export {
EventType,
IncrementalSource,
MouseInteractions,
ReplayerEvents,
} from './types';
export { record, addCustomEvent, Replayer, mirror };

View File

@@ -17,6 +17,23 @@ function wrapEvent(e: event): eventWithTime {
};
}
let wrappedEmit!: (e: eventWithTime, isCheckout?: boolean) => void;
export function addCustomEvent<T>(tag: string, payload: T) {
if (!wrappedEmit) {
throw new Error('please add custom event after start recording');
}
wrappedEmit(
wrapEvent({
type: EventType.Custom,
data: {
tag,
payload,
},
}),
);
}
function record(options: recordOptions = {}): listenerHandler | undefined {
const {
emit,
@@ -34,7 +51,7 @@ function record(options: recordOptions = {}): listenerHandler | undefined {
let lastFullSnapshotEvent: eventWithTime;
let incrementalSnapshotCount = 0;
const wrappedEmit = (e: eventWithTime, isCheckout?: boolean) => {
wrappedEmit = (e: eventWithTime, isCheckout?: boolean) => {
emit(e, isCheckout);
if (e.type === EventType.FullSnapshot) {
lastFullSnapshotEvent = e;

View File

@@ -6,6 +6,7 @@ export enum EventType {
FullSnapshot,
IncrementalSnapshot,
Meta,
Custom,
}
export type domContentLoadedEvent = {
@@ -43,6 +44,14 @@ export type metaEvent = {
};
};
export type customEvent<T = unknown> = {
type: EventType.Custom;
data: {
tag: string;
payload: T;
};
};
export enum IncrementalSource {
Mutation,
MouseMove,
@@ -91,7 +100,8 @@ export type event =
| loadedEvent
| fullSnapshotEvent
| incrementalSnapshotEvent
| metaEvent;
| metaEvent
| customEvent;
export type eventWithTime = event & {
timestamp: number;

View File

@@ -245,3 +245,89 @@ exports[`async-checkout 1`] = `
}
]"
`;
exports[`custom-event 1`] = `
"[
{
\\"type\\": 4,
\\"data\\": {
\\"href\\": \\"about:blank\\",
\\"width\\": 800,
\\"height\\": 600
}
},
{
\\"type\\": 2,
\\"data\\": {
\\"node\\": {
\\"type\\": 0,
\\"childNodes\\": [
{
\\"type\\": 2,
\\"tagName\\": \\"html\\",
\\"attributes\\": {},
\\"childNodes\\": [
{
\\"type\\": 2,
\\"tagName\\": \\"head\\",
\\"attributes\\": {},
\\"childNodes\\": [],
\\"id\\": 3
},
{
\\"type\\": 2,
\\"tagName\\": \\"body\\",
\\"attributes\\": {},
\\"childNodes\\": [
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n \\",
\\"id\\": 5
},
{
\\"type\\": 2,
\\"tagName\\": \\"input\\",
\\"attributes\\": {
\\"type\\": \\"text\\"
},
\\"childNodes\\": [],
\\"id\\": 6
},
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n \\\\n \\\\n \\",
\\"id\\": 7
}
],
\\"id\\": 4
}
],
\\"id\\": 2
}
],
\\"id\\": 1
},
\\"initialOffset\\": {
\\"left\\": 0,
\\"top\\": 0
}
}
},
{
\\"type\\": 5,
\\"data\\": {
\\"tag\\": \\"tag1\\",
\\"payload\\": 1
}
},
{
\\"type\\": 5,
\\"data\\": {
\\"tag\\": \\"tag2\\",
\\"payload\\": {
\\"a\\": \\"b\\"
}
}
}
]"
`;

View File

@@ -23,6 +23,7 @@ interface ISuite extends Suite {
interface IWindow extends Window {
rrweb: {
record: (options: recordOptions) => listenerHandler | undefined;
addCustomEvent<T>(tag: string, payload: T): void;
};
emit: (e: eventWithTime) => undefined;
}
@@ -180,4 +181,19 @@ describe('record', function(this: ISuite) {
await this.page.waitFor(50);
assertSnapshot(this.events, __filename, 'async-checkout');
});
it('can add custom event', async () => {
await this.page.evaluate(() => {
const { record, addCustomEvent } = (window as IWindow).rrweb;
record({
emit: (window as IWindow).emit,
});
addCustomEvent<number>('tag1', 1);
addCustomEvent<{ a: string }>('tag2', {
a: 'b',
});
});
await this.page.waitFor(50);
assertSnapshot(this.events, __filename, 'custom-event');
});
});