@bugspotter/sdk 0.2.5-alpha.5 → 0.3.1

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/dist/index.js CHANGED
@@ -62,7 +62,9 @@ async function fetchReplaySettings(endpoint, apiKey) {
62
62
  if (apiKey) {
63
63
  headers['x-api-key'] = apiKey;
64
64
  }
65
- const response = await fetch(`${apiBaseUrl}/api/v1/settings/replay`, { headers });
65
+ const response = await fetch(`${apiBaseUrl}/api/v1/settings/replay`, {
66
+ headers,
67
+ });
66
68
  if (!response.ok) {
67
69
  logger.warn(`Failed to fetch replay settings: ${response.status}. Using defaults.`);
68
70
  return defaults;
@@ -20,7 +20,11 @@ exports.DEFAULT_PATTERNS = {
20
20
  name: 'email',
21
21
  regex: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g,
22
22
  description: 'Email addresses',
23
- examples: ['user@example.com', 'john.doe+tag@company.co.uk', 'test_user@sub.domain.com'],
23
+ examples: [
24
+ 'user@example.com',
25
+ 'john.doe+tag@company.co.uk',
26
+ 'test_user@sub.domain.com',
27
+ ],
24
28
  priority: 1, // Highest priority - most specific
25
29
  },
26
30
  creditcard: {
@@ -53,7 +57,11 @@ exports.DEFAULT_PATTERNS = {
53
57
  name: 'ip',
54
58
  regex: /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b|(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b/g,
55
59
  description: 'IPv4 and IPv6 addresses',
56
- examples: ['192.168.1.100', '127.0.0.1', '2001:0db8:85a3:0000:0000:8a2e:0370:7334'],
60
+ examples: [
61
+ '192.168.1.100',
62
+ '127.0.0.1',
63
+ '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
64
+ ],
57
65
  priority: 5,
58
66
  },
59
67
  phone: {
@@ -96,7 +104,11 @@ exports.DEFAULT_PATTERNS = {
96
104
  name: 'password',
97
105
  regex: /(?:password|passwd|pwd)[\s:=]+[^\s]{6,}|(?:password|passwd|pwd)["']?\s*[:=]\s*["']?[^\s"']{6,}/gi,
98
106
  description: 'Password fields in text (password=..., pwd:...)',
99
- examples: ['password: MySecret123!', 'passwd=SecurePass456', 'pwd: "MyP@ssw0rd"'],
107
+ examples: [
108
+ 'password: MySecret123!',
109
+ 'passwd=SecurePass456',
110
+ 'pwd: "MyP@ssw0rd"',
111
+ ],
100
112
  priority: 9,
101
113
  },
102
114
  };
package/dist/version.d.ts CHANGED
@@ -5,4 +5,4 @@
5
5
  * This file is automatically generated during the build process.
6
6
  * To update the version, modify package.json
7
7
  */
8
- export declare const VERSION = "0.2.5-alpha.5";
8
+ export declare const VERSION = "0.3.1";
package/dist/version.js CHANGED
@@ -8,4 +8,4 @@
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.VERSION = void 0;
11
- exports.VERSION = '0.2.5-alpha.5';
11
+ exports.VERSION = '0.3.1';
@@ -31,7 +31,8 @@ class FormValidator {
31
31
  }
32
32
  // Validate PII confirmation if PII detected
33
33
  if (data.piiDetected && !data.piiConfirmed) {
34
- errors.piiConfirmation = 'Please confirm you have reviewed sensitive information';
34
+ errors.piiConfirmation =
35
+ 'Please confirm you have reviewed sensitive information';
35
36
  }
36
37
  return {
37
38
  isValid: Object.keys(errors).length === 0,
@@ -13,11 +13,28 @@ export interface StyleConfig {
13
13
  }
14
14
  export declare class StyleManager {
15
15
  private config;
16
+ private readonly SPACING;
17
+ private readonly BREAKPOINTS;
18
+ private readonly MODAL_SIZES;
19
+ private readonly FONT_SIZES;
20
+ private readonly BORDER_STYLES;
21
+ private readonly SHADOW_STYLES;
16
22
  constructor(config?: StyleConfig);
17
23
  /**
18
24
  * Generate complete CSS stylesheet for the modal
19
25
  */
20
26
  generateStyles(): string;
27
+ private generateOverlayStyles;
28
+ private generateModalStyles;
29
+ private generateHeaderStyles;
30
+ private generateBodyStyles;
31
+ private generateFormStyles;
32
+ private generateButtonStyles;
33
+ private generatePIIStyles;
34
+ private generateLoadingStyles;
35
+ private generateAccessibilityStyles;
36
+ private generateTabletResponsiveStyles;
37
+ private generateMobileResponsiveStyles;
21
38
  /**
22
39
  * Inject styles into document head
23
40
  */
@@ -9,11 +9,50 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.StyleManager = void 0;
10
10
  class StyleManager {
11
11
  constructor(config = {}) {
12
+ // ============================================================================
13
+ // SPACING & SIZING CONSTANTS
14
+ // ============================================================================
15
+ this.SPACING = {
16
+ xs: 8,
17
+ sm: 12,
18
+ md: 16,
19
+ lg: 20,
20
+ };
21
+ this.BREAKPOINTS = {
22
+ tablet: 768,
23
+ mobile: 480,
24
+ };
25
+ this.MODAL_SIZES = {
26
+ desktop: '600px',
27
+ tablet: '500px',
28
+ mobilePercent: '98%',
29
+ headerHeight: '30px',
30
+ };
31
+ // ============================================================================
32
+ // FONT & LAYOUT CONSTANTS
33
+ // ============================================================================
34
+ this.FONT_SIZES = {
35
+ h2: '20px',
36
+ h2Mobile: '18px',
37
+ label: '14px',
38
+ labelMobile: '13px',
39
+ body: '14px',
40
+ small: '12px',
41
+ sr: '13px',
42
+ };
43
+ this.BORDER_STYLES = {
44
+ primary: '1px solid #e0e0e0',
45
+ light: '1px solid #ddd',
46
+ };
47
+ this.SHADOW_STYLES = {
48
+ modal: '0 4px 6px rgba(0, 0, 0, 0.1)',
49
+ };
12
50
  this.config = {
13
51
  primaryColor: config.primaryColor || '#007bff',
14
52
  dangerColor: config.dangerColor || '#dc3545',
15
53
  borderRadius: config.borderRadius || '4px',
16
- fontFamily: config.fontFamily || '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
54
+ fontFamily: config.fontFamily ||
55
+ '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
17
56
  zIndex: config.zIndex || 999999,
18
57
  };
19
58
  }
@@ -22,6 +61,24 @@ class StyleManager {
22
61
  */
23
62
  generateStyles() {
24
63
  return `
64
+ ${this.generateOverlayStyles()}
65
+ ${this.generateModalStyles()}
66
+ ${this.generateHeaderStyles()}
67
+ ${this.generateBodyStyles()}
68
+ ${this.generateFormStyles()}
69
+ ${this.generateButtonStyles()}
70
+ ${this.generatePIIStyles()}
71
+ ${this.generateLoadingStyles()}
72
+ ${this.generateAccessibilityStyles()}
73
+ ${this.generateTabletResponsiveStyles()}
74
+ ${this.generateMobileResponsiveStyles()}
75
+ `;
76
+ }
77
+ // ============================================================================
78
+ // COMPONENT STYLES - OVERLAY & MODAL
79
+ // ============================================================================
80
+ generateOverlayStyles() {
81
+ return `
25
82
  .overlay {
26
83
  position: fixed;
27
84
  top: 0;
@@ -35,20 +92,35 @@ class StyleManager {
35
92
  z-index: ${this.config.zIndex};
36
93
  font-family: ${this.config.fontFamily};
37
94
  }
38
-
95
+ `;
96
+ }
97
+ generateModalStyles() {
98
+ return `
39
99
  .modal {
40
100
  background: white;
41
101
  border-radius: 8px;
42
102
  width: 90%;
43
- max-width: 600px;
103
+ max-width: ${this.MODAL_SIZES.desktop};
44
104
  max-height: 90vh;
45
105
  overflow-y: auto;
46
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
106
+ box-shadow: ${this.SHADOW_STYLES.modal};
107
+ scrollbar-width: none;
108
+ -ms-overflow-style: none;
47
109
  }
48
110
 
111
+ .modal::-webkit-scrollbar {
112
+ display: none;
113
+ }
114
+ `;
115
+ }
116
+ // ============================================================================
117
+ // COMPONENT STYLES - HEADER
118
+ // ============================================================================
119
+ generateHeaderStyles() {
120
+ return `
49
121
  .header {
50
- padding: 20px;
51
- border-bottom: 1px solid #e0e0e0;
122
+ padding: ${this.SPACING.lg}px;
123
+ border-bottom: ${this.BORDER_STYLES.primary};
52
124
  display: flex;
53
125
  justify-content: space-between;
54
126
  align-items: center;
@@ -56,7 +128,7 @@ class StyleManager {
56
128
 
57
129
  .header h2 {
58
130
  margin: 0;
59
- font-size: 20px;
131
+ font-size: ${this.FONT_SIZES.h2};
60
132
  font-weight: 600;
61
133
  }
62
134
 
@@ -67,8 +139,8 @@ class StyleManager {
67
139
  cursor: pointer;
68
140
  color: #666;
69
141
  padding: 0;
70
- width: 30px;
71
- height: 30px;
142
+ width: ${this.MODAL_SIZES.headerHeight};
143
+ height: ${this.MODAL_SIZES.headerHeight};
72
144
  display: flex;
73
145
  align-items: center;
74
146
  justify-content: center;
@@ -78,29 +150,38 @@ class StyleManager {
78
150
  .close:hover {
79
151
  background: #f0f0f0;
80
152
  }
81
-
153
+ `;
154
+ }
155
+ // ============================================================================
156
+ // COMPONENT STYLES - BODY & FORM
157
+ // ============================================================================
158
+ generateBodyStyles() {
159
+ return `
82
160
  .body {
83
- padding: 20px;
161
+ padding: ${this.SPACING.lg}px;
84
162
  }
85
-
163
+ `;
164
+ }
165
+ generateFormStyles() {
166
+ return `
86
167
  .form-group {
87
- margin-bottom: 20px;
168
+ margin-bottom: ${this.SPACING.lg}px;
88
169
  }
89
170
 
90
171
  .label {
91
172
  display: block;
92
- margin-bottom: 8px;
173
+ margin-bottom: ${this.SPACING.xs}px;
93
174
  font-weight: 500;
94
- font-size: 14px;
175
+ font-size: ${this.FONT_SIZES.label};
95
176
  }
96
177
 
97
178
  .input,
98
179
  .textarea {
99
180
  width: 100%;
100
- padding: 10px;
101
- border: 1px solid #ddd;
181
+ padding: ${this.SPACING.xs}px;
182
+ border: ${this.BORDER_STYLES.light};
102
183
  border-radius: ${this.config.borderRadius};
103
- font-size: 14px;
184
+ font-size: ${this.FONT_SIZES.body};
104
185
  font-family: ${this.config.fontFamily};
105
186
  box-sizing: border-box;
106
187
  }
@@ -116,40 +197,92 @@ class StyleManager {
116
197
  resize: vertical;
117
198
  }
118
199
 
119
- .screenshot-container {
120
- margin-top: 10px;
121
- position: relative;
200
+ .checkbox-group {
201
+ display: flex;
202
+ align-items: center;
203
+ gap: ${this.SPACING.xs}px;
204
+ margin-top: ${this.SPACING.md}px;
122
205
  }
123
206
 
124
- .screenshot {
125
- max-width: 100%;
126
- border: 1px solid #ddd;
127
- border-radius: ${this.config.borderRadius};
207
+ .checkbox {
208
+ width: 18px;
209
+ height: 18px;
210
+ cursor: pointer;
128
211
  }
129
212
 
130
- .redaction-canvas {
131
- position: absolute;
132
- top: 0;
133
- left: 0;
134
- cursor: crosshair;
135
- border: 2px solid ${this.config.primaryColor};
213
+ .checkbox-label {
214
+ margin: 0;
215
+ font-size: ${this.FONT_SIZES.body};
216
+ cursor: pointer;
217
+ user-select: none;
218
+ }
219
+
220
+ .error {
221
+ color: ${this.config.dangerColor};
222
+ font-size: ${this.FONT_SIZES.small};
223
+ margin-top: 4px;
224
+ }
225
+ `;
226
+ }
227
+ // ============================================================================
228
+ // COMPONENT STYLES - BUTTONS & CONTROLS
229
+ // ============================================================================
230
+ generateButtonStyles() {
231
+ return `
232
+ .footer {
233
+ padding: ${this.SPACING.lg}px;
234
+ border-top: ${this.BORDER_STYLES.primary};
235
+ display: flex;
236
+ justify-content: flex-end;
237
+ gap: ${this.SPACING.xs}px;
238
+ }
239
+
240
+ .btn {
241
+ padding: ${this.SPACING.xs}px ${this.SPACING.md}px;
242
+ border: none;
136
243
  border-radius: ${this.config.borderRadius};
244
+ cursor: pointer;
245
+ font-size: ${this.FONT_SIZES.body};
246
+ font-weight: 500;
247
+ }
248
+
249
+ .btn-primary {
250
+ background: ${this.config.primaryColor};
251
+ color: white;
252
+ }
253
+
254
+ .btn-primary:hover {
255
+ opacity: 0.9;
256
+ }
257
+
258
+ .btn-primary:disabled {
259
+ opacity: 0.5;
260
+ cursor: not-allowed;
261
+ }
262
+
263
+ .btn-secondary {
264
+ background: #6c757d;
265
+ color: white;
266
+ }
267
+
268
+ .btn-secondary:hover {
269
+ opacity: 0.9;
137
270
  }
138
271
 
139
272
  .redaction-controls {
140
- margin-top: 10px;
273
+ margin-top: ${this.SPACING.xs}px;
141
274
  display: flex;
142
- gap: 10px;
275
+ gap: ${this.SPACING.xs}px;
143
276
  }
144
277
 
145
278
  .btn-redact,
146
279
  .btn-clear {
147
- padding: 8px 16px;
148
- border: 1px solid #ddd;
280
+ padding: ${this.SPACING.xs}px ${this.SPACING.md}px;
281
+ border: ${this.BORDER_STYLES.light};
149
282
  border-radius: ${this.config.borderRadius};
150
283
  background: white;
151
284
  cursor: pointer;
152
- font-size: 14px;
285
+ font-size: ${this.FONT_SIZES.body};
153
286
  }
154
287
 
155
288
  .btn-redact:hover,
@@ -163,17 +296,43 @@ class StyleManager {
163
296
  border-color: ${this.config.primaryColor};
164
297
  }
165
298
 
299
+ .screenshot-container {
300
+ margin-top: ${this.SPACING.xs}px;
301
+ position: relative;
302
+ }
303
+
304
+ .screenshot {
305
+ max-width: 100%;
306
+ border: ${this.BORDER_STYLES.light};
307
+ border-radius: ${this.config.borderRadius};
308
+ }
309
+
310
+ .redaction-canvas {
311
+ position: absolute;
312
+ top: 0;
313
+ left: 0;
314
+ cursor: crosshair;
315
+ border: 2px solid ${this.config.primaryColor};
316
+ border-radius: ${this.config.borderRadius};
317
+ }
318
+ `;
319
+ }
320
+ // ============================================================================
321
+ // COMPONENT STYLES - PII DETECTION
322
+ // ============================================================================
323
+ generatePIIStyles() {
324
+ return `
166
325
  .pii-section {
167
- margin-top: 20px;
168
- padding: 15px;
326
+ margin-top: ${this.SPACING.lg}px;
327
+ padding: ${this.SPACING.md}px;
169
328
  background: #fff3cd;
170
329
  border: 1px solid #ffc107;
171
330
  border-radius: ${this.config.borderRadius};
172
331
  }
173
332
 
174
333
  .pii-title {
175
- margin: 0 0 10px 0;
176
- font-size: 14px;
334
+ margin: 0 0 ${this.SPACING.xs}px 0;
335
+ font-size: ${this.FONT_SIZES.body};
177
336
  font-weight: 600;
178
337
  color: #856404;
179
338
  }
@@ -181,7 +340,7 @@ class StyleManager {
181
340
  .pii-list {
182
341
  margin: 0;
183
342
  padding-left: 20px;
184
- font-size: 13px;
343
+ font-size: ${this.FONT_SIZES.sr};
185
344
  color: #856404;
186
345
  }
187
346
 
@@ -192,61 +351,16 @@ class StyleManager {
192
351
  background: #ffc107;
193
352
  color: #856404;
194
353
  border-radius: 12px;
195
- font-size: 12px;
354
+ font-size: ${this.FONT_SIZES.small};
196
355
  font-weight: 500;
197
356
  }
198
-
199
- .checkbox-group {
200
- display: flex;
201
- align-items: center;
202
- gap: 8px;
203
- margin-top: 15px;
204
- }
205
-
206
- .checkbox {
207
- width: 18px;
208
- height: 18px;
209
- cursor: pointer;
210
- }
211
-
212
- .checkbox-label {
213
- margin: 0;
214
- font-size: 14px;
215
- cursor: pointer;
216
- user-select: none;
217
- }
218
-
219
- .footer {
220
- padding: 20px;
221
- border-top: 1px solid #e0e0e0;
222
- display: flex;
223
- justify-content: flex-end;
224
- gap: 10px;
225
- }
226
-
227
- .btn {
228
- padding: 10px 20px;
229
- border: none;
230
- border-radius: ${this.config.borderRadius};
231
- cursor: pointer;
232
- font-size: 14px;
233
- font-weight: 500;
234
- }
235
-
236
- .btn-primary {
237
- background: ${this.config.primaryColor};
238
- color: white;
239
- }
240
-
241
- .btn-primary:hover {
242
- opacity: 0.9;
243
- }
244
-
245
- .btn-primary:disabled {
246
- opacity: 0.5;
247
- cursor: not-allowed;
248
- }
249
-
357
+ `;
358
+ }
359
+ // ============================================================================
360
+ // COMPONENT STYLES - LOADING STATE
361
+ // ============================================================================
362
+ generateLoadingStyles() {
363
+ return `
250
364
  .btn.loading {
251
365
  position: relative;
252
366
  padding-left: 2.5rem;
@@ -269,7 +383,13 @@ class StyleManager {
269
383
  @keyframes spinner {
270
384
  to { transform: rotate(360deg); }
271
385
  }
272
-
386
+ `;
387
+ }
388
+ // ============================================================================
389
+ // COMPONENT STYLES - ACCESSIBILITY
390
+ // ============================================================================
391
+ generateAccessibilityStyles() {
392
+ return `
273
393
  .sr-only {
274
394
  position: absolute;
275
395
  width: 1px;
@@ -281,20 +401,110 @@ class StyleManager {
281
401
  white-space: nowrap;
282
402
  border-width: 0;
283
403
  }
284
-
285
- .btn-secondary {
286
- background: #6c757d;
287
- color: white;
288
- }
289
-
290
- .btn-secondary:hover {
291
- opacity: 0.9;
404
+ `;
405
+ }
406
+ // ============================================================================
407
+ // RESPONSIVE STYLES - TABLET (≤768px)
408
+ // ============================================================================
409
+ generateTabletResponsiveStyles() {
410
+ return `
411
+ @media (max-width: ${this.BREAKPOINTS.tablet}px) {
412
+ .modal {
413
+ width: 95%;
414
+ max-width: ${this.MODAL_SIZES.tablet};
415
+ }
416
+
417
+ .header {
418
+ padding: ${this.SPACING.md}px;
419
+ }
420
+
421
+ .body {
422
+ padding: ${this.SPACING.md}px;
423
+ }
424
+
425
+ .footer {
426
+ padding: ${this.SPACING.md}px;
427
+ }
428
+
429
+ /* Prevent iOS zoom on input focus (requires 16px minimum) */
430
+ .input,
431
+ .textarea {
432
+ padding: ${this.SPACING.xs}px;
433
+ font-size: 16px;
434
+ }
435
+
436
+ .textarea {
437
+ min-height: 80px;
438
+ }
292
439
  }
293
-
294
- .error {
295
- color: ${this.config.dangerColor};
296
- font-size: 12px;
297
- margin-top: 4px;
440
+ `;
441
+ }
442
+ // ============================================================================
443
+ // RESPONSIVE STYLES - MOBILE (≤480px)
444
+ // ============================================================================
445
+ generateMobileResponsiveStyles() {
446
+ return `
447
+ @media (max-width: ${this.BREAKPOINTS.mobile}px) {
448
+ .modal {
449
+ width: ${this.MODAL_SIZES.mobilePercent};
450
+ max-width: 100%;
451
+ max-height: 95vh;
452
+ }
453
+
454
+ .header {
455
+ padding: ${this.SPACING.sm}px;
456
+ }
457
+
458
+ .header h2 {
459
+ font-size: ${this.FONT_SIZES.h2Mobile};
460
+ }
461
+
462
+ .body {
463
+ padding: ${this.SPACING.sm}px;
464
+ }
465
+
466
+ .footer {
467
+ padding: ${this.SPACING.sm}px;
468
+ flex-direction: column;
469
+ }
470
+
471
+ .btn {
472
+ width: 100%;
473
+ padding: ${this.SPACING.md}px;
474
+ }
475
+
476
+ .input,
477
+ .textarea {
478
+ padding: ${this.SPACING.xs}px;
479
+ }
480
+
481
+ .textarea {
482
+ resize: none;
483
+ }
484
+
485
+ .redaction-controls {
486
+ flex-direction: column;
487
+ }
488
+
489
+ .btn-redact,
490
+ .btn-clear {
491
+ width: 100%;
492
+ }
493
+
494
+ .pii-section {
495
+ padding: ${this.SPACING.sm}px;
496
+ margin-top: ${this.SPACING.md}px;
497
+ }
498
+
499
+ .label {
500
+ font-size: ${this.FONT_SIZES.labelMobile};
501
+ }
502
+
503
+ .close {
504
+ width: 28px;
505
+ height: 28px;
506
+ font-size: 20px;
507
+ }
298
508
  }
299
509
  `;
300
510
  }
@@ -12,7 +12,8 @@ class TemplateManager {
12
12
  this.config = {
13
13
  title: config.title || 'Report a Bug',
14
14
  titlePlaceholder: config.titlePlaceholder || 'Brief description of the issue',
15
- descriptionPlaceholder: config.descriptionPlaceholder || 'Detailed description of what happened...',
15
+ descriptionPlaceholder: config.descriptionPlaceholder ||
16
+ 'Detailed description of what happened...',
16
17
  submitButtonText: config.submitButtonText || 'Submit Bug Report',
17
18
  cancelButtonText: config.cancelButtonText || 'Cancel',
18
19
  showScreenshot: config.showScreenshot !== false,