@sessionvision/core 0.3.0 → 0.4.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.
Files changed (38) hide show
  1. package/README.md +14 -11
  2. package/dist/react/core/config.d.ts +14 -1
  3. package/dist/react/core/init.d.ts +25 -0
  4. package/dist/react/recorder/chunk.d.ts +59 -0
  5. package/dist/react/recorder/index.d.ts +46 -0
  6. package/dist/react/recorder/mask.d.ts +13 -0
  7. package/dist/react/recorder/rrweb.d.ts +19 -0
  8. package/dist/react/recorder/upload.d.ts +20 -0
  9. package/dist/react/types.d.ts +37 -1
  10. package/dist/sessionvision-recorder.js +13041 -0
  11. package/dist/sessionvision-recorder.js.map +1 -0
  12. package/dist/sessionvision-recorder.min.js +7 -0
  13. package/dist/sessionvision-recorder.min.js.map +1 -0
  14. package/dist/sessionvision.cjs.js +284 -12
  15. package/dist/sessionvision.cjs.js.map +1 -1
  16. package/dist/sessionvision.esm.js +284 -12
  17. package/dist/sessionvision.esm.js.map +1 -1
  18. package/dist/sessionvision.js +284 -12
  19. package/dist/sessionvision.js.map +1 -1
  20. package/dist/sessionvision.min.js +2 -2
  21. package/dist/sessionvision.min.js.map +1 -1
  22. package/dist/types/core/config.d.ts +14 -1
  23. package/dist/types/core/init.d.ts +25 -0
  24. package/dist/types/recorder/chunk.d.ts +59 -0
  25. package/dist/types/recorder/index.d.ts +46 -0
  26. package/dist/types/recorder/mask.d.ts +13 -0
  27. package/dist/types/recorder/rrweb.d.ts +19 -0
  28. package/dist/types/recorder/upload.d.ts +20 -0
  29. package/dist/types/types.d.ts +37 -1
  30. package/dist/vue/core/config.d.ts +14 -1
  31. package/dist/vue/core/init.d.ts +25 -0
  32. package/dist/vue/recorder/chunk.d.ts +59 -0
  33. package/dist/vue/recorder/index.d.ts +46 -0
  34. package/dist/vue/recorder/mask.d.ts +13 -0
  35. package/dist/vue/recorder/rrweb.d.ts +19 -0
  36. package/dist/vue/recorder/upload.d.ts +20 -0
  37. package/dist/vue/types.d.ts +37 -1
  38. package/package.json +5 -2
