@logspace/sdk 1.0.3 → 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.3",
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",
@@ -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,6 +234,7 @@ 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;
238
240
  export declare const API_TO_SETTINGS_KEY_MAP: Record<string, keyof RecordingSettings>;
@@ -344,10 +346,13 @@ export declare enum MessageType {
344
346
  */
345
347
  export declare enum InternalMessageType {
346
348
  PING = "ping",
349
+ GET_TAB_ID = "GET_TAB_ID",
350
+ CANCEL_AREA_SELECTION = "CANCEL_AREA_SELECTION",
347
351
  SHOW_COUNTDOWN = "SHOW_COUNTDOWN",
348
352
  COUNTDOWN_COMPLETE = "COUNTDOWN_COMPLETE",
349
353
  SELECT_AREA = "SELECT_AREA",
350
354
  AREA_SELECTED = "AREA_SELECTED",
355
+ AREA_SELECTION_CANCELLED = "AREA_SELECTION_CANCELLED",
351
356
  NETWORK_HEADERS_REQUEST = "NETWORK_HEADERS_REQUEST",
352
357
  NETWORK_HEADERS_RESPONSE = "NETWORK_HEADERS_RESPONSE",
353
358
  SHOW_WEBCAM_OVERLAY = "show-webcam-overlay",
@@ -369,6 +374,9 @@ export declare enum InternalMessageType {
369
374
  OFFSCREEN_LOG = "offscreen-log",
370
375
  DISPLAY_MEDIA_SELECTED = "display-media-selected",
371
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
372
380
  CLOSE_POPUP = "CLOSE_POPUP",
373
381
  RECORDING_STARTED = "RECORDING_STARTED",
374
382
  RECORDING_ERROR = "RECORDING_ERROR",
@@ -420,6 +428,7 @@ export interface StatusResponse {
420
428
  session: RecordingSession | null;
421
429
  error?: string;
422
430
  auth?: AuthState;
431
+ recordedTabIds?: number[];
423
432
  }
424
433
  export interface CspDetectedMessage extends Message {
425
434
  type: MessageType.CSP_DETECTED;
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