Chore: Move most types from rrweb to @rrweb/types package (#1031)

* Chore: Add move most types from rrweb to @rrweb/types package

* Split off type imports

* Split off type import to its own line

* Get vite to generate type definitions

* Apply formatting changes

* noEmit not allowed in tsconfig, moved it to build step

* Align version of @rrweb/types with main rrweb package

Based on @mark-fenng's comments https://github.com/rrweb-io/rrweb/pull/1031/files#r1002298176

* Move up keywords
This commit is contained in:
Justin Halsall
2026-04-01 12:00:00 +08:00
committed by GitHub
parent 96ba547e72
commit 905ac51afb
69 changed files with 1307 additions and 712 deletions

4
packages/types/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
dist
es
lib
typings

View File

@@ -0,0 +1,49 @@
{
"name": "@rrweb/types",
"version": "2.0.0-alpha.3",
"keywords": [
"rrweb",
"@rrweb/types"
],
"scripts": {
"dev": "vite",
"build": "tsc -noEmit && vite build",
"check-types": "tsc -noEmit",
"prepublish": "npm run build",
"lint": "yarn eslint src/**/*.ts"
},
"homepage": "https://github.com/rrweb-io/rrweb/tree/main/packages/@rrweb/types#readme",
"bugs": {
"url": "https://github.com/rrweb-io/rrweb/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/rrweb-io/rrweb.git"
},
"license": "MIT",
"type": "module",
"main": "./dist/types.umd.cjs",
"module": "./dist/types.js",
"typings": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/types.js",
"require": "./dist/types.umd.cjs"
}
},
"files": [
"build",
"dist"
],
"devDependencies": {
"typescript": "^4.7.3",
"vite": "^3.2.0-beta.2",
"vite-plugin-dts": "^1.6.6"
},
"dependencies": {
"rrweb-snapshot": "^2.0.0-alpha.3"
},
"browserslist": [
"supports es6-class"
]
}

638
packages/types/src/index.ts Normal file
View File

