@bugspotter/sdk 2.0.0 → 2.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/CONTRIBUTING.md CHANGED
@@ -190,9 +190,9 @@ pnpm build # Production build
190
190
 
191
191
  ## Getting Help
192
192
 
193
- - **Questions**: Open a [Discussion](https://github.com/apexbridge-tech/bugspotter-sdk/discussions)
194
- - **Bugs**: Open an [Issue](https://github.com/apexbridge-tech/bugspotter-sdk/issues) with the bug template
195
- - **Features**: Open an [Issue](https://github.com/apexbridge-tech/bugspotter-sdk/issues) with the feature template
193
+ - **Questions**: Open a [Discussion](https://github.com/apex-bridge/bugspotter-sdk/discussions)
194
+ - **Bugs**: Open an [Issue](https://github.com/apex-bridge/bugspotter-sdk/issues) with the bug template
195
+ - **Features**: Open an [Issue](https://github.com/apex-bridge/bugspotter-sdk/issues) with the feature template
196
196
  - **Security**: Email security@apexbridge.tech
197
197
 
198
198
  ## License
package/README.md CHANGED
@@ -23,7 +23,7 @@ pnpm add @bugspotter/sdk
23
23
 
24
24
  ```html
25
25
  <!-- BugSpotter CDN (versioned - recommended for production) -->
26
- <script src="https://cdn.bugspotter.io/sdk/bugspotter-1.0.0.min.js"></script>
26
+ <script src="https://cdn.bugspotter.io/sdk/bugspotter-2.0.0.min.js"></script>
27
27
 
28
28
  <!-- Latest version (for development only) -->
29
29
  <script src="https://cdn.bugspotter.io/sdk/bugspotter-latest.min.js"></script>
@@ -38,8 +38,8 @@ pnpm add @bugspotter/sdk
38
38
 
39
39
  ```bash
40
40
  # Clone and build from source
41
- git clone https://github.com/apexbridge-tech/bugspotter.git
42
- cd bugspotter/packages/sdk
41
+ git clone https://github.com/apex-bridge/bugspotter-sdk.git
42
+ cd bugspotter-sdk
43
43
  pnpm install
44
44
  pnpm build
45
45
  ```
@@ -57,12 +57,8 @@ import BugSpotter from '@bugspotter/sdk';
57
57
 
58
58
  // Initialize with auto-widget (note: init is async)
59
59
  const bugSpotter = await BugSpotter.init({
60
- endpoint: 'https://api.bugspotter.com/api/v1/reports',
61
- auth: {
62
- type: 'api-key',
63
- apiKey: 'bgs_your_api_key',
64
- projectId: 'your-project-uuid',
65
- },
60
+ endpoint: 'https://api.bugspotter.com',
61
+ apiKey: 'bgs_your_api_key',
66
62
  showWidget: true,
67
63
  });
68
64
  ```
@@ -73,12 +69,8 @@ const bugSpotter = await BugSpotter.init({
73
69
  const BugSpotter = require('@bugspotter/sdk');
74
70
 
75
71
  const bugSpotter = await BugSpotter.init({
76
- endpoint: 'https://api.bugspotter.com/api/v1/reports',
77
- auth: {
78
- type: 'api-key',
79
- apiKey: 'bgs_your_api_key',
80
- projectId: 'your-project-uuid',
81
- },
72
+ endpoint: 'https://api.bugspotter.com',
73
+ apiKey: 'bgs_your_api_key',
82
74
  showWidget: true,
83
75
  });
84
76
  ```
@@ -91,12 +83,8 @@ const bugSpotter = await BugSpotter.init({
91
83
  // Initialize with auto-widget
92
84
  (async () => {
93
85
  const bugSpotter = await BugSpotter.init({
94
- endpoint: 'https://api.bugspotter.com/api/v1/reports',
95
- auth: {
96
- type: 'api-key',
97
- apiKey: 'bgs_your_api_key',
98
- projectId: 'your-project-uuid',
99
- },
86
+ endpoint: 'https://api.bugspotter.com',
87
+ apiKey: 'bgs_your_api_key',
100
88
  showWidget: true,
101
89
  });
102
90
  })();
@@ -112,12 +100,8 @@ import BugSpotter from '@bugspotter/sdk';
112
100
 
113
101
  // 1. Initialize SDK with required auth
114
102
  const bugSpotter = await BugSpotter.init({
115
- endpoint: 'https://api.bugspotter.com/api/v1/reports',
116
- auth: {
117
- type: 'api-key',
118
- apiKey: 'bgs_your_api_key',
119
- projectId: 'your-project-uuid', // Required for file uploads
120
- },
103
+ endpoint: 'https://api.bugspotter.com',
104
+ apiKey: 'bgs_your_api_key',
121
105
  showWidget: true,
122
106
  });
123
107
 
@@ -142,12 +126,8 @@ const bugSpotter = await BugSpotter.init({
142
126
  ```javascript
143
127
  // Initialize without widget
144
128
  const bugSpotter = await BugSpotter.init({
145
- endpoint: 'https://api.bugspotter.com/api/v1/reports',
146
- auth: {
147
- type: 'api-key',
148
- apiKey: 'bgs_your_api_key',
149
- projectId: 'your-project-uuid',
150
- },
129
+ endpoint: 'https://api.bugspotter.com',
130
+ apiKey: 'bgs_your_api_key',
151
131
  showWidget: false,
152
132
  });
153
133
 
@@ -177,12 +157,8 @@ await bugSpotter.submit({
177
157
  ```javascript
178
158
  // Widget appears automatically with showWidget: true
179
159
  const bugSpotter = await BugSpotter.init({
180
- endpoint: 'https://api.bugspotter.com/api/v1/reports',
181
- auth: {
182
- type: 'api-key',
183
- apiKey: 'bgs_your_api_key',
184
- projectId: 'your-project-uuid',
185
- },
160
+ endpoint: 'https://api.bugspotter.com',
161
+ apiKey: 'bgs_your_api_key',
186
162
  showWidget: true,
187
163
  widgetOptions: {
188
164
  position: 'bottom-right',
@@ -254,22 +230,84 @@ button.setBackgroundColor('#00ff00');
254
230
 
255
231
  ## 🔒 PII Sanitization
256
232
 
257
- Automatic detection and masking of sensitive data before submission.
233
+ Automatic detection and masking of sensitive text data **in the browser before upload**. When enabled (default), text fields (console logs, network URLs, metadata) are sanitized before submission. For visual exclusion: use `replay.blockSelectors` to hide DOM elements from session replay, and `data-bugspotter-exclude` attribute to exclude elements from screenshots.
234
+
235
+ ### Built-in Patterns (9 types)
236
+
237
+ | Pattern | Detects | Example |
238
+ | ------------ | ------------------------- | ----------------------------------------------- |
239
+ | `email` | Email addresses | `user@example.com` → `[REDACTED-EMAIL]` |
240
+ | `phone` | Phone numbers | `+7 701 123-4567` → `[REDACTED-PHONE]` |
241
+ | `creditcard` | Credit card numbers | `4111-1111-1111-1111` → `[REDACTED-CREDITCARD]` |
242
+ | `ssn` | US Social Security | `123-45-6789` → `[REDACTED-SSN]` |
243
+ | `iin` | Kazakhstan IIN/BIN | `860101350478` → `[REDACTED-IIN]` |
244
+ | `ip` | IPv4 and IPv6 | `192.168.1.1` → `[REDACTED-IP]` |
245
+ | `apikey` | Stripe, AWS, Google keys | `sk_live_...` → `[REDACTED-APIKEY]` |
246
+ | `token` | Bearer, JWT, OAuth tokens | `eyJhbG...` → `[REDACTED-TOKEN]` |
247
+ | `password` | Password field values | `••••••••` → `[REDACTED-PASSWORD]` |
248
+
249
+ ### Presets
250
+
251
+ Use a preset name instead of listing patterns individually:
252
+
253
+ | Preset | Patterns included |
254
+ | ------------------ | ----------------------- |
255
+ | `'all'` | All 9 patterns |
256
+ | `'minimal'` | email, creditcard, ssn |
257
+ | `'financial'` | creditcard, ssn |
258
+ | `'contact'` | email, phone |
259
+ | `'identification'` | ssn, iin |
260
+ | `'kazakhstan'` | email, phone, iin |
261
+ | `'gdpr'` | email, phone, ip |
262
+ | `'pci'` | creditcard |
263
+ | `'credentials'` | apikey, token, password |
264
+
265
+ ```javascript
266
+ // Use a preset
267
+ await BugSpotter.init({
268
+ sanitize: { patterns: 'kazakhstan' }, // email + phone + IIN
269
+ });
270
+
271
+ // Or pick individual patterns
272
+ await BugSpotter.init({
273
+ sanitize: { patterns: ['email', 'phone', 'creditcard'] },
274
+ });
275
+ ```
276
+
277
+ ### Custom Patterns
258
278
 
259
- **Built-in patterns:** Email, phone, credit card, SSN, Kazakhstan IIN, IP address
279
+ Add your own regex patterns for industry-specific data:
260
280
 
261
281
  ```javascript
262
282
  await BugSpotter.init({
263
283
  sanitize: {
264
- enabled: true, // Default
265
- patterns: ['email', 'phone', 'creditcard'],
266
- customPatterns: [{ name: 'api-key', regex: /API[-_]KEY:\s*[\w-]{20,}/gi }],
267
- excludeSelectors: ['.public-email'],
284
+ enabled: true,
285
+ patterns: 'all',
286
+ customPatterns: [
287
+ {
288
+ name: 'broker-account',
289
+ regex: /FRH\d{9}/gi,
290
+ description: 'Freedom Finance broker account number',
291
+ },
292
+ {
293
+ name: 'iban-kz',
294
+ regex: /KZ\d{2}[A-Z]{4}\d{13}/gi,
295
+ description: 'Kazakhstan IBAN',
296
+ },
297
+ {
298
+ name: 'internal-id',
299
+ regex: /ORD-\d{6,}/gi,
300
+ description: 'Internal order ID',
301
+ },
302
+ ],
303
+ excludeSelectors: ['.public-info'], // Don't redact inside these elements
268
304
  },
269
305
  });
270
306
  ```
271
307
 
272
- **Performance:** <10ms overhead, supports Cyrillic text
308
+ Custom patterns produce `[REDACTED-BROKER-ACCOUNT]`, `[REDACTED-IBAN-KZ]`, etc.
309
+
310
+ **Performance:** < 50ms overhead, recursive sanitization of nested objects, supports Cyrillic text
273
311
 
274
312
  ## 📋 API Reference
275
313
 
@@ -283,43 +321,59 @@ Initialize the SDK. **This method is async** to support fetching backend-control
283
321
 
284
322
  ```typescript
285
323
  interface BugSpotterConfig {
286
- endpoint: string; // Required: Backend API URL
287
- auth: {
288
- // Required: Authentication configuration
289
- type: 'api-key';
290
- apiKey: string; // API key (bgs_...)
291
- projectId: string; // Project UUID (required for file uploads)
292
- };
324
+ apiKey: string; // Required: API key (bgs_...)
325
+ endpoint?: string; // Base URL of BugSpotter API
326
+ sampleRate?: number; // Session sampling (0-1, default: 1 = all sessions)
293
327
  showWidget?: boolean; // Auto-show widget (default: true)
294
328
  widgetOptions?: FloatingButtonOptions;
295
329
  replay?: {
296
- // Session replay configuration
297
330
  enabled?: boolean; // Enable replay (default: true)
298
331
  duration?: number; // Buffer duration in seconds (default: 15)
299
332
  sampling?: {
300
333
  mousemove?: number; // Mousemove throttle in ms (default: 50)
301
334
  scroll?: number; // Scroll throttle in ms (default: 100)
302
335
  };
336
+ blockSelectors?: string[]; // CSS selectors to exclude from replay
337
+ blockClass?: string; // CSS class to exclude from replay
303
338
  // Quality settings (optional, backend controlled by default)
304
- inlineStylesheet?: boolean; // Inline CSS stylesheets (default: backend controlled)
305
- inlineImages?: boolean; // Inline images (default: backend controlled)
306
- collectFonts?: boolean; // Collect fonts (default: backend controlled)
307
- recordCanvas?: boolean; // Record canvas elements (default: backend controlled)
308
- recordCrossOriginIframes?: boolean; // Record cross-origin iframes (default: backend controlled)
339
+ inlineStylesheet?: boolean;
340
+ inlineImages?: boolean;
341
+ collectFonts?: boolean;
342
+ recordCanvas?: boolean;
343
+ recordCrossOriginIframes?: boolean;
309
344
  };
310
345
  sanitize?: {
311
- // PII sanitization configuration
312
346
  enabled?: boolean; // Enable PII sanitization (default: true)
313
- patterns?: Array<
314
- // PII patterns to detect
315
- 'email' | 'phone' | 'creditcard' | 'ssn' | 'iin' | 'ip' | 'custom'
316
- >;
347
+ patterns?:
348
+ | 'all'
349
+ | 'minimal'
350
+ | 'financial'
351
+ | 'contact'
352
+ | 'identification'
353
+ | 'credentials'
354
+ | 'kazakhstan'
355
+ | 'gdpr'
356
+ | 'pci'
357
+ | Array<
358
+ | 'email'
359
+ | 'phone'
360
+ | 'creditcard'
361
+ | 'ssn'
362
+ | 'iin'
363
+ | 'ip'
364
+ | 'apikey'
365
+ | 'token'
366
+ | 'password'
367
+ | 'custom'
368
+ >;
317
369
  customPatterns?: Array<{
318
- // Custom regex patterns
319
- name: string; // Pattern name for [REDACTED-NAME]
370
+ name: string; // Pattern name → [REDACTED-NAME]
320
371
  regex: RegExp; // Detection regex
372
+ description?: string; // Human-readable description
373
+ examples?: string[]; // Example values for testing
374
+ priority?: number; // Pattern ordering hint (optional)
321
375
  }>;
322
- excludeSelectors?: string[]; // CSS selectors to exclude from sanitization
376
+ excludeSelectors?: string[]; // CSS selectors to exclude from DOM text sanitization (replay)
323
377
  };
324
378
  }
325
379
  ```
@@ -492,7 +546,6 @@ new DirectUploader(config: DirectUploadConfig)
492
546
  interface DirectUploadConfig {
493
547
  apiEndpoint: string; // Backend API URL
494
548
  apiKey: string; // bgs_... API key
495
- projectId: string; // Project UUID
496
549
  bugId: string; // Bug report UUID
497
550
  }
498
551
  ```
@@ -507,7 +560,9 @@ Upload screenshot directly to storage.
507
560
  const screenshotBlob = await fetch(dataUrl).then((r) => r.blob());
508
561
 
509
562
  const result = await uploader.uploadScreenshot(screenshotBlob, (progress) => {
510
- console.log(`Screenshot: ${progress.loaded}/${progress.total} (${progress.percentage}%)`);
563
+ console.log(
564
+ `Screenshot: ${progress.loaded}/${progress.total} (${progress.percentage}%)`
565
+ );
511
566
  });
512
567
 
513
568
  // result: { success: true, storageKey: "screenshots/..." }
@@ -697,7 +752,7 @@ Output: `dist/bugspotter.min.js` (~99 KB)
697
752
  - **Load**: < 100ms
698
753
  - **Memory**: < 15 MB (30s replay buffer)
699
754
  - **Screenshot**: ~500ms
700
- - **PII sanitization**: <10ms
755
+ - **PII sanitization**: <50ms
701
756
 
702
757
  ## 🔒 Security
703
758