@spotify-confidence/csr-recorder 0.0.0 → 0.17.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/README.md +36 -0
- package/dist/index.cjs +11090 -0
- package/dist/index.d.cts +124 -0
- package/dist/index.d.ts +124 -0
- package/dist/index.js +11084 -0
- package/package.json +49 -1
- package/src/engine/index.ts +11 -0
- package/src/engine/rrweb-engine.test.ts +63 -0
- package/src/engine/rrweb-engine.ts +49 -0
- package/src/index.ts +11 -0
- package/src/recorder-routing.test.ts +162 -0
- package/src/recorder.test.ts +207 -0
- package/src/recorder.ts +266 -0
- package/src/start-recording.ts +21 -0
- package/src/types.ts +64 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { RecordingEvent } from "@spotify-confidence/csr-common";
|
|
2
|
+
|
|
3
|
+
//#region src/engine/index.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Abstraction over the underlying recording library (rrweb, custom, etc.).
|
|
6
|
+
* The Recorder class depends on this interface — never on rrweb directly.
|
|
7
|
+
*/
|
|
8
|
+
interface RecordingEngine {
|
|
9
|
+
start(config: RecordingConfig, onEvent: (event: RecordingEvent) => void): void;
|
|
10
|
+
stop(): void;
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/types.d.ts
|
|
14
|
+
interface RecorderOptions {
|
|
15
|
+
/** Engine used to capture DOM events (defaults to rrweb). */
|
|
16
|
+
engine: RecordingEngine;
|
|
17
|
+
/** Called for each recorded event. */
|
|
18
|
+
onEvent: (event: import("@spotify-confidence/csr-common").RecordingEvent) => void;
|
|
19
|
+
}
|
|
20
|
+
declare const DEFAULT_MASK_SELECTORS: string[];
|
|
21
|
+
declare const DEFAULT_BLOCK_SELECTORS: string[];
|
|
22
|
+
interface RecordingConfig {
|
|
23
|
+
/**
|
|
24
|
+
* CSS selectors for text content that should be masked. Joined with `,` and
|
|
25
|
+
* passed to rrweb as `maskTextSelector`. Text inside matching elements is
|
|
26
|
+
* replaced with `*` of the same length on the wire.
|
|
27
|
+
*/
|
|
28
|
+
maskSelectors?: string[];
|
|
29
|
+
/**
|
|
30
|
+
* CSS selectors for elements whose subtree should be blocked entirely.
|
|
31
|
+
* Joined with `,` and passed to rrweb as `blockSelector`. Matching elements
|
|
32
|
+
* are replaced with a same-sized placeholder; their contents are never
|
|
33
|
+
* serialized — stronger than masking, use for media, third-party widgets,
|
|
34
|
+
* or anything that shouldn't leave the page at all.
|
|
35
|
+
*/
|
|
36
|
+
blockSelectors?: string[];
|
|
37
|
+
/**
|
|
38
|
+
* Mask the values of every `<input>` / `<textarea>` / `contenteditable`.
|
|
39
|
+
* Defaults to `true` — typed PII (emails, names, search queries) doesn't
|
|
40
|
+
* leave the page. Pass `false` to record raw input values; `<input
|
|
41
|
+
* type="password">` is masked by rrweb regardless.
|
|
42
|
+
*/
|
|
43
|
+
maskInputs?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Capture browser console output during the recording. Defaults to `false`
|
|
46
|
+
* because console output frequently contains PII, tokens, and other
|
|
47
|
+
* sensitive data that should not be ingested into the recording pipeline
|
|
48
|
+
* without explicit opt-in.
|
|
49
|
+
*
|
|
50
|
+
* - `true` — capture all levels (log, warn, error, debug, info).
|
|
51
|
+
* - `{ levels: [...] }` — capture only the listed levels.
|
|
52
|
+
*/
|
|
53
|
+
captureConsoleLogs?: boolean | {
|
|
54
|
+
levels: import("@spotify-confidence/csr-common").ConsoleLogLevel[];
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Capture network requests (fetch and XMLHttpRequest) during the recording.
|
|
58
|
+
* Defaults to `false` because request URLs and metadata can contain PII,
|
|
59
|
+
* tokens, or other sensitive data.
|
|
60
|
+
*
|
|
61
|
+
* Only metadata is captured (method, URL, status, duration, sizes) — no
|
|
62
|
+
* headers or bodies are recorded.
|
|
63
|
+
*/
|
|
64
|
+
captureNetworkRequests?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Capture client-side route changes during the recording. Defaults to
|
|
67
|
+
* `true`. Only the pathname is recorded; origin, query strings, and
|
|
68
|
+
* hashes are stripped.
|
|
69
|
+
*/
|
|
70
|
+
captureRouteChanges?: boolean;
|
|
71
|
+
}
|
|
72
|
+
declare enum RecorderState {
|
|
73
|
+
Idle = "idle",
|
|
74
|
+
Recording = "recording",
|
|
75
|
+
Stopped = "stopped"
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/recorder.d.ts
|
|
79
|
+
declare class Recorder {
|
|
80
|
+
private readonly engine;
|
|
81
|
+
private readonly onEvent;
|
|
82
|
+
private state;
|
|
83
|
+
private visibilityHandler;
|
|
84
|
+
private originalFetch;
|
|
85
|
+
private originalXhrOpen;
|
|
86
|
+
private originalXhrSend;
|
|
87
|
+
private originalPushState;
|
|
88
|
+
private originalReplaceState;
|
|
89
|
+
private popstateHandler;
|
|
90
|
+
constructor(options: RecorderOptions);
|
|
91
|
+
get currentState(): RecorderState;
|
|
92
|
+
start(config?: RecordingConfig): void;
|
|
93
|
+
private emitNetworkRequest;
|
|
94
|
+
private patchNetwork;
|
|
95
|
+
private patchFetch;
|
|
96
|
+
private patchXhr;
|
|
97
|
+
private emitRouteChange;
|
|
98
|
+
private static currentPathname;
|
|
99
|
+
private patchRouting;
|
|
100
|
+
private restoreRouting;
|
|
101
|
+
private restoreNetwork;
|
|
102
|
+
stop(): void;
|
|
103
|
+
}
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region src/engine/rrweb-engine.d.ts
|
|
106
|
+
/**
|
|
107
|
+
* rrweb adapter — bundles rrweb so consumers don't take a peer-dep on it.
|
|
108
|
+
*/
|
|
109
|
+
declare class RrwebEngine implements RecordingEngine {
|
|
110
|
+
private stopFn;
|
|
111
|
+
start(config: RecordingConfig, onEvent: (event: RecordingEvent) => void): void;
|
|
112
|
+
stop(): void;
|
|
113
|
+
}
|
|
114
|
+
//#endregion
|
|
115
|
+
//#region src/start-recording.d.ts
|
|
116
|
+
/**
|
|
117
|
+
* Start recording DOM events. Each event is passed to the callback
|
|
118
|
+
* as it is captured — no buffering or batching.
|
|
119
|
+
*
|
|
120
|
+
* Returns a function that stops the recording.
|
|
121
|
+
*/
|
|
122
|
+
declare function record(onEvent: (event: RecordingEvent) => void, config?: RecordingConfig): () => void;
|
|
123
|
+
//#endregion
|
|
124
|
+
export { DEFAULT_BLOCK_SELECTORS, DEFAULT_MASK_SELECTORS, Recorder, type RecorderOptions, RecorderState, type RecordingConfig, type RecordingEngine, RrwebEngine, record };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { RecordingEvent } from "@spotify-confidence/csr-common";
|
|
2
|
+
|
|
3
|
+
//#region src/engine/index.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Abstraction over the underlying recording library (rrweb, custom, etc.).
|
|
6
|
+
* The Recorder class depends on this interface — never on rrweb directly.
|
|
7
|
+
*/
|
|
8
|
+
interface RecordingEngine {
|
|
9
|
+
start(config: RecordingConfig, onEvent: (event: RecordingEvent) => void): void;
|
|
10
|
+
stop(): void;
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/types.d.ts
|
|
14
|
+
interface RecorderOptions {
|
|
15
|
+
/** Engine used to capture DOM events (defaults to rrweb). */
|
|
16
|
+
engine: RecordingEngine;
|
|
17
|
+
/** Called for each recorded event. */
|
|
18
|
+
onEvent: (event: import("@spotify-confidence/csr-common").RecordingEvent) => void;
|
|
19
|
+
}
|
|
20
|
+
declare const DEFAULT_MASK_SELECTORS: string[];
|
|
21
|
+
declare const DEFAULT_BLOCK_SELECTORS: string[];
|
|
22
|
+
interface RecordingConfig {
|
|
23
|
+
/**
|
|
24
|
+
* CSS selectors for text content that should be masked. Joined with `,` and
|
|
25
|
+
* passed to rrweb as `maskTextSelector`. Text inside matching elements is
|
|
26
|
+
* replaced with `*` of the same length on the wire.
|
|
27
|
+
*/
|
|
28
|
+
maskSelectors?: string[];
|
|
29
|
+
/**
|
|
30
|
+
* CSS selectors for elements whose subtree should be blocked entirely.
|
|
31
|
+
* Joined with `,` and passed to rrweb as `blockSelector`. Matching elements
|
|
32
|
+
* are replaced with a same-sized placeholder; their contents are never
|
|
33
|
+
* serialized — stronger than masking, use for media, third-party widgets,
|
|
34
|
+
* or anything that shouldn't leave the page at all.
|
|
35
|
+
*/
|
|
36
|
+
blockSelectors?: string[];
|
|
37
|
+
/**
|
|
38
|
+
* Mask the values of every `<input>` / `<textarea>` / `contenteditable`.
|
|
39
|
+
* Defaults to `true` — typed PII (emails, names, search queries) doesn't
|
|
40
|
+
* leave the page. Pass `false` to record raw input values; `<input
|
|
41
|
+
* type="password">` is masked by rrweb regardless.
|
|
42
|
+
*/
|
|
43
|
+
maskInputs?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Capture browser console output during the recording. Defaults to `false`
|
|
46
|
+
* because console output frequently contains PII, tokens, and other
|
|
47
|
+
* sensitive data that should not be ingested into the recording pipeline
|
|
48
|
+
* without explicit opt-in.
|
|
49
|
+
*
|
|
50
|
+
* - `true` — capture all levels (log, warn, error, debug, info).
|
|
51
|
+
* - `{ levels: [...] }` — capture only the listed levels.
|
|
52
|
+
*/
|
|
53
|
+
captureConsoleLogs?: boolean | {
|
|
54
|
+
levels: import("@spotify-confidence/csr-common").ConsoleLogLevel[];
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Capture network requests (fetch and XMLHttpRequest) during the recording.
|
|
58
|
+
* Defaults to `false` because request URLs and metadata can contain PII,
|
|
59
|
+
* tokens, or other sensitive data.
|
|
60
|
+
*
|
|
61
|
+
* Only metadata is captured (method, URL, status, duration, sizes) — no
|
|
62
|
+
* headers or bodies are recorded.
|
|
63
|
+
*/
|
|
64
|
+
captureNetworkRequests?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Capture client-side route changes during the recording. Defaults to
|
|
67
|
+
* `true`. Only the pathname is recorded; origin, query strings, and
|
|
68
|
+
* hashes are stripped.
|
|
69
|
+
*/
|
|
70
|
+
captureRouteChanges?: boolean;
|
|
71
|
+
}
|
|
72
|
+
declare enum RecorderState {
|
|
73
|
+
Idle = "idle",
|
|
74
|
+
Recording = "recording",
|
|
75
|
+
Stopped = "stopped"
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/recorder.d.ts
|
|
79
|
+
declare class Recorder {
|
|
80
|
+
private readonly engine;
|
|
81
|
+
private readonly onEvent;
|
|
82
|
+
private state;
|
|
83
|
+
private visibilityHandler;
|
|
84
|
+
private originalFetch;
|
|
85
|
+
private originalXhrOpen;
|
|
86
|
+
private originalXhrSend;
|
|
87
|
+
private originalPushState;
|
|
88
|
+
private originalReplaceState;
|
|
89
|
+
private popstateHandler;
|
|
90
|
+
constructor(options: RecorderOptions);
|
|
91
|
+
get currentState(): RecorderState;
|
|
92
|
+
start(config?: RecordingConfig): void;
|
|
93
|
+
private emitNetworkRequest;
|
|
94
|
+
private patchNetwork;
|
|
95
|
+
private patchFetch;
|
|
96
|
+
private patchXhr;
|
|
97
|
+
private emitRouteChange;
|
|
98
|
+
private static currentPathname;
|
|
99
|
+
private patchRouting;
|
|
100
|
+
private restoreRouting;
|
|
101
|
+
private restoreNetwork;
|
|
102
|
+
stop(): void;
|
|
103
|
+
}
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region src/engine/rrweb-engine.d.ts
|
|
106
|
+
/**
|
|
107
|
+
* rrweb adapter — bundles rrweb so consumers don't take a peer-dep on it.
|
|
108
|
+
*/
|
|
109
|
+
declare class RrwebEngine implements RecordingEngine {
|
|
110
|
+
private stopFn;
|
|
111
|
+
start(config: RecordingConfig, onEvent: (event: RecordingEvent) => void): void;
|
|
112
|
+
stop(): void;
|
|
113
|
+
}
|
|
114
|
+
//#endregion
|
|
115
|
+
//#region src/start-recording.d.ts
|
|
116
|
+
/**
|
|
117
|
+
* Start recording DOM events. Each event is passed to the callback
|
|
118
|
+
* as it is captured — no buffering or batching.
|
|
119
|
+
*
|
|
120
|
+
* Returns a function that stops the recording.
|
|
121
|
+
*/
|
|
122
|
+
declare function record(onEvent: (event: RecordingEvent) => void, config?: RecordingConfig): () => void;
|
|
123
|
+
//#endregion
|
|
124
|
+
export { DEFAULT_BLOCK_SELECTORS, DEFAULT_MASK_SELECTORS, Recorder, type RecorderOptions, RecorderState, type RecordingConfig, type RecordingEngine, RrwebEngine, record };
|