@@ -0,0 +1,638 @@
import type {
serializedNodeWithId,
Mirror,
INode,
DataURLOptions,
} from 'rrweb-snapshot';
export enum EventType {
DomContentLoaded,
Load,
FullSnapshot,
IncrementalSnapshot,
Meta,
Custom,
Plugin,
}
export type domContentLoadedEvent = {
type: EventType.DomContentLoaded;
data: unknown;
};
export type loadedEvent = {
type: EventType.Load;
data: unknown;
};
export type fullSnapshotEvent = {
type: EventType.FullSnapshot;
data: {
node: serializedNodeWithId;
initialOffset: {
top: number;
left: number;
};
};
};
export type incrementalSnapshotEvent = {
type: EventType.IncrementalSnapshot;
data: incrementalData;
};
export type metaEvent = {
type: EventType.Meta;
data: {
href: string;
width: number;
height: number;
};
};
export type customEvent<T = unknown> = {
type: EventType.Custom;
data: {
tag: string;
payload: T;
};
};
export type pluginEvent<T = unknown> = {
type: EventType.Plugin;
data: {
plugin: string;
payload: T;
};
};
export enum IncrementalSource {
Mutation,
MouseMove,
MouseInteraction,
Scroll,
ViewportResize,
Input,
TouchMove,
MediaInteraction,
StyleSheetRule,
CanvasMutation,
Font,
Log,
Drag,
StyleDeclaration,
Selection,
AdoptedStyleSheet,
}
export type mutationData = {
source: IncrementalSource.Mutation;
} & mutationCallbackParam;
export type mousemoveData = {
source:
| IncrementalSource.MouseMove
| IncrementalSource.TouchMove
| IncrementalSource.Drag;
positions: mousePosition[];
};
export type mouseInteractionData = {
source: IncrementalSource.MouseInteraction;
} & mouseInteractionParam;
export type scrollData = {
source: IncrementalSource.Scroll;
} & scrollPosition;
export type viewportResizeData = {
source: IncrementalSource.ViewportResize;
} & viewportResizeDimension;
export type inputData = {
source: IncrementalSource.Input;
id: number;
} & inputValue;
export type mediaInteractionData = {
source: IncrementalSource.MediaInteraction;
} & mediaInteractionParam;
export type styleSheetRuleData = {
source: IncrementalSource.StyleSheetRule;
} & styleSheetRuleParam;
export type styleDeclarationData = {
source: IncrementalSource.StyleDeclaration;
} & styleDeclarationParam;
export type canvasMutationData = {
source: IncrementalSource.CanvasMutation;
} & canvasMutationParam;
export type fontData = {
source: IncrementalSource.Font;
} & fontParam;
export type selectionData = {
source: IncrementalSource.Selection;
} & selectionParam;
export type adoptedStyleSheetData = {
source: IncrementalSource.AdoptedStyleSheet;
} & adoptedStyleSheetParam;
export type incrementalData =
| mutationData
| mousemoveData
| mouseInteractionData
| scrollData
| viewportResizeData
| inputData
| mediaInteractionData
| styleSheetRuleData
| canvasMutationData
| fontData
| selectionData
| styleDeclarationData
| adoptedStyleSheetData;
export type event =
| domContentLoadedEvent
| loadedEvent
| fullSnapshotEvent
| incrementalSnapshotEvent
| metaEvent
| customEvent
| pluginEvent;
export type eventWithTime = event & {
timestamp: number;
delay?: number;
};
export type canvasEventWithTime = eventWithTime & {
type: EventType.IncrementalSnapshot;
data: canvasMutationData;
};
export type blockClass = string | RegExp;
export type maskTextClass = string | RegExp;
export type SamplingStrategy = Partial<{
/**
* false means not to record mouse/touch move events
* number is the throttle threshold of recording mouse/touch move
*/
mousemove: boolean | number;
/**
* number is the throttle threshold of mouse/touch move callback
*/
mousemoveCallback: number;
/**
* false means not to record mouse interaction events
* can also specify record some kinds of mouse interactions
*/
mouseInteraction: boolean | Record<string, boolean | undefined>;
/**
* number is the throttle threshold of recording scroll
*/
scroll: number;
/**
* number is the throttle threshold of recording media interactions
*/
media: number;
/**
* 'all' will record all the input events
* 'last' will only record the last input value while input a sequence of chars
*/
input: 'all' | 'last';
/**
* 'all' will record every single canvas call
* number between 1 and 60, will record an image snapshots in a web-worker a (maximum) number of times per second.
* Number only supported where [`OffscreenCanvas`](http://mdn.io/offscreencanvas) is supported.
*/
canvas: 'all' | number;
}>;
export type RecordPlugin<TOptions = unknown> = {
name: string;
observer?: (
cb: (...args: Array<unknown>) => void,
win: IWindow,
options: TOptions,
) => listenerHandler;
eventProcessor?: <TExtend>(event: eventWithTime) => eventWithTime & TExtend;
getMirror?: (mirror: Mirror) => void;
options: TOptions;
};
export type hooksParam = {
mutation?: mutationCallBack;
mousemove?: mousemoveCallBack;
mouseInteraction?: mouseInteractionCallBack;
scroll?: scrollCallback;
viewportResize?: viewportResizeCallback;
input?: inputCallback;
mediaInteaction?: mediaInteractionCallback;
styleSheetRule?: styleSheetRuleCallback;
styleDeclaration?: styleDeclarationCallback;
canvasMutation?: canvasMutationCallback;
font?: fontCallback;
selection?: selectionCallback;
};
// https://dom.spec.whatwg.org/#interface-mutationrecord
export type mutationRecord = {
type: string;
target: Node;
oldValue: string | null;
addedNodes: NodeList;
removedNodes: NodeList;
attributeName: string | null;
};
export type textCursor = {
node: Node;
value: string | null;
};
export type textMutation = {
id: number;
value: string | null;
};
export type styleAttributeValue = {
[key: string]: styleValueWithPriority | string | false;
};
export type styleValueWithPriority = [string, string];
export type attributeCursor = {
node: Node;
attributes: {
[key: string]: string | styleAttributeValue | null;
};
};
export type attributeMutation = {
id: number;
attributes: {
[key: string]: string | styleAttributeValue | null;
};
};
export type removedNodeMutation = {
parentId: number;
id: number;
isShadow?: boolean;
};
export type addedNodeMutation = {
parentId: number;
// Newly recorded mutations will not have previousId any more, just for compatibility
previousId?: number | null;
nextId: number | null;
node: serializedNodeWithId;
};
export type mutationCallbackParam = {
texts: textMutation[];
attributes: attributeMutation[];
removes: removedNodeMutation[];
adds: addedNodeMutation[];
isAttachIframe?: true;
};
export type mutationCallBack = (m: mutationCallbackParam) => void;
export type mousemoveCallBack = (
p: mousePosition[],
source:
| IncrementalSource.MouseMove
| IncrementalSource.TouchMove
| IncrementalSource.Drag,
) => void;
export type mousePosition = {
x: number;
y: number;
id: number;
timeOffset: number;
};
export type mouseMovePos = {
x: number;
y: number;
id: number;
debugData: incrementalData;
};
export enum MouseInteractions {
MouseUp,
MouseDown,
Click,
ContextMenu,
DblClick,
Focus,
Blur,
TouchStart,
TouchMove_Departed, // we will start a separate observer for touch move event
TouchEnd,
TouchCancel,
}
export enum CanvasContext {
'2D',
WebGL,
WebGL2,
}
export type SerializedCanvasArg =
| {
rr_type: 'ArrayBuffer';
base64: string; // base64
}
| {
rr_type: 'Blob';
data: Array<CanvasArg>;
type?: string;
}
| {
rr_type: string;
src: string; // url of image
}
| {
rr_type: string;
args: Array<CanvasArg>;
}
| {
rr_type: string;
index: number;
};
export type CanvasArg =
| SerializedCanvasArg
| string
| number
| boolean
| null
| CanvasArg[];
type mouseInteractionParam = {
type: MouseInteractions;
id: number;
x: number;
y: number;
};
export type mouseInteractionCallBack = (d: mouseInteractionParam) => void;
export type scrollPosition = {
id: number;
x: number;
y: number;
};
export type scrollCallback = (p: scrollPosition) => void;
export type styleSheetAddRule = {
rule: string;
index?: number | number[];
};
export type styleSheetDeleteRule = {
index: number | number[];
};
export type styleSheetRuleParam = {
id?: number;
styleId?: number;
removes?: styleSheetDeleteRule[];
adds?: styleSheetAddRule[];
replace?: string;
replaceSync?: string;
};
export type styleSheetRuleCallback = (s: styleSheetRuleParam) => void;
export type adoptedStyleSheetParam = {
// id indicates the node id of document or shadow DOMs' host element.
id: number;
// New CSSStyleSheets which have never appeared before.
styles?: {
styleId: number;
rules: styleSheetAddRule[];
}[];
// StyleSheet ids to be adopted.
styleIds: number[];
};
export type adoptedStyleSheetCallback = (a: adoptedStyleSheetParam) => void;
export type styleDeclarationParam = {
id?: number;
styleId?: number;
index: number[];
set?: {
property: string;
value: string | null;
priority: string | undefined;
};
remove?: {
property: string;
};
};
export type styleDeclarationCallback = (s: styleDeclarationParam) => void;
export type canvasMutationCommand = {
property: string;
args: Array<unknown>;
setter?: true;
};
export type canvasMutationParam =
| {
id: number;
type: CanvasContext;
commands: canvasMutationCommand[];
}
| ({
id: number;
type: CanvasContext;
} & canvasMutationCommand);
export type canvasMutationWithType = {
type: CanvasContext;
} & canvasMutationCommand;
export type canvasMutationCallback = (p: canvasMutationParam) => void;
export type canvasManagerMutationCallback = (
target: HTMLCanvasElement,
p: canvasMutationWithType,
) => void;
export type ImageBitmapDataURLWorkerParams = {
id: number;
bitmap: ImageBitmap;
width: number;
height: number;
dataURLOptions: DataURLOptions;
};
export type ImageBitmapDataURLWorkerResponse =
| {
id: number;
}
| {
id: number;
type: string;
base64: string;
width: number;
height: number;
};
export type fontParam = {
family: string;
fontSource: string;
buffer: boolean;
descriptors?: FontFaceDescriptors;
};
export type fontCallback = (p: fontParam) => void;
export type viewportResizeDimension = {
width: number;
height: number;
};
export type viewportResizeCallback = (d: viewportResizeDimension) => void;
export type inputValue = {
text: string;
isChecked: boolean;
// `userTriggered` indicates if this event was triggered directly by user (userTriggered: true)
// or was triggered indirectly (userTriggered: false)
// Example of `userTriggered` in action:
// User clicks on radio element (userTriggered: true) which triggers the other radio element to change (userTriggered: false)
userTriggered?: boolean;
};
export type inputCallback = (v: inputValue & { id: number }) => void;
export const enum MediaInteractions {
Play,
Pause,
Seeked,
VolumeChange,
RateChange,
}
export type mediaInteractionParam = {
type: MediaInteractions;
id: number;
currentTime?: number;
volume?: number;
muted?: boolean;
playbackRate?: number;
};
export type mediaInteractionCallback = (p: mediaInteractionParam) => void;
export type DocumentDimension = {
x: number;
y: number;
// scale value relative to its parent iframe
relativeScale: number;
// scale value relative to the root iframe
absoluteScale: number;
};
export type SelectionRange = {
start: number;
startOffset: number;
end: number;
endOffset: number;
};
export type selectionParam = {
ranges: Array<SelectionRange>;
};
export type selectionCallback = (p: selectionParam) => void;
export type DeprecatedMirror = {
map: {
[key: number]: INode;
};
getId: (n: Node) => number;
getNode: (id: number) => INode | null;
removeNodeFromMap: (n: Node) => void;
has: (id: number) => boolean;
reset: () => void;
};
export type throttleOptions = {
leading?: boolean;
trailing?: boolean;
};
export type listenerHandler = () => void;
export type hookResetter = () => void;
export type playerMetaData = {
startTime: number;
endTime: number;
totalTime: number;
};
export type actionWithDelay = {
doAction: () => void;
delay: number;
};
export type Handler = (event?: unknown) => void;
export type Emitter = {
on(type: string, handler: Handler): void;
emit(type: string, event?: unknown): void;
off(type: string, handler: Handler): void;
};
export type Arguments<T> = T extends (...payload: infer U) => unknown
? U
: unknown;
export enum ReplayerEvents {
Start = 'start',
Pause = 'pause',
Resume = 'resume',
Resize = 'resize',
Finish = 'finish',
FullsnapshotRebuilded = 'fullsnapshot-rebuilded',
LoadStylesheetStart = 'load-stylesheet-start',
LoadStylesheetEnd = 'load-stylesheet-end',
SkipStart = 'skip-start',
SkipEnd = 'skip-end',
MouseInteraction = 'mouse-interaction',
EventCast = 'event-cast',
CustomEvent = 'custom-event',
Flush = 'flush',
StateChange = 'state-change',
PlayBack = 'play-back',
Destroy = 'destroy',
}
export type KeepIframeSrcFn = (src: string) => boolean;
declare global {
interface Window {
FontFace: typeof FontFace;
}
}
export type IWindow = Window & typeof globalThis;
export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;

View File

@@ -0,0 +1,26 @@
{
"compilerOptions": {
"composite": true,
"target": "ES6",
"module": "commonjs",
"noImplicitAny": true,
"strictNullChecks": true,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true,
"rootDir": "src",
"outDir": "build",
"lib": ["es6", "dom"],
"skipLibCheck": true,
"declaration": true,
"importsNotUsedAsValues": "error"
},
"compileOnSave": true,
"exclude": ["test"],
"include": ["src"],
"references": [
{
"path": "../rrweb-snapshot"
}
]
}

View File

@@ -0,0 +1,21 @@
import path from 'path';
import dts from 'vite-plugin-dts';
/**
* @type {import('vite').UserConfig}
*/
export default {
build: {
// See https://vitejs.dev/guide/build.html#library-mode
lib: {
entry: path.resolve(__dirname, 'src/index.ts'),
name: 'rrwebTypes',
},
// Leaving this unminified so you can see what exactly gets included in
// the bundles
minify: false,
sourcemap: true,
},
plugins: [dts()],
};