@nommos/core 0.0.30 → 0.0.31

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.
@@ -1,4 +1,5 @@
1
1
  import { SESSION_CHUNK_DURATION_MS, SESSION_INACTIVITY_TIMEOUT_MS, MAX_SESSION_CHUNK_BYTES } from './constants';
2
+ import pako from 'pako';
2
3
  /**
3
4
  * SessionTracker
4
5
  * --------------
@@ -12,48 +13,36 @@ import { SESSION_CHUNK_DURATION_MS, SESSION_INACTIVITY_TIMEOUT_MS, MAX_SESSION_C
12
13
  * - Environment-safe (no-op on server-side)
13
14
  */
14
15
  export class SessionTracker {
15
- constructor(ws, cfg, bid, channel) {
16
+ constructor(ws, cfg, bid, ip, channel, sessionId) {
16
17
  this.ws = ws;
17
18
  this.cfg = cfg;
18
19
  this.bid = bid;
20
+ this.ip = ip;
19
21
  this.channel = channel;
22
+ this.sessionId = sessionId;
20
23
  this.events = [];
21
24
  this.stopFn = null;
22
- this.inactivityTimer = null;
23
- this.visibilityTimer = null;
24
25
  this.isRecording = false;
25
- this.currentChunkBytes = 0;
26
- // FIX 3: Store bound listener references so they can be properly removed on stop()
27
- this.boundActivityHandler = () => this.resetInactivityTimer();
28
- this.boundVisibilityHandler = () => {
29
- if (document.visibilityState === 'hidden') {
30
- // Wait before stopping — user might switch back quickly
31
- this.visibilityTimer = setTimeout(() => {
32
- this.stopRecording();
33
- }, 10000); // 10 second grace period
34
- }
35
- else {
36
- // They came back — cancel the pending stop
37
- if (this.visibilityTimer) {
38
- clearTimeout(this.visibilityTimer);
39
- this.visibilityTimer = null;
40
- }
41
- this.resetInactivityTimer();
42
- this.startRecording();
43
- }
44
- };
26
+ this.seq = 0;
27
+ this.currentChunkSizeBytes = 0;
28
+ this.inactivityTimer = null;
45
29
  this.boundBeforeUnload = () => this.stopRecording();
30
+ this.boundActivityHandler = () => this.resetInactivityTimer();
31
+ this.boundVisibilityHandler = () => this.handleVisibilityChange();
46
32
  }
47
33
  /**
48
- * Initializes rrweb recording and setup listeners for visibility and inactivity.
34
+ * Initializes rrweb recording.
49
35
  */
50
36
  async start() {
51
37
  if (typeof window === 'undefined')
52
38
  return;
53
- this.setupVisibilityListener();
54
- this.setupActivityListeners();
55
- this.resetInactivityTimer();
39
+ window.addEventListener('beforeunload', this.boundBeforeUnload);
40
+ window.addEventListener('visibilitychange', this.boundVisibilityHandler);
41
+ // Activity listeners for inactivity timeout
42
+ const activityEvents = ['mousemove', 'click', 'keydown', 'scroll', 'touchstart'];
43
+ activityEvents.forEach(evt => window.addEventListener(evt, this.boundActivityHandler, { passive: true }));
56
44
  await this.startRecording();
45
+ this.resetInactivityTimer();
57
46
  }
58
47
  /**
59
48
  * Starts a new rrweb recording instance.
@@ -62,47 +51,35 @@ export class SessionTracker {
62
51
  if (this.isRecording || typeof window === 'undefined')
63
52
  return;
64
53
  try {
54
+ if (this.seq === 0) {
55
+ // Initial setup for a new recording
56
+ }
65
57
  const rrweb = await import('rrweb');
66
58
  this.stopFn = rrweb.record({
67
59
  emit: (event, isCheckout) => {
68
- if (this.cfg.mode === 'dev') {
69
- console.log(`[Nommos Tracker] Session Event: type=${event.type}, isCheckout=${!!isCheckout}`);
70
- }
71
- const eventJson = JSON.stringify(event);
72
- const eventBytes = new TextEncoder().encode(eventJson).length;
73
- // If it's a checkout (new chunk), flush the existing buffer BEFORE pushing the new snapshot.
74
- // This ensures the new Full Snapshot (type 2) becomes the FIRST event of the new chunk.
60
+ // If it's a checkout, flush the existing buffer BEFORE pushing the new snapshot.
75
61
  if (isCheckout) {
76
62
  if (this.cfg.mode === 'dev') {
77
63
  console.log('[Nommos Tracker] rrweb Checkout Event reached - flushing previous chunk...');
78
64
  }
79
65
  this.flush();
80
- this.currentChunkBytes = eventBytes;
81
- this.events.push(event);
82
- return;
83
66
  }
84
- // FIX 1: Check size BEFORE pushing the event to avoid exceeding the limit.
85
- // If adding this event would exceed the limit, recycle the recorder instead.
86
- // The next recording will open with a fresh Full Snapshot representing the current DOM,
87
- // so dropping this event here is safe — no data is lost.
88
- if (this.currentChunkBytes + eventBytes > MAX_SESSION_CHUNK_BYTES) {
67
+ this.events.push(event);
68
+ this.currentChunkSizeBytes += JSON.stringify(event).length;
69
+ // If we've hit the size limit, flush immediately
70
+ if (this.currentChunkSizeBytes >= MAX_SESSION_CHUNK_BYTES) {
89
71
  if (this.cfg.mode === 'dev') {
90
- console.log(`[Nommos Tracker] Chunk size limit reached (${(this.currentChunkBytes / 1024 / 1024).toFixed(2)}MB) - recycling recorder...`);
72
+ console.log(`[Nommos Tracker] Chunk size maxed out (~${this.currentChunkSizeBytes} bytes). Forcing flush.`);
91
73
  }
92
- // Use setTimeout to avoid recursion issues within the rrweb emit callback
93
- setTimeout(() => {
94
- if (this.isRecording) {
95
- this.stopRecording();
96
- this.startRecording();
97
- }
98
- }, 0);
99
- return;
74
+ this.flush();
100
75
  }
101
- this.currentChunkBytes += eventBytes;
102
- this.events.push(event);
103
76
  },
104
77
  checkoutEveryNms: this.cfg.controls?.session_chunk_duration_ms || SESSION_CHUNK_DURATION_MS,
105
78
  maskAllInputs: true,
79
+ sampling: {
80
+ mousemove: 50,
81
+ scroll: 150,
82
+ },
106
83
  }) || null;
107
84
  this.isRecording = true;
108
85
  if (this.cfg.mode === 'dev') {
@@ -127,130 +104,89 @@ export class SessionTracker {
127
104
  }
128
105
  this.isRecording = false;
129
106
  this.flush();
107
+ // We don't reset seq here, as a session can have multiple chunks across visibility/inactivity cycles
130
108
  if (this.cfg.mode === 'dev') {
131
- console.log('[Nommos Tracker] Session Recording Stopped');
109
+ console.log('[Nommos Tracker] Session Recording Paused/Stopped');
132
110
  }
133
111
  }
134
- /**
135
- * Public API to signal user activity. Resets the inactivity timer.
136
- */
137
- onUserActivity() {
138
- this.resetInactivityTimer();
112
+ handleVisibilityChange() {
113
+ if (document.visibilityState === 'hidden') {
114
+ if (this.cfg.mode === 'dev') {
115
+ console.log('[Nommos Tracker] Tab hidden - pausing recording');
116
+ }
117
+ this.stopRecording();
118
+ }
119
+ else {
120
+ if (this.cfg.mode === 'dev') {
121
+ console.log('[Nommos Tracker] Tab visible - resuming recording');
122
+ }
123
+ this.startRecording();
124
+ }
139
125
  }
140
- /**
141
- * Resets the inactivity timer. If recording was stopped due to inactivity, it restarts it.
142
- */
143
126
  resetInactivityTimer() {
144
127
  if (this.inactivityTimer) {
145
128
  clearTimeout(this.inactivityTimer);
146
129
  }
147
- // If we return from inactivity while visible, restart recording
148
- if (!this.isRecording && typeof document !== 'undefined' && document.visibilityState === 'visible') {
130
+ // If we were stopped due to inactivity, restart on new activity
131
+ if (!this.isRecording && document.visibilityState === 'visible') {
132
+ if (this.cfg.mode === 'dev') {
133
+ console.log('[Nommos Tracker] User active again - resuming recording');
134
+ }
149
135
  this.startRecording();
150
136
  }
151
- // 2 minutes of inactivity ends the current session recording
137
+ const timeout = this.cfg.controls?.session_inactivity_timeout_ms || SESSION_INACTIVITY_TIMEOUT_MS;
152
138
  this.inactivityTimer = setTimeout(() => {
153
139
  if (this.cfg.mode === 'dev') {
154
- console.log('[Nommos Tracker] Inactivity Timeout Reached');
140
+ console.log(`[Nommos Tracker] User inactive for ${timeout / 1000}s - pausing recording`);
155
141
  }
156
142
  this.stopRecording();
157
- }, this.cfg.controls?.session_inactivity_timeout_ms || SESSION_INACTIVITY_TIMEOUT_MS);
158
- }
159
- /**
160
- * Listens for visibility changes to handle background/foreground recording.
161
- */
162
- setupVisibilityListener() {
163
- // FIX 3: Use stored bound references so listeners can be removed in stop()
164
- document.addEventListener('visibilitychange', this.boundVisibilityHandler);
165
- window.addEventListener('beforeunload', this.boundBeforeUnload);
166
- }
167
- /**
168
- * Listens for user activity to reset the inactivity timer.
169
- */
170
- setupActivityListeners() {
171
- const activityEvents = ['mousemove', 'click', 'keydown', 'scroll'];
172
- // FIX 3: Use stored bound reference so listeners can be removed in stop()
173
- activityEvents.forEach((ev) => {
174
- window.addEventListener(ev, this.boundActivityHandler, { passive: true });
175
- });
143
+ }, timeout);
176
144
  }
177
145
  /**
178
146
  * Public API to completely stop the tracker (unmount/cleanup).
179
147
  */
180
148
  stop() {
149
+ if (typeof window === 'undefined')
150
+ return;
151
+ window.removeEventListener('beforeunload', this.boundBeforeUnload);
152
+ window.removeEventListener('visibilitychange', this.boundVisibilityHandler);
153
+ const activityEvents = ['mousemove', 'click', 'keydown', 'scroll', 'touchstart'];
154
+ activityEvents.forEach(evt => window.removeEventListener(evt, this.boundActivityHandler));
181
155
  if (this.inactivityTimer) {
182
156
  clearTimeout(this.inactivityTimer);
183
- this.inactivityTimer = null;
184
157
  }
185
- // FIX 3: Remove all registered listeners to prevent accumulation on re-instantiation
186
- document.removeEventListener('visibilitychange', this.boundVisibilityHandler);
187
- window.removeEventListener('beforeunload', this.boundBeforeUnload);
188
- const activityEvents = ['mousemove', 'click', 'keydown', 'scroll'];
189
- activityEvents.forEach((ev) => {
190
- window.removeEventListener(ev, this.boundActivityHandler);
191
- });
192
158
  this.stopRecording();
159
+ this.seq = 0; // Truly end the session sequence
193
160
  }
194
- /**
195
- * Packages buffered events into a payload and publishes to the broker.
196
- */
197
161
  flush() {
198
162
  if (this.events.length === 0)
199
163
  return;
200
- // FIX 2: Validate that the chunk starts with a proper snapshot before flushing.
201
- // A valid replayable chunk must begin with either:
202
- // [Meta(4), FullSnapshot(2), ...] or [FullSnapshot(2), ...]
203
- // If neither pattern is present, the chunk is corrupt and cannot be replayed.
204
- const firstEvent = this.events[0];
205
- const startsWithMeta = firstEvent?.type === 4;
206
- const secondEvent = this.events[1];
207
- const hasFullSnapshot = startsWithMeta
208
- ? secondEvent?.type === 2
209
- : firstEvent?.type === 2;
210
- if (!hasFullSnapshot) {
211
- if (this.cfg.mode === 'dev') {
212
- console.warn('[Nommos Tracker] Flush aborted: chunk does not start with a FullSnapshot. First event type:', firstEvent?.type);
213
- }
214
- this.events = [];
215
- this.currentChunkBytes = 0;
216
- return;
217
- }
218
- /**
219
- * Idle Prevention:
220
- * rrweb event types: 0=DomContentLoaded, 1=Load, 2=FullSnapshot, 3=IncrementalSnapshot, 4=Meta, 5=Custom
221
- * We only want to publish the chunk if it contains actual user activity (IncrementalSnapshot).
222
- */
223
- const hasActivity = this.events.some((e) => e.type === 3);
224
- if (!hasActivity) {
225
- if (this.cfg.mode === 'dev') {
226
- console.log('[Nommos Tracker] Session flush skipped: No user activity in this chunk.');
227
- }
228
- // Clear the buffer even if we skip flushing.
229
- // The next chunk will start with its own fresh snapshot from the checkout event.
230
- this.events = [];
231
- this.currentChunkBytes = 0;
232
- return;
233
- }
234
164
  const payload = {
235
- brandId: this.cfg.brand_id || '',
165
+ apiKey: this.cfg.token || '',
236
166
  bid: this.bid,
237
- channel: this.channel,
238
- page: window.location.pathname,
239
- fullUrl: window.location.href,
167
+ sessionId: this.sessionId,
168
+ ip: this.ip,
169
+ seq: this.seq++,
240
170
  timestamp: Date.now(),
241
- screen: {
242
- width: window.innerWidth,
243
- height: window.innerHeight,
244
- },
171
+ page: window.location.href,
245
172
  events: [...this.events],
246
173
  };
247
174
  if (this.cfg.mode === 'dev') {
248
- console.log('[Nommos Tracker] Flushing Session Recording Chunk:', payload.events.length, 'events');
175
+ console.log('[Nommos Tracker] Flushing Session Recording Chunk:', payload.events.length, 'events (seq:', payload.seq, ')');
176
+ }
177
+ try {
178
+ const compressed = pako.gzip(JSON.stringify(payload));
179
+ // Send raw binary Body instead of Base64 string for production efficiency
180
+ this.ws.publishSessionRecordingMessage(compressed);
181
+ }
182
+ catch (e) {
183
+ if (this.cfg.mode === 'dev') {
184
+ console.error('[Nommos Tracker] Compression or request preparation failed', e);
185
+ }
249
186
  }
250
- this.ws.publishSessionRecordingMessage(payload);
251
- // Clear buffer and reset byte counter
187
+ // Clear buffer
252
188
  this.events = [];
253
- this.currentChunkBytes = 0;
189
+ this.currentChunkSizeBytes = 0;
254
190
  }
255
191
  }
256
192
  //# sourceMappingURL=session-tracker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-tracker.js","sourceRoot":"","sources":["../../../../../nommos/core/src/lib/session-tracker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-tracker.js","sourceRoot":"","sources":["../../../../../nommos/core/src/lib/session-tracker.ts"],"names":[],"mappings":"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"}
@@ -5,11 +5,9 @@ export interface ConnectionConfig {
5
5
  }
6
6
  export interface TrackingControls {
7
7
  action_tracking_enabled: boolean;
8
- heatmap_tracking_enabled: boolean;
9
8
  session_tracking_enabled: boolean;
10
9
  session_chunk_duration_ms?: number;
11
10
  session_inactivity_timeout_ms?: number;
12
- heatmap_flush_interval_ms?: number;
13
11
  }
14
12
  export interface AdEventConfig {
15
13
  pixel_id: string;
@@ -38,8 +36,6 @@ export interface FullConfig extends ConnectionConfig {
38
36
  reconnectDelay?: number;
39
37
  enableTracking?: boolean;
40
38
  masterEnabled?: boolean;
41
- heatmapInterval?: number;
42
- heatmapThreshold?: number;
43
39
  controls?: TrackingControls;
44
40
  ads_events?: AdsEventsConfig;
45
41
  }
@@ -59,47 +55,18 @@ export interface AnalyticsEvent {
59
55
  bid: string;
60
56
  ip?: string;
61
57
  brand_id?: number | string;
58
+ sessionId: string;
62
59
  data?: Record<string, unknown>;
63
60
  meta?: Record<string, unknown>;
64
61
  }
65
- export interface HeatmapPoint {
66
- x: number;
67
- y: number;
68
- value: number;
69
- }
70
- export interface ScrollBand {
71
- depth: number;
72
- value: number;
73
- }
74
- export interface HeatmapPayload {
75
- brandId: string | number;
76
- bid: string;
77
- channel: number;
78
- page: string;
79
- fullUrl: string;
80
- timestamp: number;
81
- screen: {
82
- width: number;
83
- height: number;
84
- };
85
- heatmaps: {
86
- clicks: HeatmapPoint[];
87
- movement: HeatmapPoint[];
88
- scroll: ScrollBand[];
89
- };
90
- screenshot?: string;
91
- }
92
62
  export interface SessionRecordingPayload {
93
- brandId: string | number;
63
+ apiKey: string;
94
64
  bid: string;
95
- channel: number;
96
- page: string;
97
- fullUrl: string;
65
+ sessionId: string;
66
+ ip: string;
67
+ seq: number;
98
68
  timestamp: number;
99
- screen: {
100
- width: number;
101
- height: number;
102
- };
69
+ page: string;
103
70
  events: any[];
104
71
  }
105
72
  export interface TTLStringArray {
@@ -1,4 +1,4 @@
1
- import { AnalyticsEvent, FullConfig, HeatmapPayload, SessionRecordingPayload } from './types';
1
+ import { AnalyticsEvent, FullConfig, SessionRecordingPayload } from './types';
2
2
  /**
3
3
  * WebSocketClient
4
4
  * ----------------
@@ -24,6 +24,7 @@ export declare class WebSocketClient {
24
24
  * becomes connected. They are automatically flushed on connection.
25
25
  */
26
26
  pendingEvents: AnalyticsEvent[];
27
+ pendingSessions: (SessionRecordingPayload | string | Uint8Array)[];
27
28
  private readonly stompAnalyticsConnected;
28
29
  /**
29
30
  * Reactive connection state for consumers who want to listen for
@@ -61,18 +62,12 @@ export declare class WebSocketClient {
61
62
  * @param payload The analytics event to send.
62
63
  */
63
64
  publishAnalyticsMessage(payload: AnalyticsEvent): void;
64
- /**
65
- * Publishes an aggregated heatmap payload to the user-heatmap queue.
66
- *
67
- * @param payload The heatmap data to send.
68
- */
69
- publishHeatmapMessage(payload: HeatmapPayload): void;
70
65
  /**
71
66
  * Publishes a session recording payload to the user.session.recording queue.
72
67
  *
73
68
  * @param payload The session recording data to send.
74
69
  */
75
- publishSessionRecordingMessage(payload: SessionRecordingPayload): void;
70
+ publishSessionRecordingMessage(payload: SessionRecordingPayload | string | Uint8Array): void;
76
71
  /**
77
72
  * Gracefully shuts down the STOMP client and updates connection status.
78
73
  *
@@ -1,6 +1,6 @@
1
1
  import { Client } from '@stomp/stompjs';
2
2
  import { BehaviorSubject } from 'rxjs';
3
- import { ANALYTICS_QUEUE, HEATMAP_QUEUE, SESSION_RECORDING_QUEUE } from './constants';
3
+ import { ANALYTICS_QUEUE, MAX_BUFFERED_CHUNKS, SESSION_RECORDING_QUEUE } from './constants';
4
4
  /**
5
5
  * WebSocketClient
6
6
  * ----------------
@@ -27,6 +27,7 @@ export class WebSocketClient {
27
27
  * becomes connected. They are automatically flushed on connection.
28
28
  */
29
29
  this.pendingEvents = [];
30
+ this.pendingSessions = [];
30
31
  this.stompAnalyticsConnected = new BehaviorSubject(false);
31
32
  /**
32
33
  * Reactive connection state for consumers who want to listen for
@@ -90,6 +91,10 @@ export class WebSocketClient {
90
91
  this.publishAnalyticsMessage(m);
91
92
  }
92
93
  this.pendingEvents = [];
94
+ for (const s of this.pendingSessions) {
95
+ this.publishSessionRecordingMessage(s);
96
+ }
97
+ this.pendingSessions = [];
93
98
  };
94
99
  this.analyticsClient.onStompError = (frame) => {
95
100
  if (this.cfg?.mode === 'dev') {
@@ -120,23 +125,6 @@ export class WebSocketClient {
120
125
  body: JSON.stringify(payload),
121
126
  });
122
127
  }
123
- /**
124
- * Publishes an aggregated heatmap payload to the user-heatmap queue.
125
- *
126
- * @param payload The heatmap data to send.
127
- */
128
- publishHeatmapMessage(payload) {
129
- if (!this.analyticsClient?.connected || this.analyticsClient == null) {
130
- // We don't buffer heatmap data for now to avoid memory bloat,
131
- // as they are aggregated and sent in batches anyway.
132
- return;
133
- }
134
- this.analyticsClient.publish({
135
- destination: HEATMAP_QUEUE,
136
- headers: { 'content-type': 'application/json' },
137
- body: JSON.stringify(payload),
138
- });
139
- }
140
128
  /**
141
129
  * Publishes a session recording payload to the user.session.recording queue.
142
130
  *
@@ -144,12 +132,25 @@ export class WebSocketClient {
144
132
  */
145
133
  publishSessionRecordingMessage(payload) {
146
134
  if (!this.analyticsClient?.connected || this.analyticsClient == null) {
135
+ this.pendingSessions.push(payload);
136
+ // Memory Guard: Drop oldest chunks if buffer exceeds limit
137
+ if (this.pendingSessions.length > MAX_BUFFERED_CHUNKS) {
138
+ this.pendingSessions.shift();
139
+ if (this.cfg?.mode === 'dev') {
140
+ console.warn('[Nommos Tracker] Session recording buffer full. Dropping oldest chunk.');
141
+ }
142
+ }
147
143
  return;
148
144
  }
145
+ const isCompressed = typeof payload === 'string' || payload instanceof Uint8Array;
146
+ const isBinary = payload instanceof Uint8Array;
149
147
  this.analyticsClient.publish({
150
148
  destination: SESSION_RECORDING_QUEUE,
151
- headers: { 'content-type': 'application/json' },
152
- body: JSON.stringify(payload),
149
+ headers: {
150
+ 'content-type': isBinary ? 'application/octet-stream' : isCompressed ? 'text/plain' : 'application/json',
151
+ ...(isCompressed && { 'content-encoding': 'gzip' }),
152
+ },
153
+ ...(isBinary ? { binaryBody: payload } : { body: isCompressed ? payload : JSON.stringify(payload) }),
153
154
  });
154
155
  }
155
156
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"webSocket-client.js","sourceRoot":"","sources":["../../../../../nommos/core/src/lib/webSocket-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"webSocket-client.js","sourceRoot":"","sources":["../../../../../nommos/core/src/lib/webSocket-client.ts"],"names":[],"mappings":"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"}
@@ -1,50 +0,0 @@
1
- import { FullConfig } from './types';
2
- import { WebSocketClient } from './webSocket-client';
3
- export declare class HeatmapTracker {
4
- private readonly ws;
5
- private readonly cfg;
6
- private readonly browserId;
7
- private readonly channel;
8
- private clicks;
9
- private movement;
10
- private scrollBands;
11
- private eventCount;
12
- private lastMoveTime;
13
- private lastX;
14
- private lastY;
15
- private moveEventCounter;
16
- private maxScroll;
17
- private reachedBands;
18
- private activePageKey;
19
- private activePagePath;
20
- private activePageUrl;
21
- private observer;
22
- private quiescenceTimer;
23
- private visibilityTimer;
24
- private hasFirstEvent;
25
- private static screenshotStore;
26
- constructor(ws: WebSocketClient, cfg: FullConfig, browserId: string, channel: number);
27
- /**
28
- * Starts global event listeners for heatmap collection.
29
- */
30
- start(): void;
31
- private patchHistoryApi;
32
- private setupMutationObserver;
33
- private resetQuiescenceTimer;
34
- private handleNavigation;
35
- private updateContext;
36
- private capturePageScreenshot;
37
- /**
38
- * Stops listeners and flushes remaining data.
39
- */
40
- stop(): void;
41
- private handleClick;
42
- private handleMouseMove;
43
- private handleScroll;
44
- private handleVisibilityChange;
45
- private recordPoint;
46
- private incrementAndCheck;
47
- private flush;
48
- private mapToPoints;
49
- private mapToScroll;
50
- }