webrec-sdk 1.0.0
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/dist/capture/console-interceptor.d.ts +12 -0
- package/dist/capture/dead-click-detector.d.ts +14 -0
- package/dist/capture/dom-recorder.d.ts +8 -0
- package/dist/capture/error-click-detector.d.ts +12 -0
- package/dist/capture/error-tracker.d.ts +16 -0
- package/dist/capture/interaction-enricher.d.ts +17 -0
- package/dist/capture/network-interceptor.d.ts +30 -0
- package/dist/capture/scroll-depth-tracker.d.ts +21 -0
- package/dist/config.d.ts +51 -0
- package/dist/identity/session-manager.d.ts +21 -0
- package/dist/identity/user-identifier.d.ts +21 -0
- package/dist/index.d.ts +29 -0
- package/dist/privacy/masking.d.ts +15 -0
- package/dist/recorder.d.ts +43 -0
- package/dist/surveys.d.ts +8 -0
- package/dist/transport/batch-transport.d.ts +45 -0
- package/dist/transport/beacon-transport.d.ts +17 -0
- package/dist/utils/compression.d.ts +11 -0
- package/dist/utils/idle-callback.d.ts +6 -0
- package/dist/utils/safe-exec.d.ts +5 -0
- package/dist/utils/uuid.d.ts +1 -0
- package/dist/webrec.cjs.js +17 -0
- package/dist/webrec.cjs.js.map +1 -0
- package/dist/webrec.esm.js +17 -0
- package/dist/webrec.esm.js.map +1 -0
- package/dist/webrec.umd.js +17 -0
- package/dist/webrec.umd.js.map +1 -0
- package/package.json +30 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type ConsoleEvent = {
|
|
2
|
+
level: string;
|
|
3
|
+
message: string;
|
|
4
|
+
url: string;
|
|
5
|
+
};
|
|
6
|
+
export type ConsoleCallback = (event: ConsoleEvent) => void;
|
|
7
|
+
export declare class ConsoleInterceptor {
|
|
8
|
+
private originals;
|
|
9
|
+
private active;
|
|
10
|
+
start(callback: ConsoleCallback): void;
|
|
11
|
+
stop(): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type DeadClickCallback = (event: any) => void;
|
|
2
|
+
export declare class DeadClickDetector {
|
|
3
|
+
private callback;
|
|
4
|
+
private clickHandler;
|
|
5
|
+
private pendingClicks;
|
|
6
|
+
private active;
|
|
7
|
+
private origXhrOpen;
|
|
8
|
+
private origFetch;
|
|
9
|
+
private activeNetworkCount;
|
|
10
|
+
start(callback: DeadClickCallback): void;
|
|
11
|
+
stop(): void;
|
|
12
|
+
private interceptNetwork;
|
|
13
|
+
private restoreNetwork;
|
|
14
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type ErrorClickCallback = (event: any) => void;
|
|
2
|
+
export declare class ErrorClickDetector {
|
|
3
|
+
private callback;
|
|
4
|
+
private clickHandler;
|
|
5
|
+
private errorHandler;
|
|
6
|
+
private rejectionHandler;
|
|
7
|
+
private clickBuffer;
|
|
8
|
+
private active;
|
|
9
|
+
start(callback: ErrorClickCallback): void;
|
|
10
|
+
stop(): void;
|
|
11
|
+
private checkForCorrelatedClick;
|
|
12
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type RecorderErrorEvent = {
|
|
2
|
+
type: string;
|
|
3
|
+
message: string;
|
|
4
|
+
stack?: string;
|
|
5
|
+
url?: string;
|
|
6
|
+
line?: number;
|
|
7
|
+
column?: number;
|
|
8
|
+
};
|
|
9
|
+
export type ErrorCallback = (event: RecorderErrorEvent) => void;
|
|
10
|
+
export declare class ErrorTracker {
|
|
11
|
+
private errorHandler;
|
|
12
|
+
private rejectionHandler;
|
|
13
|
+
private active;
|
|
14
|
+
start(callback: ErrorCallback): void;
|
|
15
|
+
stop(): void;
|
|
16
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type EnrichedEventCallback = (event: any) => void;
|
|
2
|
+
export declare class InteractionEnricher {
|
|
3
|
+
private callback;
|
|
4
|
+
private observer;
|
|
5
|
+
private clickHandler;
|
|
6
|
+
private submitHandler;
|
|
7
|
+
private changeHandler;
|
|
8
|
+
private active;
|
|
9
|
+
private dialogDebounceMap;
|
|
10
|
+
start(callback: EnrichedEventCallback): void;
|
|
11
|
+
stop(): void;
|
|
12
|
+
private startClickCapture;
|
|
13
|
+
private startSubmitCapture;
|
|
14
|
+
private startChangeCapture;
|
|
15
|
+
private startDialogDetection;
|
|
16
|
+
private emit;
|
|
17
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type NetworkEvent = {
|
|
2
|
+
method: string;
|
|
3
|
+
url: string;
|
|
4
|
+
status: number;
|
|
5
|
+
duration: number;
|
|
6
|
+
requestSize?: number;
|
|
7
|
+
responseSize?: number;
|
|
8
|
+
requestBody?: string;
|
|
9
|
+
responseBody?: string;
|
|
10
|
+
type: string;
|
|
11
|
+
};
|
|
12
|
+
export type NetworkCallback = (event: NetworkEvent) => void;
|
|
13
|
+
export declare class NetworkInterceptor {
|
|
14
|
+
private originalFetch;
|
|
15
|
+
private originalXHROpen;
|
|
16
|
+
private originalXHRSend;
|
|
17
|
+
private active;
|
|
18
|
+
private sdkEndpoint;
|
|
19
|
+
start(callback: NetworkCallback, sdkEndpoint?: string): void;
|
|
20
|
+
/** Check if a URL is the SDK's own endpoint (should not be recorded) */
|
|
21
|
+
private isSdkUrl;
|
|
22
|
+
private interceptFetch;
|
|
23
|
+
private interceptXHR;
|
|
24
|
+
/**
|
|
25
|
+
* Strip common sensitive query parameters from URLs.
|
|
26
|
+
* Keeps the URL structure but redacts tokens, keys, passwords etc.
|
|
27
|
+
*/
|
|
28
|
+
private sanitizeUrl;
|
|
29
|
+
stop(): void;
|
|
30
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type ScrollDepthCallback = (event: any) => void;
|
|
2
|
+
export declare class ScrollDepthTracker {
|
|
3
|
+
private callback;
|
|
4
|
+
private scrollHandler;
|
|
5
|
+
private visibilityHandler;
|
|
6
|
+
private active;
|
|
7
|
+
private maxDepthPercent;
|
|
8
|
+
private currentUrl;
|
|
9
|
+
private throttleTimer;
|
|
10
|
+
private lastEmittedUrl;
|
|
11
|
+
private origPushState;
|
|
12
|
+
private origReplaceState;
|
|
13
|
+
private popstateHandler;
|
|
14
|
+
start(callback: ScrollDepthCallback): void;
|
|
15
|
+
stop(): void;
|
|
16
|
+
private calculateDepth;
|
|
17
|
+
private emitDepth;
|
|
18
|
+
private onNavigate;
|
|
19
|
+
private interceptNavigation;
|
|
20
|
+
private restoreNavigation;
|
|
21
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export interface RecorderConfig {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
endpoint?: string;
|
|
4
|
+
maskAllInputs?: boolean;
|
|
5
|
+
blockClass?: string;
|
|
6
|
+
ignoreClass?: string;
|
|
7
|
+
blockSelector?: string;
|
|
8
|
+
ignoreSelector?: string;
|
|
9
|
+
captureNetwork?: boolean;
|
|
10
|
+
captureConsole?: boolean;
|
|
11
|
+
captureErrors?: boolean;
|
|
12
|
+
/** Record canvas/WebGL elements. Increases CPU usage. Default false. */
|
|
13
|
+
recordCanvas?: boolean;
|
|
14
|
+
/** Collect fonts used on the page for accurate replay. Default true. */
|
|
15
|
+
collectFonts?: boolean;
|
|
16
|
+
batchSize?: number;
|
|
17
|
+
flushInterval?: number;
|
|
18
|
+
/** Max events to hold in memory. Oldest evicted when exceeded. Default 2000. */
|
|
19
|
+
maxQueueSize?: number;
|
|
20
|
+
/** Max retry attempts for failed flushes. Default 3. */
|
|
21
|
+
maxRetries?: number;
|
|
22
|
+
sessionTimeout?: number;
|
|
23
|
+
/** Percentage of traffic to record (0-100). Default 100 = record all. */
|
|
24
|
+
sampleRate?: number;
|
|
25
|
+
/** Minimum time in ms user must spend on page before recording starts. Default 0. */
|
|
26
|
+
minTimeOnPage?: number;
|
|
27
|
+
/** Minimum session duration in seconds before data is sent. Sessions shorter are discarded. Default 0. */
|
|
28
|
+
minSessionDuration?: number;
|
|
29
|
+
/** Ignore sessions on these URL patterns (regex strings). */
|
|
30
|
+
ignoreUrls?: string[];
|
|
31
|
+
/** Only record sessions on these URL patterns (regex strings). If set, only matching URLs are recorded. */
|
|
32
|
+
allowUrls?: string[];
|
|
33
|
+
/** Whether to respect Do Not Track browser setting. Default true. */
|
|
34
|
+
respectDoNotTrack?: boolean;
|
|
35
|
+
/** Delay in ms before recording starts after init. Default 0. */
|
|
36
|
+
startDelay?: number;
|
|
37
|
+
/** Enable verbose debug logging to console. Default false. */
|
|
38
|
+
debug?: boolean;
|
|
39
|
+
sampling?: {
|
|
40
|
+
mousemove?: boolean | number;
|
|
41
|
+
scroll?: number;
|
|
42
|
+
input?: 'last' | 'all';
|
|
43
|
+
};
|
|
44
|
+
privacy?: {
|
|
45
|
+
maskInputs?: boolean;
|
|
46
|
+
maskTextContent?: boolean;
|
|
47
|
+
blockSelectors?: string[];
|
|
48
|
+
ignoreSelectors?: string[];
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export declare const DEFAULT_CONFIG: Required<Omit<RecorderConfig, 'apiKey'>>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare class SessionManager {
|
|
2
|
+
private sessionId;
|
|
3
|
+
private anonymousId;
|
|
4
|
+
private timeout;
|
|
5
|
+
constructor(timeout: number);
|
|
6
|
+
/**
|
|
7
|
+
* Get or create a persistent anonymous ID stored in localStorage.
|
|
8
|
+
* Unlike session IDs (sessionStorage, tab-scoped, rotates on timeout),
|
|
9
|
+
* the anonymous ID persists across tabs and browser restarts — it
|
|
10
|
+
* represents the same device/browser until the user clears storage.
|
|
11
|
+
*/
|
|
12
|
+
private getOrCreateAnonymousId;
|
|
13
|
+
private getOrCreateSession;
|
|
14
|
+
private persist;
|
|
15
|
+
touch(): void;
|
|
16
|
+
getSessionId(): string;
|
|
17
|
+
getAnonymousId(): string;
|
|
18
|
+
/** Get timestamp of last activity (for timeout rotation checks) */
|
|
19
|
+
getLastActivity(): number | null;
|
|
20
|
+
reset(): string;
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface UserTraits {
|
|
2
|
+
name?: string;
|
|
3
|
+
displayName?: string;
|
|
4
|
+
email?: string;
|
|
5
|
+
[key: string]: any;
|
|
6
|
+
}
|
|
7
|
+
export declare class UserIdentifier {
|
|
8
|
+
private userId;
|
|
9
|
+
private traits;
|
|
10
|
+
private onIdentify;
|
|
11
|
+
constructor();
|
|
12
|
+
setCallback(cb: (userId: string, traits: UserTraits) => void): void;
|
|
13
|
+
identify(userId: string, traits?: UserTraits): void;
|
|
14
|
+
getUserId(): string | null;
|
|
15
|
+
getTraits(): UserTraits;
|
|
16
|
+
/** Re-fire the identify callback (e.g. after session rotation) without changing stored identity */
|
|
17
|
+
reidentify(): void;
|
|
18
|
+
reset(): void;
|
|
19
|
+
private persist;
|
|
20
|
+
private restore;
|
|
21
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { RecorderConfig } from './config';
|
|
2
|
+
import type { UserTraits } from './identity/user-identifier';
|
|
3
|
+
/**
|
|
4
|
+
* WebRec - Session recording SDK
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* WebRec.init({ apiKey: 'rec_xxx' })
|
|
8
|
+
* WebRec.identify('user-123', { name: 'John', email: 'john@example.com' })
|
|
9
|
+
* WebRec.track('checkout_complete', { value: 99 })
|
|
10
|
+
* WebRec.stop() // Pause recording
|
|
11
|
+
* WebRec.start() // Resume recording
|
|
12
|
+
* WebRec.destroy() // Full teardown (allows reinitialize)
|
|
13
|
+
*/
|
|
14
|
+
export declare const WebRec: {
|
|
15
|
+
init(config: RecorderConfig): void;
|
|
16
|
+
identify(userId: string, traits?: UserTraits): void;
|
|
17
|
+
/** Emit a custom business event */
|
|
18
|
+
track(eventName: string, properties?: Record<string, any>): void;
|
|
19
|
+
stop(): void;
|
|
20
|
+
start(): void;
|
|
21
|
+
/** Full teardown — destroy all listeners, interceptors, and state. Allows calling init() again. */
|
|
22
|
+
destroy(): void;
|
|
23
|
+
getSessionId(): string | null;
|
|
24
|
+
/** Get a link to this session in the recorder dashboard */
|
|
25
|
+
getSessionUrl(): string | null;
|
|
26
|
+
isRecording(): boolean;
|
|
27
|
+
};
|
|
28
|
+
export type { RecorderConfig, UserTraits };
|
|
29
|
+
export default WebRec;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { RecorderConfig } from '../config';
|
|
2
|
+
export declare function getMaskConfig(config: RecorderConfig): {
|
|
3
|
+
maskAllInputs: boolean;
|
|
4
|
+
maskInputOptions: {
|
|
5
|
+
password: boolean;
|
|
6
|
+
email: boolean;
|
|
7
|
+
tel: boolean;
|
|
8
|
+
};
|
|
9
|
+
maskTextClass: string;
|
|
10
|
+
maskTextSelector: string;
|
|
11
|
+
blockClass: string;
|
|
12
|
+
blockSelector: string;
|
|
13
|
+
ignoreClass: string;
|
|
14
|
+
maskTextFn: ((text: string) => string) | undefined;
|
|
15
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { RecorderConfig } from './config';
|
|
2
|
+
import { type UserTraits } from './identity/user-identifier';
|
|
3
|
+
export declare class Recorder {
|
|
4
|
+
private config;
|
|
5
|
+
private domRecorder;
|
|
6
|
+
private networkInterceptor;
|
|
7
|
+
private consoleInterceptor;
|
|
8
|
+
private errorTracker;
|
|
9
|
+
private interactionEnricher;
|
|
10
|
+
private deadClickDetector;
|
|
11
|
+
private errorClickDetector;
|
|
12
|
+
private scrollDepthTracker;
|
|
13
|
+
private transport;
|
|
14
|
+
private beacon;
|
|
15
|
+
private sessionManager;
|
|
16
|
+
private userIdentifier;
|
|
17
|
+
private initialized;
|
|
18
|
+
private recording;
|
|
19
|
+
private sampled;
|
|
20
|
+
private initTime;
|
|
21
|
+
private routeChangeCleanup;
|
|
22
|
+
private visibilityCleanup;
|
|
23
|
+
private rageClickCleanup;
|
|
24
|
+
private sessionCheckTimer;
|
|
25
|
+
private log;
|
|
26
|
+
init(userConfig: RecorderConfig): void;
|
|
27
|
+
start(): void;
|
|
28
|
+
stop(): void;
|
|
29
|
+
/** Full teardown - allows reinitializing with new config */
|
|
30
|
+
destroy(): void;
|
|
31
|
+
identify(userId: string, traits?: UserTraits): void;
|
|
32
|
+
/** Emit a custom business event (e.g., 'checkout_complete', 'add_to_cart') */
|
|
33
|
+
track(eventName: string, properties?: Record<string, any>): void;
|
|
34
|
+
getSessionId(): string | null;
|
|
35
|
+
/** Get a URL that links directly to this session in the recorder UI */
|
|
36
|
+
getSessionUrl(): string | null;
|
|
37
|
+
isRecording(): boolean;
|
|
38
|
+
private startRouteTracking;
|
|
39
|
+
private startVisibilityTracking;
|
|
40
|
+
private startRageClickDetection;
|
|
41
|
+
private startSessionCheck;
|
|
42
|
+
private captureWebVitals;
|
|
43
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-App Surveys Module
|
|
3
|
+
*
|
|
4
|
+
* Fetches active surveys from the API, renders them in a Shadow DOM widget,
|
|
5
|
+
* and submits responses. Designed to be called from recorder.ts after
|
|
6
|
+
* recording starts.
|
|
7
|
+
*/
|
|
8
|
+
export declare function initSurveys(endpoint: string, apiKey: string, getSessionId: () => string | null, debug?: boolean): void;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export interface TransportConfig {
|
|
2
|
+
endpoint: string;
|
|
3
|
+
apiKey: string;
|
|
4
|
+
batchSize: number;
|
|
5
|
+
flushInterval: number;
|
|
6
|
+
maxQueueSize?: number;
|
|
7
|
+
maxRetries?: number;
|
|
8
|
+
/** Minimum session duration in seconds before data is actually sent. Events are buffered until met. */
|
|
9
|
+
minSessionDuration?: number;
|
|
10
|
+
/** Timestamp when the session started, used with minSessionDuration. */
|
|
11
|
+
sessionStartTime?: number;
|
|
12
|
+
/** URL pattern to filter out SDK's own requests in network interceptor */
|
|
13
|
+
sdkEndpoint?: string;
|
|
14
|
+
debug?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare class BatchTransport {
|
|
17
|
+
private queue;
|
|
18
|
+
private timer;
|
|
19
|
+
private config;
|
|
20
|
+
private sessionId;
|
|
21
|
+
private anonymousId;
|
|
22
|
+
private seq;
|
|
23
|
+
private flushing;
|
|
24
|
+
private identityProvider;
|
|
25
|
+
constructor(config: TransportConfig, sessionId: string, anonymousId?: string);
|
|
26
|
+
/** Register a callback that returns the current user identity (if any) for inclusion in batch meta */
|
|
27
|
+
setIdentityProvider(provider: () => {
|
|
28
|
+
userId: string | null;
|
|
29
|
+
traits: Record<string, any>;
|
|
30
|
+
}): void;
|
|
31
|
+
start(): void;
|
|
32
|
+
stop(): void;
|
|
33
|
+
enqueue(event: any): void;
|
|
34
|
+
flush(): void;
|
|
35
|
+
private sendWithRetry;
|
|
36
|
+
private retryBatch;
|
|
37
|
+
/** Drain and return the queue atomically (for beacon transport on page unload) */
|
|
38
|
+
drainQueue(): any[];
|
|
39
|
+
/** Peek at queue without draining (for diagnostics) */
|
|
40
|
+
getQueueLength(): number;
|
|
41
|
+
updateSessionId(sessionId: string): void;
|
|
42
|
+
getSessionId(): string;
|
|
43
|
+
getAnonymousId(): string;
|
|
44
|
+
getEndpoint(): string;
|
|
45
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { BatchTransport } from './batch-transport';
|
|
2
|
+
/**
|
|
3
|
+
* Uses navigator.sendBeacon + visibilitychange/pagehide as a fallback
|
|
4
|
+
* to ensure any remaining events are sent before the page closes.
|
|
5
|
+
*/
|
|
6
|
+
export declare class BeaconTransport {
|
|
7
|
+
private transport;
|
|
8
|
+
private apiKey;
|
|
9
|
+
private active;
|
|
10
|
+
private visibilityHandler;
|
|
11
|
+
private pagehideHandler;
|
|
12
|
+
private beforeunloadHandler;
|
|
13
|
+
constructor(transport: BatchTransport, apiKey: string);
|
|
14
|
+
start(): void;
|
|
15
|
+
private sendChunk;
|
|
16
|
+
stop(): void;
|
|
17
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synchronous gzip compression (pako). Used as fallback.
|
|
3
|
+
*/
|
|
4
|
+
export declare function gzipCompress(data: string): Uint8Array;
|
|
5
|
+
/**
|
|
6
|
+
* Async gzip compression. Uses native CompressionStream API when available
|
|
7
|
+
* (zero-cost, off main thread in browsers that support it), falls back to pako.
|
|
8
|
+
*
|
|
9
|
+
* Supported: Chrome 80+, Firefox 113+, Safari 16.4+, Edge 80+
|
|
10
|
+
*/
|
|
11
|
+
export declare function compressAsync(data: string): Promise<Uint8Array>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function uuid(): string;
|