Skip to content

Commit

Permalink
John/hig-1984-pull-in-rrweb-sequential-id-pr (#65)
Browse files Browse the repository at this point in the history
* Add sequential IDs

* rrweb-io/rrweb#840

* bump version
  • Loading branch information
John Pham authored Feb 22, 2022
1 parent d6143d2 commit 9f3fe95
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 18 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@highlight-run/rrweb",
"version": "1.1.11",
"version": "1.1.12",
"description": "record and replay the web",
"scripts": {
"test": "npm run bundle:browser && cross-env TS_NODE_CACHE=false TS_NODE_FILES=true mocha -r ts-node/register -r ignore-styles -r jsdom-global/register test/**.test.ts",
Expand Down
31 changes: 31 additions & 0 deletions src/plugins/sequential-id/record/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { RecordPlugin } from '../../../types';

export type SequentialIdOptions = {
key: string;
};

const defaultOptions: SequentialIdOptions = {
key: '_sid',
};

export const PLUGIN_NAME = 'rrweb/sequential-id@1';

export const getRecordSequentialIdPlugin: (
options?: Partial<SequentialIdOptions>,
) => RecordPlugin = (options) => {
const _options = options
? Object.assign({}, defaultOptions, options)
: defaultOptions;
let id = 0;

return {
name: PLUGIN_NAME,
eventProcessor(event) {
Object.assign(event, {
[_options.key]: ++id,
});
return event;
},
options: _options,
};
};
39 changes: 39 additions & 0 deletions src/plugins/sequential-id/replay/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { SequentialIdOptions } from '../record';
import { ReplayPlugin, eventWithTime } from '../../../types';

type Options = SequentialIdOptions & {
warnOnMissingId: boolean;
};

const defaultOptions: Options = {
key: '_sid',
warnOnMissingId: true,
};

export const getReplaySequentialIdPlugin: (
options?: Partial<Options>,
) => ReplayPlugin = (options) => {
const { key, warnOnMissingId } = options
? Object.assign({}, defaultOptions, options)
: defaultOptions;
let currentId = 1;

return {
handler(event: eventWithTime) {
if (key in event) {
const id = ((event as unknown) as Record<string, number>)[key];
if (id !== currentId) {
console.error(
`[sequential-id-plugin]: expect to get an id with value "${currentId}", but got "${id}"`,
);
} else {
currentId++;
}
} else if (warnOnMissingId) {
console.warn(
`[sequential-id-plugin]: failed to get id in key: "${key}"`,
);
}
},
};
};
43 changes: 28 additions & 15 deletions src/record/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,17 @@ function record<T = eventWithTime>(

let lastFullSnapshotEvent: eventWithTime;
let incrementalSnapshotCount = 0;
const eventProcessor = (e: eventWithTime): T => {
for (const plugin of plugins || []) {
if (plugin.eventProcessor) {
e = plugin.eventProcessor(e);
}
}
if (packFn) {
e = (packFn(e) as unknown) as eventWithTime;
}
return (e as unknown) as T;
};
wrappedEmit = (e: eventWithTime, isCheckout?: boolean) => {
if (
mutationBuffers[0]?.isFrozen() &&
Expand All @@ -136,7 +147,7 @@ function record<T = eventWithTime>(
mutationBuffers.forEach((buf) => buf.unfreeze());
}

emit(((packFn ? packFn(e) : e) as unknown) as T, isCheckout);
emit(eventProcessor(e), isCheckout);
if (e.type === EventType.FullSnapshot) {
lastFullSnapshotEvent = e;
incrementalSnapshotCount = 0;
Expand Down Expand Up @@ -417,20 +428,22 @@ function record<T = eventWithTime>(
shadowDomManager,
canvasManager,
plugins:
plugins?.map((p) => ({
observer: p.observer,
options: p.options,
callback: (payload: object) =>
wrappedEmit(
wrapEvent({
type: EventType.Plugin,
data: {
plugin: p.name,
payload,
},
}),
),
})) || [],
plugins
?.filter((p) => p.observer)
?.map((p) => ({
observer: p.observer!,
options: p.options,
callback: (payload: object) =>
wrappedEmit(
wrapEvent({
type: EventType.Plugin,
data: {
plugin: p.name,
payload,
},
}),
),
})) || [],
enableStrictPrivacy,
},
hooks,
Expand Down
3 changes: 2 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,8 @@ export type SamplingStrategy = Partial<{

export type RecordPlugin<TOptions = unknown> = {
name: string;
observer: (cb: Function, win: IWindow, options: TOptions) => listenerHandler;
observer?: (cb: Function, win: IWindow, options: TOptions) => listenerHandler;
eventProcessor?: <TExtend>(event: eventWithTime) => eventWithTime & TExtend;
options: TOptions;
};

Expand Down
6 changes: 5 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,11 @@ export function isBlocked(node: Node | null, blockClass: blockClass): boolean {
if (node.nodeType === node.ELEMENT_NODE) {
let needBlock = false;
if (typeof blockClass === 'string') {
needBlock = (node as HTMLElement).classList.contains(blockClass);
if ((node as HTMLElement).closest !== undefined) {
return (node as HTMLElement).closest('.' + blockClass) !== null;
} else {
needBlock = (node as HTMLElement).classList.contains(blockClass);
}
} else {
(node as HTMLElement).classList.forEach((className) => {
if (blockClass.test(className)) {
Expand Down

0 comments on commit 9f3fe95

Please sign in to comment.