package/README.md CHANGED
@@ -39,12 +39,15 @@ sessionvision.init('proj_abc123', {
39
39
  ```tsx
40
40
  import { SessionVisionProvider, useCapture } from '@sessionvision/core/react';
41
41
 
42
- function App() {
42
+ function TrackButton() {
43
43
  const capture = useCapture();
44
+ return <button onClick={() => capture('cta_clicked')}>Track</button>;
45
+ }
44
46
 
47
+ function App() {
45
48
  return (
46
- <SessionVisionProvider apiKey={import.meta.env.VITE_SESSIONVISION_KEY}>
47
- <button onClick={() => capture('cta_clicked')}>Track</button>
49
+ <SessionVisionProvider apiKey="your_project_token">
50
+ <TrackButton />
48
51
  </SessionVisionProvider>
49
52
  );
50
53
  }
@@ -58,7 +61,7 @@ import { createSessionVision } from '@sessionvision/core/vue';
58
61
  import App from './App.vue';
59
62
 
60
63
  const app = createApp(App);
61
- app.use(createSessionVision(import.meta.env.VITE_SESSIONVISION_KEY));
64
+ app.use(createSessionVision('your_project_token'));
62
65
  app.mount('#app');
63
66
  ```
64
67
 
@@ -119,12 +122,9 @@ npm run test:e2e:headed
119
122
  npm run test:e2e:debug
120
123
  ```
121
124
 
122
- E2E tests are located in `tests/e2e/` and run against multiple browsers:
125
+ E2E tests are located in `tests/e2e/` and run against:
123
126
  - Chromium (Desktop)
124
- - Firefox (Desktop)
125
- - WebKit/Safari (Desktop)
126
127
  - Chrome Mobile (Pixel 5 emulation)
127
- - Safari Mobile (iPhone 12 emulation)
128
128
 
129
129
  #### E2E Test Infrastructure
130
130
 
@@ -227,9 +227,9 @@ The SDK exposes the following methods on the global `sessionvision` object:
227
227
  sessionvision.init('your_project_token', {
228
228
  apiHost: 'https://api.example.com',
229
229
  autocapture: {
230
- pageviews: true,
231
- clicks: true,
232
- forms: true
230
+ pageview: true,
231
+ click: true,
232
+ formSubmit: true
233
233
  }
234
234
  });
235
235
 
@@ -250,6 +250,9 @@ sessionvision.register({ app_version: '2.1.0' });
250
250
 
251
251
  // Register properties only if not already set
252
252
  sessionvision.registerOnce({ initial_referrer: document.referrer });
253
+
254
+ // Manually flush the event buffer (useful before navigation)
255
+ await sessionvision.flushEvents();
253
256
  ```
254
257
 
255
258
  ## Architecture
@@ -7,10 +7,22 @@ import { SessionVisionConfig, ResolvedConfig, RemoteConfig } from '../types';
7
7
  * Resolve user config with defaults
8
8
  */
9
9
  export declare function resolveConfig(projectToken: string, userConfig?: SessionVisionConfig): ResolvedConfig;
10
+ /**
11
+ * Get cached remote config if valid (exported for fast path in init.ts)
12
+ */
13
+ export declare function getCachedRemoteConfig(projectToken: string): RemoteConfig | null;
14
+ /**
15
+ * Resolve the recorder bundle URL relative to the SDK's apiHost
16
+ */
17
+ export declare function resolveRecorderUrl(config: ResolvedConfig): string;
18
+ interface FetchRemoteConfigOptions {
19
+ /** Inject <link rel="prefetch"> for the recorder bundle (for first-time visitors with no cache) */
20
+ prefetchRecorder?: boolean;
21
+ }
10
22
  /**
11
23
  * Fetch remote configuration from server
12
24
  */
13
- export declare function fetchRemoteConfig(resolvedConfig: ResolvedConfig): Promise<RemoteConfig | null>;
25
+ export declare function fetchRemoteConfig(resolvedConfig: ResolvedConfig, options?: FetchRemoteConfigOptions): Promise<RemoteConfig | null>;
14
26
  /**
15
27
  * Apply remote config settings
16
28
  */
@@ -19,3 +31,4 @@ export declare function applyRemoteConfig(remoteConfig: RemoteConfig): void;
19
31
  * Get default remote config for offline mode
20
32
  */
21
33
  export declare function getDefaultRemoteConfig(): RemoteConfig;
34
+ export {};
@@ -47,6 +47,31 @@ export declare function isSDKInitialized(): boolean;
47
47
  * Get the current configuration
48
48
  */
49
49
  export declare function getConfig(): ResolvedConfig | null;
50
+ /**
51
+ * Manually start recording. Respects remote config — no-op if recording.enabled is false.
52
+ * Bypasses sampling when recording is enabled.
53
+ */
54
+ export declare function startRecording(): Promise<void>;
55
+ /**
56
+ * Stop recording for this session
57
+ */
58
+ export declare function stopRecording(): void;
59
+ /**
60
+ * Check if recording is active
61
+ */
62
+ export declare function isRecording(): boolean;
63
+ /**
64
+ * Tag the current recording with custom metadata
65
+ */
66
+ export declare function tagRecordingFn(tags: Record<string, string>): void;
67
+ /**
68
+ * Subscribe to SDK events
69
+ */
70
+ export declare function onEvent(event: string, callback: (data?: unknown) => void): void;
71
+ /**
72
+ * Unsubscribe from SDK events
73
+ */
74
+ export declare function offEvent(event: string, callback: (data?: unknown) => void): void;
50
75
  /**
51
76
  * Reset for testing
52
77
  */
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Chunk manager for recording events
3
+ * Buffers rrweb events and manages chunked uploads
4
+ */
5
+ import { RecordingEvent, ResolvedConfig } from '../types';
6
+ type EventEmitFn = (event: string, data?: unknown) => void;
7
+ interface ChunkManagerOptions {
8
+ config: ResolvedConfig;
9
+ emit: EventEmitFn;
10
+ }
11
+ export declare class ChunkManager {
12
+ private buffer;
13
+ private bufferSize;
14
+ private chunkNumber;
15
+ private lastFlush;
16
+ private flushTimer;
17
+ private config;
18
+ private emit;
19
+ private tags;
20
+ private chunkStartTime;
21
+ private hasFullSnapshot;
22
+ private started;
23
+ constructor(options: ChunkManagerOptions);
24
+ /**
25
+ * Start the chunk manager flush timer
26
+ */
27
+ start(): void;
28
+ /**
29
+ * Stop the chunk manager
30
+ */
31
+ stop(): void;
32
+ /**
33
+ * Add an rrweb event to the buffer
34
+ */
35
+ addEvent(event: RecordingEvent): void;
36
+ /**
37
+ * Set tags to be sent with the next chunk
38
+ */
39
+ setTags(tags: Record<string, string>): void;
40
+ /**
41
+ * Check if the buffer should be flushed
42
+ */
43
+ private shouldFlush;
44
+ /**
45
+ * Flush the buffer — send accumulated events as a chunk
46
+ */
47
+ flush(): void;
48
+ /**
49
+ * Get the current chunk number (for testing)
50
+ */
51
+ getChunkNumber(): number;
52
+ /**
53
+ * Get the current buffer size in bytes (for testing)
54
+ */
55
+ getBufferSize(): number;
56
+ private handleVisibilityChange;
57
+ private handleBeforeUnload;
58
+ }
59
+ export {};
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Session Recorder entry point
3
+ * Handles initialization, sampling decision, and lifecycle management
4
+ */
5
+ import { RemoteConfig, ResolvedConfig } from '../types';
6
+ type EventListener = (data?: unknown) => void;
7
+ export declare function on(event: string, callback: EventListener): void;
8
+ export declare function off(event: string, callback: EventListener): void;
9
+ /**
10
+ * Deterministic sampling based on session ID
11
+ * Same session always gets same result (important for multi-page sessions)
12
+ */
13
+ export declare function shouldRecordSession(sampleRate: number, sessionId: string): boolean;
14
+ /**
15
+ * Initialize the recorder — called after the recorder bundle is loaded
16
+ */
17
+ export declare function initRecorder(config: ResolvedConfig, _remoteConfig: RemoteConfig): void;
18
+ /**
19
+ * Stop the recorder
20
+ */
21
+ export declare function stopRecorder(): void;
22
+ /**
23
+ * Check if the recorder is currently active
24
+ */
25
+ export declare function isRecorderActive(): boolean;
26
+ /**
27
+ * Tag the current recording with custom metadata
28
+ */
29
+ export declare function tagRecording(tags: Record<string, string>): void;
30
+ /**
31
+ * Reset recorder state (for testing)
32
+ */
33
+ export declare function _resetRecorder(): void;
34
+ /**
35
+ * Recorder module interface (exposed via global for script-based loading)
36
+ */
37
+ export interface RecorderModule {
38
+ initRecorder: typeof initRecorder;
39
+ stopRecorder: typeof stopRecorder;
40
+ isRecorderActive: typeof isRecorderActive;
41
+ tagRecording: typeof tagRecording;
42
+ shouldRecordSession: typeof shouldRecordSession;
43
+ on: typeof on;
44
+ off: typeof off;
45
+ }
46
+ export {};
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Privacy & masking bridge for session recordings
3
+ * Bridges rrweb's masking callbacks with the SDK's existing PII detection
4
+ */
5
+ /**
6
+ * Mask text content for rrweb's maskTextFn callback
7
+ */
8
+ export declare function maskTextForRecording(text: string): string;
9
+ /**
10
+ * Mask input values for rrweb's maskInputFn callback
11
+ * Respects data-sessionvision-unmask attribute
12
+ */
13
+ export declare function maskInputForRecording(text: string, element: HTMLElement): string;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * rrweb integration module
3
+ * Wraps rrweb with configured capture options and handles events
4
+ */
5
+ import { RecordingEvent, ResolvedConfig } from '../types';
6
+ type EventCallback = (event: RecordingEvent) => void;
7
+ /**
8
+ * Start rrweb recording
9
+ */
10
+ export declare function startRrwebRecording(config: ResolvedConfig, onEvent: EventCallback): void;
11
+ /**
12
+ * Stop rrweb recording
13
+ */
14
+ export declare function stopRrwebRecording(): void;
15
+ /**
16
+ * Check if rrweb is currently recording
17
+ */
18
+ export declare function isRrwebRecording(): boolean;
19
+ export {};
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Upload manager for recording chunks
3
+ * Sends recording chunks to the ingest API as $recording events
4
+ */
5
+ import { RecordingEvent, ResolvedConfig } from '../types';
6
+ interface ChunkPayload {
7
+ chunkNumber: number;
8
+ startTime: number;
9
+ endTime: number;
10
+ events: RecordingEvent[];
11
+ fullSnapshotIncluded: boolean;
12
+ tags?: Record<string, string>;
13
+ isFirstChunk: boolean;
14
+ }
15
+ /**
16
+ * Send a recording chunk to the ingest API
17
+ * Uses the same endpoint as regular events with the $recording event name
18
+ */
19
+ export declare function sendRecordingChunk(config: ResolvedConfig, chunk: ChunkPayload): Promise<boolean>;
20
+ export {};
@@ -36,6 +36,10 @@ export interface SessionVisionConfig {
36
36
  maskAllInputs?: boolean;
37
37
  /** Enable/disable auto-capture (default: true) */
38
38
  autocapture?: boolean | AutocaptureConfig;
39
+ /** Override recording behavior. Set false to force-disable regardless of remote config. */
40
+ recording?: false | {
41
+ maskAllInputs?: boolean;
42
+ };
39
43
  }
40
44
  /**
41
45
  * Internal resolved configuration
@@ -56,6 +60,9 @@ export interface ResolvedConfig {
56
60
  deadClick: boolean;
57
61
  formAbandonment: boolean;
58
62
  };
63
+ recording?: false | {
64
+ maskAllInputs?: boolean;
65
+ };
59
66
  }
60
67
  /**
61
68
  * Remote configuration fetched from server
@@ -264,6 +271,18 @@ export interface SessionVisionAPI {
264
271
  registerOnce(properties: EventProperties): void;
265
272
  /** Manually flush the event buffer */
266
273
  flushEvents(): Promise<void>;
274
+ /** Subscribe to SDK events (e.g., 'recording:error', 'recording:quota_exceeded') */
275
+ on(event: string, callback: (data?: unknown) => void): void;
276
+ /** Unsubscribe from SDK events */
277
+ off(event: string, callback: (data?: unknown) => void): void;
278
+ /** Manually start recording. Respects remote config — no-op if recording.enabled is false. Bypasses sampling when recording is enabled. */
279
+ startRecording(): void;
280
+ /** Stop recording for this session */
281
+ stopRecording(): void;
282
+ /** Check if recording is active */
283
+ isRecording(): boolean;
284
+ /** Tag the current recording with custom metadata */
285
+ tagRecording(tags: Record<string, string>): void;
267
286
  /** SDK version */
268
287
  version: string;
269
288
  /** Internal: queued method calls before SDK loads */
@@ -273,6 +292,23 @@ export interface SessionVisionAPI {
273
292
  /** Internal: SDK version marker */
274
293
  __SV?: number;
275
294
  }
295
+ /**
296
+ * Recording event type (rrweb event)
297
+ */
298
+ export interface RecordingEvent {
299
+ type: number;
300
+ data: unknown;
301
+ timestamp: number;
302
+ }
303
+ /**
304
+ * Recording chunk configuration
305
+ */
306
+ export declare const RECORDING_CONFIG: {
307
+ readonly FLUSH_INTERVAL_MS: 5000;
308
+ readonly MAX_BUFFER_SIZE_BYTES: number;
309
+ readonly FULL_SNAPSHOT_INTERVAL_MS: number;
310
+ readonly RETRY_DELAY_MS: 2000;
311
+ };
276
312
  /**
277
313
  * Storage key constants
278
314
  */
@@ -302,6 +338,6 @@ export declare const BUFFER_CONFIG: {
302
338
  readonly RETRY_DELAYS_MS: readonly [1000, 2000, 4000];
303
339
  };
304
340
  /**
305
- * Config cache TTL in milliseconds (1 hour)
341
+ * Config cache TTL in milliseconds (4 hours)
306
342
  */
307
343
  export declare const CONFIG_CACHE_TTL_MS: number;