@logspace/sdk 1.0.2 → 1.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logspace/sdk",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "LogSpace JavaScript SDK for session recording and logging",
5
5
  "type": "module",
6
6
  "main": "./logspace.umd.js",
@@ -19,7 +19,6 @@
19
19
  }
20
20
  },
21
21
  "files": [
22
- "README.md",
23
22
  "logspace.esm.js",
24
23
  "logspace.esm.js.map",
25
24
  "logspace.umd.js",
@@ -38,5 +37,8 @@
38
37
  "monitoring"
39
38
  ],
40
39
  "author": "LogSpace",
41
- "license": "MIT"
40
+ "license": "MIT",
41
+ "scripts": {
42
+ "preinstall": "npx only-allow bun && bun --version | grep -q '^1.2.21$' || (echo 'Error: Bun version 1.2.21 is required' && exit 1)"
43
+ }
42
44
  }
@@ -1,7 +1,7 @@
1
1
  import { LogEntry, LogType } from '../../shared/types';
2
2
  import { CaptureHandler, PrivacyConfig } from '../types';
3
- import { generateId, safeStringify, maskSensitiveData, maskHeaders } from '../../shared/utils';
4
- export { generateId, safeStringify, maskSensitiveData, maskHeaders };
3
+ import { generateId, safeStringify, maskSensitiveData, maskHeaders, maskConsoleArgs } from '../../shared/utils';
4
+ export { generateId, safeStringify, maskSensitiveData, maskHeaders, maskConsoleArgs };
5
5
  /**
6
6
  * Check if running in browser environment (SSR safety)
7
7
  */
@@ -39,7 +39,9 @@ export declare function applyPrivacy(log: LogEntry, privacy: PrivacyConfig): Log
39
39
  */
40
40
  export interface CaptureModule {
41
41
  name: string;
42
- install(handler: CaptureHandler, privacy: PrivacyConfig): void;
42
+ install(handler: CaptureHandler, privacy: PrivacyConfig, onActivity?: () => void, limits?: {
43
+ maxNetworkBodySize?: number;
44
+ }): void;
43
45
  uninstall(): void;
44
46
  reset?(): void;
45
47
  }
@@ -1,5 +1,2 @@
1
1
  import { CaptureModule } from './base';
2
- /**
3
- * SSE capture module
4
- */
5
2
  export declare const sseCapture: CaptureModule;
@@ -1,5 +1,2 @@
1
1
  import { CaptureModule } from './base';
2
- /**
3
- * WebSocket capture module
4
- */
5
2
  export declare const websocketCapture: CaptureModule;
package/sdk/index.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import { LogEntry } from '../shared/types';
2
- import { LogSpaceConfig, SDKSession, SessionPayload } from './types';
2
+ import { LogSpaceConfig, NormalizedConfig, SDKSession, SessionPayload } from './types';
3
3
  import { eventWithTime } from './capture/rrweb';
4
4
  export declare const LogSpace: {
5
5
  /**
6
6
  * Initialize the SDK
7
+ * @throws Error if SDK is already initialized
7
8
  */
8
9
  init(userConfig: LogSpaceConfig): void;
9
10
  /**
@@ -16,6 +17,7 @@ export declare const LogSpace: {
16
17
  stopSession(): Promise<void>;
17
18
  /**
18
19
  * Identify user
20
+ * If called before session starts, the identity will be queued and applied when session starts
19
21
  */
20
22
  identify(userId: string, traits?: Record<string, any>): void;
21
23
  /**
@@ -55,6 +57,28 @@ export declare const LogSpace: {
55
57
  * Get rrweb events for current session
56
58
  */
57
59
  getRRWebEvents(): eventWithTime[];
60
+ /**
61
+ * Get current configuration (read-only)
62
+ * Returns the full NormalizedConfig plus convenience top-level fields
63
+ * that match the setConfig() interface for easy verification
64
+ */
65
+ getConfig(): (NormalizedConfig & {
66
+ rateLimit: number;
67
+ maxLogs: number;
68
+ maxSize: number;
69
+ idleTimeout: number;
70
+ }) | null;
71
+ /**
72
+ * Update configuration at runtime
73
+ * Only certain settings can be changed after initialization
74
+ */
75
+ setConfig(updates: {
76
+ rateLimit?: number;
77
+ maxLogs?: number;
78
+ maxSize?: number;
79
+ idleTimeout?: number;
80
+ debug?: boolean;
81
+ }): void;
58
82
  /**
59
83
  * Destroy SDK
60
84
  */
@@ -45,6 +45,10 @@ export declare function getCurrentSessionBackup(): Promise<CurrentSessionBackup
45
45
  * Clear current session backup (called after successful send)
46
46
  */
47
47
  export declare function clearCurrentSessionBackup(): Promise<void>;
48
+ /**
49
+ * Clear current session backup only if it matches the provided session ID
50
+ */
51
+ export declare function clearCurrentSessionBackupFor(sessionId: string): Promise<void>;
48
52
  /**
49
53
  * Add a session to pending queue (for retry later)
50
54
  */
package/sdk/types.d.ts CHANGED
@@ -12,6 +12,7 @@ export type RecordingType = 'video' | 'rrweb';
12
12
  */
13
13
  export interface SDKSession {
14
14
  id: string;
15
+ tabId: string;
15
16
  startTime: number;
16
17
  endTime?: number;
17
18
  status: 'idle' | 'recording' | 'paused' | 'stopped';
@@ -96,7 +97,7 @@ export interface RRWebConfig {
96
97
  */
97
98
  recordCanvas?: boolean;
98
99
  /** Take a full DOM snapshot every N events
99
- * @default 200
100
+ * @default 150
100
101
  */
101
102
  checkoutEveryNth?: number;
102
103
  }
@@ -146,7 +147,7 @@ export interface SessionLimits {
146
147
  */
147
148
  maxDuration?: number;
148
149
  /** Idle timeout in seconds - auto-end if no activity
149
- * @default 30
150
+ * @default 120
150
151
  */
151
152
  idleTimeout?: number;
152
153
  /** Navigate away timeout in seconds - grace period when tab becomes hidden
@@ -162,6 +163,10 @@ export interface SessionLimits {
162
163
  * @default true
163
164
  */
164
165
  deduplicate?: boolean;
166
+ /** Maximum size for network request/response bodies in bytes
167
+ * @default 10240 (10KB)
168
+ */
169
+ maxNetworkBodySize?: number;
165
170
  }
166
171
  /**
167
172
  * Session end triggers
@@ -193,11 +198,11 @@ export interface SamplingConfig {
193
198
  */
194
199
  enabled?: boolean;
195
200
  /** Seconds of logs to keep before the trigger event
196
- * @default 15
201
+ * @default 30
197
202
  */
198
203
  bufferBefore?: number;
199
204
  /** Seconds to continue recording after the trigger event
200
- * @default 15
205
+ * @default 30
201
206
  */
202
207
  recordAfter?: number;
203
208
  /** What triggers a session to be saved */
@@ -244,6 +249,10 @@ export interface HooksConfig {
244
249
  * @default undefined
245
250
  */
246
251
  onSamplingTrigger?: (trigger: 'error' | 'consoleError' | 'networkError' | 'manual', log?: LogEntry) => void;
252
+ /** Called when a sampling session is discarded (no trigger occurred)
253
+ * @default undefined
254
+ */
255
+ onSessionDiscarded?: (session: SDKSession, reason: 'noTrigger' | 'idle' | 'maxDuration' | 'manual') => void;
247
256
  /** Called on transport/network errors
248
257
  * @default undefined
249
258
  */
@@ -266,7 +275,7 @@ export interface LogSpaceConfig {
266
275
  */
267
276
  capture?: CaptureConfig;
268
277
  /** rrweb DOM recording settings
269
- * @default { maskAllInputs: false, recordCanvas: false, checkoutEveryNth: 200 }
278
+ * @default { maskAllInputs: false, recordCanvas: false, checkoutEveryNth: 150 }
270
279
  */
271
280
  rrweb?: RRWebConfig;
272
281
  /** Privacy settings for masking sensitive data
@@ -274,7 +283,7 @@ export interface LogSpaceConfig {
274
283
  */
275
284
  privacy?: PrivacyConfig;
276
285
  /** Session limits for protection against memory issues
277
- * @default { maxLogs: 10000, maxSize: 10485760, maxDuration: 300, idleTimeout: 30, rateLimit: 100, deduplicate: true }
286
+ * @default { maxLogs: 10000, maxSize: 10485760, maxDuration: 1800, idleTimeout: 120, rateLimit: 100, deduplicate: true }
278
287
  */
279
288
  limits?: SessionLimits;
280
289
  /** Configure when to auto-end sessions
package/shared/types.d.ts CHANGED
@@ -11,6 +11,7 @@ export interface RecordingSession {
11
11
  cspBlocked?: boolean;
12
12
  title?: string;
13
13
  comment?: string;
14
+ videoStartTime?: number;
14
15
  }
15
16
  export interface TabRecording {
16
17
  tabId: number;
@@ -233,8 +234,17 @@ export interface RecordingSettings {
233
234
  excludeDomains: string[];
234
235
  maskSensitiveData: boolean;
235
236
  logLevels: LogSeverity[];
237
+ maxNetworkBodySize: number;
236
238
  }
237
239
  export declare const DEFAULT_SETTINGS: RecordingSettings;
240
+ export declare const API_TO_SETTINGS_KEY_MAP: Record<string, keyof RecordingSettings>;
241
+ export interface RemoteSettingsState {
242
+ disabledKeys: Set<keyof RecordingSettings>;
243
+ lastFetched: number | null;
244
+ loading: boolean;
245
+ error: string | null;
246
+ }
247
+ export declare function parseApiSettingValue(apiKey: string, value: string, valueType: string): any;
238
248
  export interface SessionStats {
239
249
  logCount: number;
240
250
  networkLogCount: number;
@@ -300,6 +310,101 @@ export declare enum MessageType {
300
310
  CSP_DETECTED = "CSP_DETECTED",// CSP blocked script injection
301
311
  FETCH_ASSIGNED_LOGS = "FETCH_ASSIGNED_LOGS"
302
312
  }
313
+ /**
314
+ * Internal message types used for communication between extension components
315
+ * These are not part of the public MessageType enum to avoid bloating it
316
+ *
317
+ * MESSAGE FLOW DOCUMENTATION:
318
+ *
319
+ * Background Script <-> Content Script:
320
+ * - REGISTER_TAB: Background registers a tab for recording
321
+ * - UNREGISTER_TAB: Background unregisters a tab
322
+ * - SHOW_COUNTDOWN: Background asks content to show countdown overlay
323
+ * - SELECT_AREA: Background asks content to show area selector
324
+ * - AREA_SELECTED: Content informs background of selected area
325
+ * - NETWORK_HEADERS_*: Background forwards network headers to content
326
+ * - show-webcam-overlay / hide-webcam-overlay: Webcam control
327
+ * - SAVE_ANNOTATION / SAVE_DRAWING_ANNOTATION: User annotations
328
+ * - STORAGE_SIZE_UPDATE: Background informs content of storage usage
329
+ * - SHOW_SAVE_MODAL / UPDATE_SAVE_MODAL_VIDEO: Save dialog control
330
+ *
331
+ * Background Script <-> Offscreen Document:
332
+ * - start-video-recording / stop-video-recording: Video recording control
333
+ * - start-display-media-recording: Screen capture control
334
+ * - test-microphone-permission / test-webcam-permission: Permission tests
335
+ * - start-microphone-visualization / stop-microphone-visualization: Audio levels
336
+ * - save-video: Offscreen sends video data to background
337
+ * - video-chunk-size: Offscreen reports chunk sizes
338
+ * - offscreen-log: Offscreen forwards logs to background
339
+ * - display-media-selected: User selected screen/window
340
+ * - microphone-audio-level: Audio visualization data
341
+ *
342
+ * Background Script <-> Popup:
343
+ * - CLOSE_POPUP: Background requests popup to close
344
+ * - RECORDING_STARTED / RECORDING_ERROR: Recording state notifications
345
+ * - All MessageType and AuthMessageType enums
346
+ */
347
+ export declare enum InternalMessageType {
348
+ PING = "ping",
349
+ GET_TAB_ID = "GET_TAB_ID",
350
+ CANCEL_AREA_SELECTION = "CANCEL_AREA_SELECTION",
351
+ SHOW_COUNTDOWN = "SHOW_COUNTDOWN",
352
+ COUNTDOWN_COMPLETE = "COUNTDOWN_COMPLETE",
353
+ SELECT_AREA = "SELECT_AREA",
354
+ AREA_SELECTED = "AREA_SELECTED",
355
+ AREA_SELECTION_CANCELLED = "AREA_SELECTION_CANCELLED",
356
+ NETWORK_HEADERS_REQUEST = "NETWORK_HEADERS_REQUEST",
357
+ NETWORK_HEADERS_RESPONSE = "NETWORK_HEADERS_RESPONSE",
358
+ SHOW_WEBCAM_OVERLAY = "show-webcam-overlay",
359
+ HIDE_WEBCAM_OVERLAY = "hide-webcam-overlay",
360
+ SAVE_ANNOTATION = "SAVE_ANNOTATION",
361
+ SAVE_DRAWING_ANNOTATION = "SAVE_DRAWING_ANNOTATION",
362
+ STORAGE_SIZE_UPDATE = "STORAGE_SIZE_UPDATE",
363
+ SHOW_SAVE_MODAL = "SHOW_SAVE_MODAL",
364
+ UPDATE_SAVE_MODAL_VIDEO = "UPDATE_SAVE_MODAL_VIDEO",
365
+ START_VIDEO_RECORDING = "start-video-recording",
366
+ STOP_VIDEO_RECORDING = "stop-video-recording",
367
+ START_DISPLAY_MEDIA_RECORDING = "start-display-media-recording",
368
+ TEST_MICROPHONE_PERMISSION = "test-microphone-permission",
369
+ TEST_WEBCAM_PERMISSION = "test-webcam-permission",
370
+ START_MICROPHONE_VISUALIZATION = "start-microphone-visualization",
371
+ STOP_MICROPHONE_VISUALIZATION = "stop-microphone-visualization",
372
+ SAVE_VIDEO = "save-video",
373
+ VIDEO_CHUNK_SIZE = "video-chunk-size",
374
+ OFFSCREEN_LOG = "offscreen-log",
375
+ DISPLAY_MEDIA_SELECTED = "display-media-selected",
376
+ MICROPHONE_AUDIO_LEVEL = "microphone-audio-level",
377
+ BEGIN_MEDIA_RECORDING = "begin-media-recording",
378
+ VIDEO_RECORDING_STARTED = "video-recording-started",
379
+ SCREEN_SHARE_ENDED = "screen-share-ended",// User clicked browser's "Stop sharing" button
380
+ CLOSE_POPUP = "CLOSE_POPUP",
381
+ RECORDING_STARTED = "RECORDING_STARTED",
382
+ RECORDING_ERROR = "RECORDING_ERROR",
383
+ LOGIN_SUCCESS = "LOGIN_SUCCESS",
384
+ LOGIN_FAILED = "LOGIN_FAILED",
385
+ STATE_UPDATE = "STATE_UPDATE",
386
+ LOG_UPDATE = "LOG_UPDATE",
387
+ SAVE_RECORDING_METADATA = "SAVE_RECORDING_METADATA",
388
+ GET_SESSION_LOGS = "GET_SESSION_LOGS",
389
+ GET_UPLOAD_FORM_DATA = "GET_UPLOAD_FORM_DATA",
390
+ SEARCH_PROJECTS = "SEARCH_PROJECTS",
391
+ SEARCH_ENVIRONMENTS = "SEARCH_ENVIRONMENTS",
392
+ SEARCH_USERS = "SEARCH_USERS",
393
+ UPLOAD_RECORDING = "UPLOAD_RECORDING",
394
+ CONNECT = "CONNECT"
395
+ }
396
+ /**
397
+ * Validate that a message has a valid type
398
+ * @param message The message to validate
399
+ * @returns true if the message has a valid type property
400
+ */
401
+ export declare function isValidMessage(message: unknown): boolean;
402
+ /**
403
+ * Check if a message type is a known type
404
+ * @param type The message type to check
405
+ * @returns true if the type is in MessageType, AuthMessageType, or InternalMessageType
406
+ */
407
+ export declare function isKnownMessageType(type: string): boolean;
303
408
  export interface Message {
304
409
  type: MessageType;
305
410
  payload?: any;
@@ -323,6 +428,7 @@ export interface StatusResponse {
323
428
  session: RecordingSession | null;
324
429
  error?: string;
325
430
  auth?: AuthState;
431
+ recordedTabIds?: number[];
326
432
  }
327
433
  export interface CspDetectedMessage extends Message {
328
434
  type: MessageType.CSP_DETECTED;
@@ -352,5 +458,6 @@ export interface AuthPollingState {
352
458
  export declare enum AuthMessageType {
353
459
  LOGIN_START = "LOGIN_START",
354
460
  LOGOUT = "LOGOUT",
355
- VALIDATE_AUTH = "VALIDATE_AUTH"
461
+ VALIDATE_AUTH = "VALIDATE_AUTH",
462
+ SYNC_SETTINGS = "SYNC_SETTINGS"
356
463
  }
package/shared/utils.d.ts CHANGED
@@ -27,10 +27,17 @@ export declare function safeStringify(value: any): string;
27
27
  * Mask sensitive data in strings for privacy protection
28
28
  */
29
29
  export declare function maskSensitiveData(text: string): string;
30
+ /**
31
+ * Mask console arguments, handling the case where label and value are separate args
32
+ * e.g., console.log("Password:", "secret") produces ["Password:", "secret"]
33
+ */
34
+ export declare function maskConsoleArgs(args: string[]): string[];
30
35
  /**
31
36
  * Mask sensitive data in HTTP headers for privacy protection
37
+ * @param headers - The headers object to mask
38
+ * @param additionalHeaders - Additional header names to redact (from config.privacy.redactHeaders)
32
39
  */
33
- export declare function maskHeaders(headers: Record<string, string>): Record<string, string>;
40
+ export declare function maskHeaders(headers: Record<string, string>, additionalHeaders?: string[]): Record<string, string>;
34
41
  /**
35
42
  * Check if a URL matches any of the excluded domain patterns
36
43
  * Supports regex patterns for flexible matching
package/README.md DELETED
@@ -1,269 +0,0 @@
1
- # @logspace/sdk
2
-
3
- A lightweight JavaScript SDK for session recording and debugging. Capture user sessions with DOM replay, console logs, network requests, errors, and more.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install @logspace/sdk
9
- ```
10
-
11
- ```bash
12
- yarn add @logspace/sdk
13
- ```
14
-
15
- ```bash
16
- pnpm add @logspace/sdk
17
- ```
18
-
19
- ## Quick Start
20
-
21
- ```javascript
22
- import LogSpace from '@logspace/sdk';
23
-
24
- // Initialize the SDK
25
- LogSpace.init({
26
- serverUrl: 'https://your-logspace-server.com',
27
- apiKey: 'project_id:environment_id',
28
- });
29
-
30
- // Start recording
31
- LogSpace.startSession();
32
-
33
- // Identify the user (optional)
34
- LogSpace.identify('user-123', {
35
- email: 'user@example.com',
36
- plan: 'pro',
37
- });
38
-
39
- // Track custom events
40
- LogSpace.track('button_clicked', { buttonId: 'submit' });
41
-
42
- // Add breadcrumbs for debugging
43
- LogSpace.breadcrumb('User opened settings', 'navigation');
44
-
45
- // Stop recording and send to server
46
- await LogSpace.stopSession();
47
- ```
48
-
49
- ## Features
50
-
51
- - 🎬 **DOM Recording** - Full visual replay using rrweb
52
- - 📝 **Console Logs** - Capture all console output (log, warn, error, debug)
53
- - 🌐 **Network Requests** - Track XHR and Fetch calls with timing
54
- - ❌ **Error Tracking** - Catch JavaScript errors and unhandled rejections
55
- - 🖱️ **User Interactions** - Record clicks, inputs, and scrolls
56
- - 📊 **Performance Metrics** - Core Web Vitals and resource timing
57
- - 🔌 **WebSocket & SSE** - Monitor real-time connections
58
- - 💾 **Storage Changes** - Track localStorage/sessionStorage modifications
59
- - 🔒 **Privacy First** - Built-in PII masking and data sanitization
60
-
61
- ## Configuration
62
-
63
- ```javascript
64
- LogSpace.init({
65
- // Server configuration
66
- serverUrl: 'https://your-server.com',
67
- apiKey: 'project_id:environment_id',
68
-
69
- // What to capture
70
- capture: {
71
- rrweb: true, // DOM recording
72
- console: true, // Console logs
73
- network: true, // Network requests
74
- errors: true, // JavaScript errors
75
- interactions: true, // User interactions
76
- performance: true, // Performance metrics
77
- websocket: true, // WebSocket connections
78
- sse: true, // Server-Sent Events
79
- storage: true, // localStorage/sessionStorage
80
- resources: true, // Resource loading
81
- spaNavigation: true, // SPA route changes
82
- },
83
-
84
- // rrweb settings
85
- rrweb: {
86
- maskAllInputs: false, // Mask all input values
87
- maskTextSelector: null, // CSS selector for text masking
88
- blockSelector: null, // CSS selector to block elements
89
- recordCanvas: false, // Record canvas content
90
- checkoutEveryNth: 200, // Full snapshot interval
91
- },
92
-
93
- // Privacy settings
94
- privacy: {
95
- maskSensitiveData: true, // Auto-mask PII patterns
96
- maskSelectors: [], // CSS selectors to mask
97
- excludeUrls: [], // URL patterns to exclude
98
- blockNetworkBodies: [], // Block request/response bodies
99
- redactHeaders: [], // Headers to redact
100
- logLevels: ['log', 'info', 'warn', 'error', 'debug'],
101
- },
102
-
103
- // Session limits
104
- limits: {
105
- maxLogs: 10000, // Max logs per session
106
- maxSize: 10 * 1024 * 1024, // Max session size (10MB)
107
- maxDuration: 300, // Max duration in seconds (5 min)
108
- idleTimeout: 30, // Idle timeout in seconds
109
- rateLimit: 100, // Max logs per second
110
- deduplicate: true, // Deduplicate consecutive logs
111
- },
112
-
113
- // Auto-end behavior
114
- autoEnd: {
115
- continueOnRefresh: true, // Continue session on page refresh
116
- onIdle: true, // End on idle timeout
117
- onLimitReached: true, // End when limits reached
118
- },
119
-
120
- // Sampling mode (only record on errors)
121
- sampling: {
122
- enabled: false,
123
- bufferBefore: 15, // Seconds before trigger
124
- recordAfter: 15, // Seconds after trigger
125
- triggers: {
126
- onError: true,
127
- onConsoleError: true,
128
- onNetworkStatus: [500, 502, 503, 504],
129
- },
130
- },
131
-
132
- // Lifecycle hooks
133
- hooks: {
134
- onAction: (log, session) => {},
135
- beforeSend: (logs) => logs,
136
- onSessionStart: (session) => {},
137
- onSessionEnd: (session, logs) => {},
138
- onLimitReached: (reason) => {},
139
- onSamplingTrigger: (trigger, log) => {},
140
- onError: (error) => {},
141
- },
142
-
143
- // Additional options
144
- headers: {}, // Custom API headers
145
- debug: false, // Enable debug logging
146
- });
147
- ```
148
-
149
- ## API Reference
150
-
151
- ### Initialization
152
-
153
- #### `LogSpace.init(config)`
154
-
155
- Initialize the SDK with configuration options.
156
-
157
- ### Session Control
158
-
159
- #### `LogSpace.startSession(metadata?)`
160
-
161
- Start a new recording session with optional metadata.
162
-
163
- ```javascript
164
- LogSpace.startSession({ page: 'checkout', variant: 'A' });
165
- ```
166
-
167
- #### `LogSpace.stopSession()`
168
-
169
- Stop recording and send the session to the server.
170
-
171
- ```javascript
172
- await LogSpace.stopSession();
173
- ```
174
-
175
- #### `LogSpace.pauseRecording()`
176
-
177
- Temporarily pause recording.
178
-
179
- #### `LogSpace.resumeRecording()`
180
-
181
- Resume a paused recording.
182
-
183
- ### User Identification
184
-
185
- #### `LogSpace.identify(userId, traits?)`
186
-
187
- Associate the session with a user.
188
-
189
- ```javascript
190
- LogSpace.identify('user-123', {
191
- email: 'user@example.com',
192
- name: 'John Doe',
193
- plan: 'enterprise',
194
- });
195
- ```
196
-
197
- ### Custom Events
198
-
199
- #### `LogSpace.track(event, properties?)`
200
-
201
- Track a custom event.
202
-
203
- ```javascript
204
- LogSpace.track('purchase_completed', {
205
- orderId: 'ORD-123',
206
- amount: 99.99,
207
- });
208
- ```
209
-
210
- #### `LogSpace.breadcrumb(message, category?)`
211
-
212
- Add a breadcrumb for debugging context.
213
-
214
- ```javascript
215
- LogSpace.breadcrumb('User clicked add to cart', 'action');
216
- ```
217
-
218
- ### Sampling Mode
219
-
220
- #### `LogSpace.trigger(reason?)`
221
-
222
- Manually trigger session capture in sampling mode.
223
-
224
- ```javascript
225
- LogSpace.trigger('user_reported_issue');
226
- ```
227
-
228
- ### Session Data
229
-
230
- #### `LogSpace.getSession()`
231
-
232
- Get the current session object.
233
-
234
- #### `LogSpace.getSessionLogs()`
235
-
236
- Get all logs for the current session.
237
-
238
- #### `LogSpace.getSessionData()`
239
-
240
- Get full session payload for local export.
241
-
242
- #### `LogSpace.getRRWebEvents()`
243
-
244
- Get rrweb events for the current session.
245
-
246
- ### Cleanup
247
-
248
- #### `LogSpace.destroy()`
249
-
250
- Destroy the SDK and clean up resources.
251
-
252
- ## Usage Formats
253
-
254
- The SDK supports multiple module formats:
255
-
256
- - **ESM**: `import LogSpace from '@logspace/sdk'`
257
- - **CommonJS**: `const LogSpace = require('@logspace/sdk')`
258
- - **IIFE**: `<script src="logspace.iife.js"></script>` (exposes `window.LogSpace`)
259
-
260
- ## Browser Support
261
-
262
- - Chrome 60+
263
- - Firefox 55+
264
- - Safari 12+
265
- - Edge 79+
266
-
267
- ## License
268
-
269
- MIT